Skip to content

Commit 2e6d1f9

Browse files
feat(frontend): support for receiving cycles with OISY signer (#2489)
* feat(frontend): support for receiving cycles with OISY signer * chore: fmt and lint
1 parent a5a53e0 commit 2e6d1f9

File tree

5 files changed

+68
-45
lines changed

5 files changed

+68
-45
lines changed

src/frontend/src/lib/api/icp-index.api.ts

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,6 @@ import { assertNonNullish } from '@dfinity/utils';
55
import { IcpIndexCanister, type IcpIndexDid } from '@icp-sdk/canisters/ledger/icp';
66
import type { IcrcAccount } from '@icp-sdk/canisters/ledger/icrc';
77

8-
export const getBalance = async ({
9-
account,
10-
identity
11-
}: {
12-
account: IcrcAccount;
13-
identity: OptionIdentity;
14-
}): Promise<bigint> => {
15-
assertNonNullish(identity, 'No internet identity to initialize the Index actor.');
16-
17-
const agent = await getAgent({ identity });
18-
19-
const { accountBalance } = IcpIndexCanister.create({
20-
agent
21-
});
22-
23-
return accountBalance({
24-
accountIdentifier: toAccountIdentifier(account).toHex(),
25-
certified: false
26-
});
27-
};
28-
298
export const getIcpTransactions = async ({
309
account,
3110
identity,

src/frontend/src/lib/api/icrc-index.api.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,29 @@ import {
88
type IcrcIndexDid
99
} from '@icp-sdk/canisters/ledger/icrc';
1010

11+
export const getUncertifiedBalance = async ({
12+
account,
13+
identity,
14+
indexId
15+
}: {
16+
account: IcrcAccount;
17+
identity: OptionIdentity;
18+
} & Pick<LedgerIds, 'indexId'>): Promise<bigint> => {
19+
assertNonNullish(identity, 'No internet identity to initialize the ICRC Index actor.');
20+
21+
const agent = await getAgent({ identity });
22+
23+
const { balance } = IcrcIndexCanister.create({
24+
agent,
25+
canisterId: indexId
26+
});
27+
28+
return balance({
29+
...account,
30+
certified: false
31+
});
32+
};
33+
1134
export const getIcrcTransactions = async ({
1235
account,
1336
indexId,

src/frontend/src/lib/components/wallet/tokens/ReceiveTokens.svelte

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
import Popover from '$lib/components/ui/Popover.svelte';
77
import ReceiveTokensQRCode from '$lib/components/wallet/tokens/ReceiveTokensQRCode.svelte';
88
import ReceiveTokensSigner from '$lib/components/wallet/tokens/ReceiveTokensSigner.svelte';
9+
import { CYCLES, ICP } from '$lib/constants/token.constants';
910
import { isNotSkylab } from '$lib/env/app.env';
10-
import type { SelectedWallet } from '$lib/schemas/wallet.schema';
11+
import type { SelectedToken, SelectedWallet } from '$lib/schemas/wallet.schema';
1112
import { i18n } from '$lib/stores/app/i18n.store';
1213
import { toAccountIdentifier } from '$lib/utils/icp-icrc-account.utils';
1314
@@ -23,6 +24,10 @@
2324
let walletIdText = $derived(encodeIcrcAccount(walletId));
2425
let accountIdentifier = $derived(toAccountIdentifier(walletId));
2526
27+
let selectedToken = $derived<SelectedToken>(
28+
selectedWallet?.type === 'mission_control' ? ICP : CYCLES
29+
);
30+
2631
let step: 'options' | 'wallet_id' | 'account_identifier' | 'signer' = $state('options');
2732
2833
$effect(() => {
@@ -53,7 +58,12 @@
5358
</div>
5459
{:else if step === 'signer'}
5560
<div in:fade>
56-
<ReceiveTokensSigner back={() => (step = 'options')} {walletId} bind:visible />
61+
<ReceiveTokensSigner
62+
back={() => (step = 'options')}
63+
{selectedToken}
64+
{walletId}
65+
bind:visible
66+
/>
5767
</div>
5868
{:else}
5969
<div class="options">

src/frontend/src/lib/components/wallet/tokens/ReceiveTokensSigner.svelte

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,35 @@
11
<script lang="ts">
22
import type { IcrcAccount } from '@dfinity/oisy-wallet-signer';
3-
import { IcpWallet } from '@dfinity/oisy-wallet-signer/icp-wallet';
4-
import { ICPToken, isNullish, nonNullish, toNullable } from '@dfinity/utils';
5-
import type { Icrc1TransferRequest } from '@icp-sdk/canisters/ledger/icp';
3+
import { IcrcWallet } from '@dfinity/oisy-wallet-signer/icrc-wallet';
4+
import { isNullish, nonNullish, toNullable } from '@dfinity/utils';
5+
import type { TransferParams } from '@icp-sdk/canisters/ledger/icrc';
66
import Confetti from '$lib/components/ui/Confetti.svelte';
77
import Spinner from '$lib/components/ui/Spinner.svelte';
88
import ReceiveTokensSignerForm from '$lib/components/wallet/tokens/ReceiveTokensSignerForm.svelte';
9-
import { ICP } from '$lib/constants/token.constants';
109
import { OISY_WALLET_OPTIONS } from '$lib/constants/wallet.constants';
11-
import type { WalletId } from '$lib/schemas/wallet.schema';
10+
import type { SelectedToken, WalletId } from '$lib/schemas/wallet.schema';
1211
import { wizardBusy } from '$lib/stores/app/busy.store';
1312
import { i18n } from '$lib/stores/app/i18n.store';
1413
import { toasts } from '$lib/stores/app/toasts.store';
1514
import { assertAndConvertAmountToToken } from '$lib/utils/token.utils';
1615
1716
interface Props {
1817
walletId: WalletId;
18+
selectedToken: SelectedToken;
1919
back: () => void;
2020
visible?: boolean;
2121
}
2222
23-
let { back, walletId, visible = $bindable() }: Props = $props();
23+
let { back, walletId, selectedToken, visible = $bindable() }: Props = $props();
2424
2525
let step: 'connecting' | 'receiving' | 'form' | 'success' = $state('connecting');
2626
let account: IcrcAccount | undefined = $state(undefined);
2727
2828
const init = async () => {
29-
let wallet: IcpWallet | undefined;
29+
let wallet: IcrcWallet | undefined;
3030
3131
try {
32-
wallet = await IcpWallet.connect({
32+
wallet = await IcrcWallet.connect({
3333
...OISY_WALLET_OPTIONS,
3434
onDisconnect: () => {
3535
if (nonNullish(account)) {
@@ -73,8 +73,8 @@
7373
const { valid, tokenAmount } = assertAndConvertAmountToToken({
7474
amount,
7575
balance,
76-
token: ICPToken,
77-
fee: ICP.fees.transaction
76+
token: selectedToken.token,
77+
fee: selectedToken.fees.transaction
7878
});
7979
8080
if (!valid || isNullish(tokenAmount)) {
@@ -92,24 +92,25 @@
9292
9393
step = 'receiving';
9494
95-
let wallet: IcpWallet | undefined;
95+
let wallet: IcrcWallet | undefined;
9696
9797
try {
98-
wallet = await IcpWallet.connect(OISY_WALLET_OPTIONS);
98+
wallet = await IcrcWallet.connect(OISY_WALLET_OPTIONS);
9999
100100
const { owner, subaccount } = walletId;
101101
102-
const request: Icrc1TransferRequest = {
102+
const params: TransferParams = {
103103
to: {
104104
owner,
105105
subaccount: toNullable(subaccount)
106106
},
107-
amount: tokenAmount.toE8s()
107+
amount: tokenAmount.toUlps()
108108
};
109109
110-
await wallet.icrc1Transfer({
110+
await wallet.transfer({
111111
owner: account.owner,
112-
request
112+
params,
113+
ledgerCanisterId: selectedToken.ledgerId
113114
});
114115
115116
step = 'success';
@@ -136,7 +137,7 @@
136137
<button onclick={() => (visible = false)}>{$i18n.core.close}</button>
137138
</div>
138139
{:else if step === 'form' && nonNullish(account)}
139-
<ReceiveTokensSignerForm {account} {back} receive={onsubmit} />
140+
<ReceiveTokensSignerForm {account} {back} receive={onsubmit} {selectedToken} />
140141
{:else}
141142
<div class="spinner">
142143
<Spinner inline />

src/frontend/src/lib/components/wallet/tokens/ReceiveTokensSignerForm.svelte

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,26 @@
22
import type { IcrcAccount } from '@dfinity/oisy-wallet-signer';
33
import { base64ToUint8Array, nonNullish } from '@dfinity/utils';
44
import { Principal } from '@icp-sdk/core/principal';
5-
import { getBalance } from '$lib/api/icp-index.api';
5+
import { getUncertifiedBalance } from '$lib/api/icrc-index.api';
66
import Identifier from '$lib/components/ui/Identifier.svelte';
77
import Input from '$lib/components/ui/Input.svelte';
88
import SkeletonText from '$lib/components/ui/SkeletonText.svelte';
99
import Value from '$lib/components/ui/Value.svelte';
10+
import TokenSymbol from '$lib/components/wallet/tokens/TokenSymbol.svelte';
1011
import { authIdentity } from '$lib/derived/auth.derived';
12+
import type { SelectedToken } from '$lib/schemas/wallet.schema';
1113
import { i18n } from '$lib/stores/app/i18n.store';
1214
import { toasts } from '$lib/stores/app/toasts.store';
13-
import { formatICP } from '$lib/utils/icp.utils';
15+
import { formatToken } from '$lib/utils/token.utils';
1416
1517
interface Props {
1618
account: IcrcAccount;
19+
selectedToken: SelectedToken;
1720
back: () => void;
1821
receive: (params: { balance: bigint | undefined; amount: string }) => Promise<void>;
1922
}
2023
21-
let { account, back, receive }: Props = $props();
24+
let { account, selectedToken, back, receive }: Props = $props();
2225
2326
let balance: bigint | undefined = $state(undefined);
2427
let amount = $state('');
@@ -30,7 +33,11 @@
3033
? base64ToUint8Array(account.subaccount)
3134
: undefined;
3235
33-
balance = await getBalance({ account: { owner, subaccount }, identity: $authIdentity });
36+
balance = await getUncertifiedBalance({
37+
account: { owner, subaccount },
38+
identity: $authIdentity,
39+
indexId: Principal.fromText(selectedToken.indexId)
40+
});
3441
} catch (err: unknown) {
3542
toasts.error({
3643
text: $i18n.errors.wallet_load_balance,
@@ -71,7 +78,10 @@
7178
{$i18n.wallet.balance}
7279
{/snippet}
7380
{#if nonNullish(balance)}
74-
{formatICP(balance)} <small>ICP</small>
81+
<span
82+
>{formatToken({ selectedToken, amount: balance })}
83+
<TokenSymbol {selectedToken} /></span
84+
>
7585
{:else}
7686
<SkeletonText />
7787
{/if}

0 commit comments

Comments
 (0)