Skip to content

Commit

Permalink
✨ feat: ICRC-3 support check for ICRC tokens (#180)
Browse files Browse the repository at this point in the history
  • Loading branch information
rustin01 authored Oct 21, 2024
1 parent 3fae887 commit fde5ecc
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 6 deletions.
1 change: 1 addition & 0 deletions apps/wallet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"dayjs": "^1.11.11",
"ethers": "^6.13.1",
"i18next": "^23.15.1",
"ic0": "^0.2.8",
"jwt-decode": "^4.0.0",
"oidc-client-ts": "^3.0.1",
"qrcode": "^1.5.3",
Expand Down
27 changes: 23 additions & 4 deletions apps/wallet/src/utils/chain/chain-wallets/dfinity/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import { HttpAgent } from "@dfinity/agent";
import { AccountIdentifier, LedgerCanister } from '@dfinity/ledger-icp'
import { IcrcLedgerCanister, IcrcMetadataResponseEntries } from "@dfinity/ledger-icrc";
import { Principal } from "@dfinity/principal";
import { Icrc49CallCanisterRequest, Icrc49CallCanisterResult, IcrcErrorCode, JsonRpcResponseError, JsonRpcResponseSuccess } from "./types";
import { Icrc25SupportedStandardsResult, Icrc49CallCanisterRequest, Icrc49CallCanisterResult, IcrcErrorCode, JsonRpcResponseError, JsonRpcResponseSuccess } from "./types";
import { buildJsonRpcError, buildJsonRpcResponse } from "./utils";
import * as cbor from 'cborg';
import { RUNTIME_ICRC_DEV, RUNTIME_ICRC_HOST } from "../../../runtime";
import ic from 'ic0'

const ICP_LEDGER_CANISTER_ID = Principal.fromText('ryjl3-tyaaa-aaaaa-aaaba-cai');

Expand Down Expand Up @@ -56,7 +57,7 @@ export class DfinityChainWallet extends BaseChainWallet {
}

await this.readyPromise
// native
// ICP
if (assetInfo.chainAssetType.equals(ChainAssetType.ICP)) {
const ledger = this.getIcpLedger();
const balance = await ledger.accountBalance({
Expand All @@ -68,6 +69,7 @@ export class DfinityChainWallet extends BaseChainWallet {
}
// ICRC
if (assetInfo.chainAssetType.equals(ChainAssetType.ICRC3)) {
await this.assertIcrc3Support(assetInfo.contractAddress)
const ledger = this.getIcrcLedger(assetInfo.contractAddress)
const balance = await ledger.balance({
owner: Principal.fromText(address)
Expand All @@ -85,7 +87,7 @@ export class DfinityChainWallet extends BaseChainWallet {
}
await this.readyPromise

// native
// ICP
if (assetInfo.chainAssetType.equals(ChainAssetType.ICP)) {
const ledger = this.getIcpLedger()
const blockHeight = await ledger.transfer({
Expand All @@ -99,6 +101,7 @@ export class DfinityChainWallet extends BaseChainWallet {
}
// ICRC
if (assetInfo.chainAssetType.equals(ChainAssetType.ICRC3)) {
await this.assertIcrc3Support(assetInfo.contractAddress)
const ledger = this.getIcrcLedger(assetInfo.contractAddress)
const decimals = assetInfo.decimalPlaces?.value ?? (await this.getIcrcDecimals(ledger))
const blockIndex = await ledger.transfer({
Expand All @@ -121,7 +124,7 @@ export class DfinityChainWallet extends BaseChainWallet {
}
await this.readyPromise

// native
// ICP
if (assetInfo.chainAssetType.equals(ChainAssetType.ICP)) {
if (this.feeCache['native']) {
return this.feeCache['native']
Expand All @@ -138,6 +141,7 @@ export class DfinityChainWallet extends BaseChainWallet {
if (this.feeCache[assetInfo.contractAddress]) {
return this.feeCache[assetInfo.contractAddress]
}
await this.assertIcrc3Support(assetInfo.contractAddress)
const ledger = this.getIcrcLedger(assetInfo.contractAddress)
const fee = await ledger.transactionFee({})
const decimals = assetInfo.decimalPlaces?.value ?? (await this.getIcrcDecimals(ledger))
Expand Down Expand Up @@ -207,4 +211,19 @@ export class DfinityChainWallet extends BaseChainWallet {
}
return decimals
}

private assertIcrc3Support = async (canisterId: string) => {
try {
const ledger = ic(canisterId)
const response: Icrc25SupportedStandardsResult['supportedStandards']
= await ledger.call('icrc1_supported_standards')

console.debug('icrc1_supported_standards',canisterId, response)
if (!Array.isArray(response) || !response.find((standard) => standard?.name.toUpperCase() === 'ICRC-3')) {
throw new Error(`Dfinity: token(${canisterId}) does not support ICRC-3`)
}
} catch (e) {
throw new Error(`Dfinity: failed to check ICRC-3 support of token(${canisterId})`)
}
}
}
53 changes: 51 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,16 @@
"@babel/helper-validator-identifier" "^7.24.7"
to-fast-properties "^2.0.0"

"@dfinity/agent@^0.19.2":
version "0.19.3"
resolved "https://registry.npmmirror.com/@dfinity/agent/-/agent-0.19.3.tgz#aa3f9c0f67d8e8f81714650ebb2a38e1b691021b"
integrity sha512-q410aNLoOA1ZkwdAMgSo6t++pjISn9TfSybRXhPRI5Ume7eG6+6qYr/rlvcXy7Nb2+Ar7LTsHNn34IULfjni7w==
dependencies:
"@noble/hashes" "^1.3.1"
base64-arraybuffer "^0.2.0"
borc "^2.1.1"
simple-cbor "^0.4.1"

"@dfinity/agent@^2.1.1":
version "2.1.1"
resolved "https://registry.npmmirror.com/@dfinity/agent/-/agent-2.1.1.tgz#e2c7a37c2fb8c43752e560aea3669cc3c208165e"
Expand All @@ -210,6 +220,11 @@
buffer "^6.0.3"
simple-cbor "^0.4.1"

"@dfinity/candid@^0.19.2":
version "0.19.3"
resolved "https://registry.npmmirror.com/@dfinity/candid/-/candid-0.19.3.tgz#edc3491572d293824b821ce3a4fc50f5b4714f4d"
integrity sha512-yXfbLSWTeRd4G0bLLxYoDqpXH3Jim0P+1PPZOoktXNC1X1hB+ea3yrZebX75t4GVoQK7123F7mxWHiPjuV2tQQ==

"@dfinity/candid@^2.1.1":
version "2.1.1"
resolved "https://registry.npmmirror.com/@dfinity/candid/-/candid-2.1.1.tgz#546c77cbcbd7538f3a140cf3e5575bfe5871531a"
Expand All @@ -228,6 +243,15 @@
asn1js "^3.0.5"
bs58check "^3.0.1"

"@dfinity/identity@^0.19.2":
version "0.19.3"
resolved "https://registry.npmmirror.com/@dfinity/identity/-/identity-0.19.3.tgz#caec4a38b4a7d4567e662a7eb5bf2a9ae6466bdf"
integrity sha512-6XHrkNQ8tVN6+MERyXPy+avGHTd2zoX3l47bu6gSwreDdOZQnAnXpHVzLcXhnUptkBVetcC70YQEKCmqtuLriA==
dependencies:
"@noble/hashes" "^1.3.1"
borc "^2.1.1"
tweetnacl "^1.0.1"

"@dfinity/ledger-icp@^2.5.0":
version "2.5.0"
resolved "https://registry.npmmirror.com/@dfinity/ledger-icp/-/ledger-icp-2.5.0.tgz#f563779f39e346d2e6365554e15727f9d99ba906"
Expand All @@ -238,6 +262,13 @@
resolved "https://registry.npmmirror.com/@dfinity/ledger-icrc/-/ledger-icrc-2.5.0.tgz#d26ad52a19aad35f48801ff662278bc4cf0378d2"
integrity sha512-/Q1xqKGLtOdCVxZYSwXqk2J2+b00OWO/Q/rPGg+eZ6QJDU4BnUkF+nQMLZXZZTFG/uAGuZjTn7Kd9/36aibh3g==

"@dfinity/principal@^0.19.2":
version "0.19.3"
resolved "https://registry.npmmirror.com/@dfinity/principal/-/principal-0.19.3.tgz#428cfca3d2d2de9e1433b3b33498fd595fb441d8"
integrity sha512-+nixVvdGt7ECxRvLXDXsvU9q9sSPssBtDQ4bXa149SK6gcYcmZ6lfWIi3DJNqj3tGROxILVBsguel9tECappsA==
dependencies:
"@noble/hashes" "^1.3.1"

"@dfinity/principal@^2.1.1":
version "2.1.1"
resolved "https://registry.npmmirror.com/@dfinity/principal/-/principal-2.1.1.tgz#a61abec1a556e865244de26aa992d15b19fc1736"
Expand Down Expand Up @@ -2151,6 +2182,13 @@ create-require@^1.1.1:
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==

cross-fetch@^3.1.5:
version "3.1.8"
resolved "https://registry.npmmirror.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82"
integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==
dependencies:
node-fetch "^2.6.12"

cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
Expand Down Expand Up @@ -3013,6 +3051,17 @@ i18next@^23.15.1:
dependencies:
"@babel/runtime" "^7.23.2"

ic0@^0.2.8:
version "0.2.8"
resolved "https://registry.npmmirror.com/ic0/-/ic0-0.2.8.tgz#9864d4926444c433960d6d454a8bf5c1b7a13149"
integrity sha512-IPtyrB79fvlb9uQcI8dlKDBsqc1eyCckMDsKzgbaiURrM/bVnDJaZ+dsB1CXxQNpsmb/qV3DXPXJRAhh6AVh3w==
dependencies:
"@dfinity/agent" "^0.19.2"
"@dfinity/candid" "^0.19.2"
"@dfinity/identity" "^0.19.2"
"@dfinity/principal" "^0.19.2"
cross-fetch "^3.1.5"

ieee754@^1.1.13, ieee754@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
Expand Down Expand Up @@ -3626,7 +3675,7 @@ [email protected]:
dependencies:
whatwg-url "^5.0.0"

node-fetch@^2.6.1, node-fetch@^2.7.0:
node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
Expand Down Expand Up @@ -4883,7 +4932,7 @@ tweetnacl-util@^0.15.1:
resolved "https://registry.yarnpkg.com/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz#b80fcdb5c97bcc508be18c44a4be50f022eea00b"
integrity sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==

[email protected], tweetnacl@^1.0.3:
[email protected], tweetnacl@^1.0.1, tweetnacl@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596"
integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==
Expand Down

0 comments on commit fde5ecc

Please sign in to comment.