From 279a7f373188e4dcac8e5b90a754f47dd0191d94 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Thu, 16 Jan 2025 21:08:25 +0800 Subject: [PATCH 1/8] feat: Add usdi to compatible xudt list --- packages/ckb/src/constants/index.ts | 48 ++++++++++++++++------------- packages/ckb/src/rgbpp/btc-time.ts | 2 +- packages/ckb/src/utils/ckb-tx.ts | 8 ++--- 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/packages/ckb/src/constants/index.ts b/packages/ckb/src/constants/index.ts index 72955a7a..7e98ff5b 100644 --- a/packages/ckb/src/constants/index.ts +++ b/packages/ckb/src/constants/index.ts @@ -66,15 +66,6 @@ const TestnetInfo = { depType: 'code', } as CKBComponents.CellDep, - CompatibleXUDTTypeScripts: [ - // RUSD - { - codeHash: '0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a', - hashType: 'type', - args: '', - }, - ] as CKBComponents.Script[], - UniqueTypeScript: { codeHash: '0x8e341bcfec6393dcd41e635733ff2dca00a6af546949f70c57a706c0f344df8b', hashType: 'type', @@ -223,15 +214,6 @@ const MainnetInfo = { depType: 'code', } as CKBComponents.CellDep, - CompatibleXUDTTypeScripts: [ - // RUSD - { - codeHash: '0x26a33e0815888a4a0614a0b7d09fa951e0993ff21e55905510104a0b1312032b', - hashType: 'type', - args: '', - }, - ] as CKBComponents.Script[], - UniqueTypeScript: { codeHash: '0x2c8c11c985da60b0a330c61a85507416d6382c130ba67f0c47ab071e00aec628', hashType: 'data1', @@ -294,6 +276,33 @@ const MainnetInfo = { } as CKBComponents.Script, }; +export const COMPATIBLE_XUDT_TYPE_SCRIPTS: CKBComponents.Script[] = [ + // RUSD Mainnet + { + codeHash: '0x26a33e0815888a4a0614a0b7d09fa951e0993ff21e55905510104a0b1312032b', + hashType: 'type', + args: '', + }, + // RUSD Testnet + { + codeHash: '0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a', + hashType: 'type', + args: '', + }, + // USDI Mainnet + { + codeHash: '0xbfa35a9c38a676682b65ade8f02be164d48632281477e36f8dc2f41f79e56bfc', + hashType: 'type', + args: '', + }, + // USDI Testnet + { + codeHash: '0xcc9dc33ef234e14bc788c43a4848556a5fb16401a04662fc55db9bb201987037', + hashType: 'type', + args: '', + }, +]; + export const UNLOCKABLE_LOCK_SCRIPT = { codeHash: '0x0000000000000000000000000000000000000000000000000000000000000000', hashType: 'data', @@ -363,9 +372,6 @@ export const getSporeTypeScript = (isMainnet: boolean) => export const getSporeTypeDep = (isMainnet: boolean) => isMainnet ? MainnetInfo.SporeTypeDep : TestnetInfo.SporeTypeDep; -export const getCompatibleXudtTypeScripts = (isMainnet: boolean) => - isMainnet ? MainnetInfo.CompatibleXUDTTypeScripts : TestnetInfo.CompatibleXUDTTypeScripts; - export const getUtxoAirdropBadgeTypeScript = (isMainnet: boolean) => isMainnet ? MainnetInfo.UtxoAirdropBadgeTypeScript : TestnetInfo.UtxoAirdropBadgeTypeScript; export const getUtxoAirdropBadgeTypeDep = (isMainnet: boolean) => diff --git a/packages/ckb/src/rgbpp/btc-time.ts b/packages/ckb/src/rgbpp/btc-time.ts index b14d07c7..97d8b882 100644 --- a/packages/ckb/src/rgbpp/btc-time.ts +++ b/packages/ckb/src/rgbpp/btc-time.ts @@ -66,7 +66,7 @@ export const buildBtcTimeCellsSpentTx = async ({ const hasStandardUDT = outputs.some((output) => isStandardUDTTypeSupported(output.type!, isMainnet)); const compatibleXudtCodeHashes = outputs - .filter((output) => isCompatibleUDTTypesSupported(output.type!, isMainnet)) + .filter((output) => isCompatibleUDTTypesSupported(output.type!)) .map((output) => output.type!.codeHash); const cellDeps = await fetchTypeIdCellDeps( isMainnet, diff --git a/packages/ckb/src/utils/ckb-tx.ts b/packages/ckb/src/utils/ckb-tx.ts index 69b83080..f5371eab 100644 --- a/packages/ckb/src/utils/ckb-tx.ts +++ b/packages/ckb/src/utils/ckb-tx.ts @@ -5,7 +5,7 @@ import { CKB_UNIT, UNLOCKABLE_LOCK_SCRIPT, getClusterTypeScript, - getCompatibleXudtTypeScripts, + COMPATIBLE_XUDT_TYPE_SCRIPTS, getSporeTypeScript, getTokenMetadataTypeScript, getUtxoAirdropBadgeTypeScript, @@ -44,8 +44,8 @@ export const isTokenMetadataType = (type: CKBComponents.Script, isMainnet: boole return tokenMetadataType === typeAsset; }; -export const isCompatibleUDTTypesSupported = (type: CKBComponents.Script, isMainnet: boolean): boolean => { - const compatibleXudtTypeBytes = getCompatibleXudtTypeScripts(isMainnet).map((script) => serializeScript(script)); +export const isCompatibleUDTTypesSupported = (type: CKBComponents.Script): boolean => { + const compatibleXudtTypeBytes = COMPATIBLE_XUDT_TYPE_SCRIPTS.map((script) => serializeScript(script)); const typeAsset = serializeScript({ ...type, args: '', @@ -63,7 +63,7 @@ export const isStandardUDTTypeSupported = (type: CKBComponents.Script, isMainnet }; export const isUDTTypeSupported = (type: CKBComponents.Script, isMainnet: boolean): boolean => { - return isStandardUDTTypeSupported(type, isMainnet) || isCompatibleUDTTypesSupported(type, isMainnet); + return isStandardUDTTypeSupported(type, isMainnet) || isCompatibleUDTTypesSupported(type); }; export const isSporeTypeSupported = (type: CKBComponents.Script, isMainnet: boolean): boolean => { From 783d2e51674246ff58fa56a035bcb9179354d284 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Thu, 16 Jan 2025 21:20:23 +0800 Subject: [PATCH 2/8] refactor: Remove cell deps cdn url --- packages/ckb/src/constants/index.ts | 2 +- packages/ckb/src/utils/cell-dep.spec.ts | 4 ++-- packages/ckb/src/utils/cell-dep.ts | 11 +---------- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/packages/ckb/src/constants/index.ts b/packages/ckb/src/constants/index.ts index 7e98ff5b..86bc6ec7 100644 --- a/packages/ckb/src/constants/index.ts +++ b/packages/ckb/src/constants/index.ts @@ -148,7 +148,7 @@ const TestnetInfo = { } as CKBComponents.Script, UtxoAirdropBadgeTypeDep: { - outPoint: { txHash: '0xfa0a6821293cc1ef4ee67a900862208e27f67b98237c9b13bf93c84607c5cd33', index: '0x2' }, + outPoint: { txHash: '0xbbbb73972ac260a0f7204bea707288c3970688fe8714c3246a5e9a538168a42a', index: '0x0' }, depType: 'code', } as CKBComponents.CellDep, diff --git a/packages/ckb/src/utils/cell-dep.spec.ts b/packages/ckb/src/utils/cell-dep.spec.ts index 764f74ba..62f13864 100644 --- a/packages/ckb/src/utils/cell-dep.spec.ts +++ b/packages/ckb/src/utils/cell-dep.spec.ts @@ -109,8 +109,8 @@ describe('dynamic fetch cell dep', () => { const cellDeps = await fetchTypeIdCellDeps(isMainnet, { utxoAirdropBadge: true, }); - expect(cellDeps[0].outPoint?.txHash).toBe('0xfa0a6821293cc1ef4ee67a900862208e27f67b98237c9b13bf93c84607c5cd33'); - expect(cellDeps[0].outPoint?.index).toBe('0x2'); + expect(cellDeps[0].outPoint?.txHash).toBe('0xbbbb73972ac260a0f7204bea707288c3970688fe8714c3246a5e9a538168a42a'); + expect(cellDeps[0].outPoint?.index).toBe('0x0'); }, { timeout: 10000 }, ); diff --git a/packages/ckb/src/utils/cell-dep.ts b/packages/ckb/src/utils/cell-dep.ts index 5bfd1786..5c3d8b89 100644 --- a/packages/ckb/src/utils/cell-dep.ts +++ b/packages/ckb/src/utils/cell-dep.ts @@ -36,11 +36,6 @@ export interface CellDepsObject { const GITHUB_CELL_DEPS_JSON_URL = 'https://raw.githubusercontent.com/utxostack/typeid-contract-cell-deps/main/deployment/cell-deps.json'; -// If the CDN has cache issue, please clear the cache by visiting -// https://www.jsdelivr.com/tools/purge?path=/gh/utxostack/typeid-contract-cell-deps@main -const CDN_GITHUB_CELL_DEPS_JSON_URL = - 'https://cdn.jsdelivr.net/gh/utxostack/typeid-contract-cell-deps@main/deployment/cell-deps.json'; - const VERCEL_CELL_DEPS_JSON_STATIC_URL = 'https://typeid-contract-cell-deps.vercel.app/deployment/cell-deps.json'; const VERCEL_SERVER_CELL_DEPS_JSON_URL = 'https://typeid-contract-cell-deps.vercel.app/api/cell-deps'; @@ -49,11 +44,7 @@ const request = (url: string) => axios.get(url, { timeout: 10000 }); const fetchCellDepsJsonFromStaticSource = async () => { try { - const response = await Promise.any([ - request(CDN_GITHUB_CELL_DEPS_JSON_URL), - request(GITHUB_CELL_DEPS_JSON_URL), - request(VERCEL_CELL_DEPS_JSON_STATIC_URL), - ]); + const response = await Promise.any([request(VERCEL_CELL_DEPS_JSON_STATIC_URL), request(GITHUB_CELL_DEPS_JSON_URL)]); return response.data as CellDepsObject; } catch (error) { // for (const e of error.errors) { From 9bfbd56785157c0c8b3d92da53590d168309d0b3 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Thu, 16 Jan 2025 21:28:00 +0800 Subject: [PATCH 3/8] chore: Add changeset --- .changeset/sweet-cheetahs-drop.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/sweet-cheetahs-drop.md diff --git a/.changeset/sweet-cheetahs-drop.md b/.changeset/sweet-cheetahs-drop.md new file mode 100644 index 00000000..2d133157 --- /dev/null +++ b/.changeset/sweet-cheetahs-drop.md @@ -0,0 +1,5 @@ +--- +'@rgbpp-sdk/ckb': minor +--- + +Add USDI to compatible xUDT list and remove jsdelivr CDN because of cache From 5b52ed6fea84271d666ed3c641834e120bf8afee Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Mon, 20 Jan 2025 16:35:45 +0800 Subject: [PATCH 4/8] feat: Fetch compatible xudt list from server --- packages/ckb/src/utils/cell-dep.spec.ts | 13 +++++- packages/ckb/src/utils/cell-dep.ts | 56 +++++++++++++++++++++++++ packages/ckb/src/utils/ckb-tx.ts | 13 +++++- 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/packages/ckb/src/utils/cell-dep.spec.ts b/packages/ckb/src/utils/cell-dep.spec.ts index 62f13864..b509757a 100644 --- a/packages/ckb/src/utils/cell-dep.spec.ts +++ b/packages/ckb/src/utils/cell-dep.spec.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from 'vitest'; -import { fetchTypeIdCellDeps } from './cell-dep'; +import { CompatibleXUDTRegistry, fetchTypeIdCellDeps } from './cell-dep'; import { getBtcTimeLockDep, getRgbppLockDep, getUniqueTypeDep, getXudtDep } from '../constants'; describe('dynamic fetch cell dep', () => { @@ -114,4 +114,15 @@ describe('dynamic fetch cell dep', () => { }, { timeout: 10000 }, ); + + it( + 'CompatibleXUDTRegistry.getCompatibleTokens', + async () => { + const scripts = CompatibleXUDTRegistry.getCompatibleTokens(); + expect(scripts.length > 0).toBe(true); + // RUSD Mainnet + expect(scripts[0].codeHash).toBe('0x26a33e0815888a4a0614a0b7d09fa951e0993ff21e55905510104a0b1312032b'); + }, + { timeout: 10000 }, + ); }); diff --git a/packages/ckb/src/utils/cell-dep.ts b/packages/ckb/src/utils/cell-dep.ts index 5c3d8b89..dcd1dec5 100644 --- a/packages/ckb/src/utils/cell-dep.ts +++ b/packages/ckb/src/utils/cell-dep.ts @@ -1,5 +1,6 @@ import axios from 'axios'; import { + COMPATIBLE_XUDT_TYPE_SCRIPTS, getBtcTimeLockDep, getRgbppLockDep, getUniqueTypeDep, @@ -201,3 +202,58 @@ export const fetchTypeIdCellDeps = async ( return cellDeps; }; + +const VERCEL_STATIC_COMPATIBLE_XUDT_URL = 'https://typeid-contract-cell-deps.vercel.app/compatible-udt.json'; +const GITHUB_STATIC_COMPATIBLE_XUDT_URL = + 'https://raw.githubusercontent.com/utxostack/typeid-contract-cell-deps/main/compatible-udt.json'; + +/** + * The `CompatibleXUDTRegistry` class is responsible for managing a cache of compatible XUDT (eXtensible User-Defined Token) scripts. + * It fetches and caches the compatible tokens from specified URLs and refreshes the cache periodically. + */ +export class CompatibleXUDTRegistry { + private static cache: CKBComponents.Script[] = []; + private static lastFetchTime: number = 0; + private static CACHE_DURATION = 3 * 60 * 1000; // 3 minutes ([about 24 CKB blocks](https://docs-old.nervos.org/docs/essays/tx-confirmation)) + private static xudtUrl = VERCEL_STATIC_COMPATIBLE_XUDT_URL; + + // If you want to get the latest compatible xUDT list, CompatibleXUDTRegistry.refreshCache should be called first + static getCompatibleTokens(): CKBComponents.Script[] { + const now = Date.now(); + if (this.cache.length > 0 || now - this.lastFetchTime > this.CACHE_DURATION) { + this.refreshCache(this.xudtUrl); + } + return this.cache.length > 0 ? this.cache : COMPATIBLE_XUDT_TYPE_SCRIPTS; + } + + /** + * Refreshes the cache by fetching data from the provided URL or a default URL. + * + * This method attempts to fetch data from the provided URL or a default URL + * using `Promise.any` to handle multiple potential sources. If the fetch is + * successful, it updates the cache with the fetched data and sets the last + * fetch time to the current timestamp. + * + * @param url - An optional URL to fetch data from. If not provided, a default + * URL (`VERCEL_CELL_DEPS_JSON_STATIC_URL`) will be used. + * @returns A promise that resolves when the cache has been refreshed. + */ + static async refreshCache(url?: string): Promise { + this.xudtUrl = url ?? VERCEL_CELL_DEPS_JSON_STATIC_URL; + try { + const response = await Promise.any([request(this.xudtUrl), request(GITHUB_STATIC_COMPATIBLE_XUDT_URL)]); + if (response && response.data) { + const xudtList = response.data as { codeHash: string }[]; + this.cache = xudtList.map((xudt) => { + return { + codeHash: xudt.codeHash, + hashType: 'type', + } as CKBComponents.Script; + }); + } + this.lastFetchTime = Date.now(); + } catch (error) { + // console.error(error) + } + } +} diff --git a/packages/ckb/src/utils/ckb-tx.ts b/packages/ckb/src/utils/ckb-tx.ts index f5371eab..8aca55d3 100644 --- a/packages/ckb/src/utils/ckb-tx.ts +++ b/packages/ckb/src/utils/ckb-tx.ts @@ -5,7 +5,6 @@ import { CKB_UNIT, UNLOCKABLE_LOCK_SCRIPT, getClusterTypeScript, - COMPATIBLE_XUDT_TYPE_SCRIPTS, getSporeTypeScript, getTokenMetadataTypeScript, getUtxoAirdropBadgeTypeScript, @@ -15,6 +14,7 @@ import { Hex, IndexerCell, RgbppTokenInfo } from '../types'; import { encodeRgbppTokenInfo, genBtcTimeLockScript } from './rgbpp'; import { Collector } from '../collector'; import { NoLiveCellError } from '../error'; +import { CompatibleXUDTRegistry } from './cell-dep'; export { serializeScript }; @@ -44,8 +44,17 @@ export const isTokenMetadataType = (type: CKBComponents.Script, isMainnet: boole return tokenMetadataType === typeAsset; }; +// +/** + * Checks if the provided UDT (User Defined Token) type script is supported by comparing it against a list of compatible UDT types. + * If you want to get the latest compatible xUDT list, CompatibleXUDTRegistry.refreshCache should be called before the isCompatibleUDTTypesSupported + * + * @param type - The UDT type script to check for compatibility. + * @returns A boolean indicating whether the provided UDT type script is supported. + */ export const isCompatibleUDTTypesSupported = (type: CKBComponents.Script): boolean => { - const compatibleXudtTypeBytes = COMPATIBLE_XUDT_TYPE_SCRIPTS.map((script) => serializeScript(script)); + const compatibleList = CompatibleXUDTRegistry.getCompatibleTokens(); + const compatibleXudtTypeBytes = compatibleList.map((script) => serializeScript(script)); const typeAsset = serializeScript({ ...type, args: '', From 4d35f9000485d013fe2b9ce562d5e2e341e0bf29 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Mon, 20 Jan 2025 16:37:46 +0800 Subject: [PATCH 5/8] feat: Fetch latest compatible xudt list for examples and tests --- examples/rgbpp/README.md | 2 + .../xudt/compatible-xudt/1-ckb-leap-btc.ts | 9 ++- .../xudt/compatible-xudt/2-btc-transfer.ts | 9 ++- .../xudt/compatible-xudt/3-btc-leap-ckb.ts | 9 ++- .../rgbpp/xudt/compatible-xudt/assets-api.ts | 78 +++++++++++-------- .../xudt/compatible-xudt/1-ckb-leap-btc.ts | 9 ++- .../xudt/compatible-xudt/2-btc-transfer.ts | 9 ++- .../xudt/compatible-xudt/3-btc-leap-ckb.ts | 9 ++- 8 files changed, 94 insertions(+), 40 deletions(-) diff --git a/examples/rgbpp/README.md b/examples/rgbpp/README.md index 58162bcc..1878a7d2 100644 --- a/examples/rgbpp/README.md +++ b/examples/rgbpp/README.md @@ -2,6 +2,8 @@ - xUDT directory: The examples for RGB++ UDT issuance, transfer, transferAll and leap - Spore directory: The examples for RGB++ Spore creation, transfer and leap +- compatible-xudt directory: The examples for RGB++ compatible UDT issuance, transfer, transferAll and leap + - If you want to get the latest compatible xUDT list, `CompatibleXUDTRegistry.refreshCache` should be called first > [!TIP] > All the parameters of the examples should be repalced with your own, including BTC private key, CKB private key, BTC Service origin, BTC Service token, BTC UTXO, xUDT type args, Spore type args, etc. diff --git a/examples/rgbpp/xudt/compatible-xudt/1-ckb-leap-btc.ts b/examples/rgbpp/xudt/compatible-xudt/1-ckb-leap-btc.ts index 218813b2..db786446 100644 --- a/examples/rgbpp/xudt/compatible-xudt/1-ckb-leap-btc.ts +++ b/examples/rgbpp/xudt/compatible-xudt/1-ckb-leap-btc.ts @@ -1,6 +1,6 @@ import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; import { genCkbJumpBtcVirtualTx } from 'rgbpp'; -import { getSecp256k1CellDep, buildRgbppLockArgs } from 'rgbpp/ckb'; +import { getSecp256k1CellDep, buildRgbppLockArgs, CompatibleXUDTRegistry } from 'rgbpp/ckb'; import { CKB_PRIVATE_KEY, isMainnet, collector, ckbAddress, BTC_TESTNET_TYPE } from '../../env'; interface LeapToBtcParams { @@ -18,6 +18,13 @@ const leapRusdFromCkbToBtc = async ({ }: LeapToBtcParams) => { const toRgbppLockArgs = buildRgbppLockArgs(outIndex, btcTxId); + // Refresh the cache by fetching the latest compatible xUDT list from the specified URL. + // The default URL is: + // https://raw.githubusercontent.com/utxostack/typeid-contract-cell-deps/main/compatible-udt.json + // You can set your own trusted URL to fetch the compatible xUDT list. + // await CompatibleXUDTRegistry.refreshCache("https://your-own-trusted-compatible-xudt-url"); + await CompatibleXUDTRegistry.refreshCache(); + const ckbRawTx = await genCkbJumpBtcVirtualTx({ collector, fromCkbAddress: ckbAddress, diff --git a/examples/rgbpp/xudt/compatible-xudt/2-btc-transfer.ts b/examples/rgbpp/xudt/compatible-xudt/2-btc-transfer.ts index 8574abbf..54ab8337 100644 --- a/examples/rgbpp/xudt/compatible-xudt/2-btc-transfer.ts +++ b/examples/rgbpp/xudt/compatible-xudt/2-btc-transfer.ts @@ -1,4 +1,4 @@ -import { buildRgbppLockArgs } from 'rgbpp/ckb'; +import { buildRgbppLockArgs, CompatibleXUDTRegistry } from 'rgbpp/ckb'; import { buildRgbppTransferTx } from 'rgbpp'; import { isMainnet, collector, btcService, btcAccount, btcDataSource, BTC_TESTNET_TYPE } from '../../env'; import { saveCkbVirtualTxResult } from '../../shared/utils'; @@ -18,6 +18,13 @@ const transferRusdOnBtc = async ({ compatibleXudtTypeScript, transferAmount, }: RgbppTransferParams) => { + // Refresh the cache by fetching the latest compatible xUDT list from the specified URL. + // The default URL is: + // https://raw.githubusercontent.com/utxostack/typeid-contract-cell-deps/main/compatible-udt.json + // You can set your own trusted URL to fetch the compatible xUDT list. + // await CompatibleXUDTRegistry.refreshCache("https://your-own-trusted-compatible-xudt-url"); + await CompatibleXUDTRegistry.refreshCache(); + const { ckbVirtualTxResult, btcPsbtHex } = await buildRgbppTransferTx({ ckb: { collector, diff --git a/examples/rgbpp/xudt/compatible-xudt/3-btc-leap-ckb.ts b/examples/rgbpp/xudt/compatible-xudt/3-btc-leap-ckb.ts index fec1724c..6a334456 100644 --- a/examples/rgbpp/xudt/compatible-xudt/3-btc-leap-ckb.ts +++ b/examples/rgbpp/xudt/compatible-xudt/3-btc-leap-ckb.ts @@ -1,4 +1,4 @@ -import { buildRgbppLockArgs } from 'rgbpp/ckb'; +import { buildRgbppLockArgs, CompatibleXUDTRegistry } from 'rgbpp/ckb'; import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; import { genBtcJumpCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; import { isMainnet, collector, btcService, btcDataSource, btcAccount, BTC_TESTNET_TYPE } from '../../env'; @@ -18,6 +18,13 @@ const leapRusdFromBtcToCKB = async ({ compatibleXudtTypeScript, transferAmount, }: LeapToCkbParams) => { + // Refresh the cache by fetching the latest compatible xUDT list from the specified URL. + // The default URL is: + // https://raw.githubusercontent.com/utxostack/typeid-contract-cell-deps/main/compatible-udt.json + // You can set your own trusted URL to fetch the compatible xUDT list. + // await CompatibleXUDTRegistry.refreshCache("https://your-own-trusted-compatible-xudt-url"); + await CompatibleXUDTRegistry.refreshCache(); + const ckbVirtualTxResult = await genBtcJumpCkbVirtualTx({ collector, rgbppLockArgsList, diff --git a/examples/rgbpp/xudt/compatible-xudt/assets-api.ts b/examples/rgbpp/xudt/compatible-xudt/assets-api.ts index b47f8328..6f3231ba 100644 --- a/examples/rgbpp/xudt/compatible-xudt/assets-api.ts +++ b/examples/rgbpp/xudt/compatible-xudt/assets-api.ts @@ -2,48 +2,58 @@ import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; import { btcService } from '../../env'; (async () => { - const assets = await btcService.getRgbppAssetsByBtcAddress('tb1qvt7p9g6mw70sealdewtfp0sekquxuru6j3gwmt', { - type_script: serializeScript({ - codeHash: '0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a', - hashType: 'type', - args: '0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b', - }), - }); - console.log('RUSD Assets: ', JSON.stringify(assets)); + // const assets = await btcService.getRgbppAssetsByBtcAddress('tb1qvt7p9g6mw70sealdewtfp0sekquxuru6j3gwmt', { + // type_script: serializeScript({ + // codeHash: '0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a', + // hashType: 'type', + // args: '0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b', + // }), + // }); + // console.log('RUSD Assets: ', JSON.stringify(assets)); - const activities = await btcService.getRgbppActivityByBtcAddress('tb1qvt7p9g6mw70sealdewtfp0sekquxuru6j3gwmt', { - type_script: serializeScript({ - codeHash: '0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a', - hashType: 'type', - args: '0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b', - }), - }); - console.log('RUSD Activities: ', JSON.stringify(activities)); + // const activities = await btcService.getRgbppActivityByBtcAddress('tb1qvt7p9g6mw70sealdewtfp0sekquxuru6j3gwmt', { + // type_script: serializeScript({ + // codeHash: '0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a', + // hashType: 'type', + // args: '0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b', + // }), + // }); + // console.log('RUSD Activities: ', JSON.stringify(activities)); - const info = await btcService.getRgbppAssetInfoByTypeScript( - serializeScript({ - codeHash: '0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb', - hashType: 'type', - args: '0x661cfbe2124b3e79e50e505c406be5b2dcf9da15d8654b749ec536fa4c2eaaae', - }), - ); - console.log('Standard xUDT info: ', JSON.stringify(info)); + // const balance = await btcService.getRgbppBalanceByBtcAddress('tb1qvt7p9g6mw70sealdewtfp0sekquxuru6j3gwmt', { + // type_script: serializeScript({ + // codeHash: '0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a', + // hashType: 'type', + // args: '0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b', + // }), + // no_cache: true, + // }); + // console.log('RUSD balance from btc-assets-api: ', JSON.stringify(balance)); + + // const info = await btcService.getRgbppAssetInfoByTypeScript( + // serializeScript({ + // codeHash: '0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb', + // hashType: 'type', + // args: '0x661cfbe2124b3e79e50e505c406be5b2dcf9da15d8654b749ec536fa4c2eaaae', + // }), + // ); + // console.log('Standard xUDT info: ', JSON.stringify(info)); const rusdInfo = await btcService.getRgbppAssetInfoByTypeScript( serializeScript({ - codeHash: '0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a', + codeHash: '0xcc9dc33ef234e14bc788c43a4848556a5fb16401a04662fc55db9bb201987037', hashType: 'type', - args: '0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b', + args: '0x71fd1985b2971a9903e4d8ed0d59e6710166985217ca0681437883837b86162f', }), ); console.log('RUSD xUDT info: ', JSON.stringify(rusdInfo)); - const utxoAirdropInfo = await btcService.getRgbppAssetInfoByTypeScript( - serializeScript({ - codeHash: '0xf5da9003e31fa9301a3915fe304de9bdb80524b5f0d8fc325fb699317998ee7a', - hashType: 'type', - args: '0xa63d308c04b4c075eb1d7d5cac891cf20276e3ddb2ec855fc981c88d8134dbe2', - }), - ); - console.log('UTXO Airdrop xUDT info: ', JSON.stringify(utxoAirdropInfo)); + // const utxoAirdropInfo = await btcService.getRgbppAssetInfoByTypeScript( + // serializeScript({ + // codeHash: '0xf5da9003e31fa9301a3915fe304de9bdb80524b5f0d8fc325fb699317998ee7a', + // hashType: 'type', + // args: '0xa63d308c04b4c075eb1d7d5cac891cf20276e3ddb2ec855fc981c88d8134dbe2', + // }), + // ); + // console.log('UTXO Airdrop xUDT info: ', JSON.stringify(utxoAirdropInfo)); })(); diff --git a/tests/rgbpp/xudt/compatible-xudt/1-ckb-leap-btc.ts b/tests/rgbpp/xudt/compatible-xudt/1-ckb-leap-btc.ts index 2dc71e8d..a7af8b88 100644 --- a/tests/rgbpp/xudt/compatible-xudt/1-ckb-leap-btc.ts +++ b/tests/rgbpp/xudt/compatible-xudt/1-ckb-leap-btc.ts @@ -1,6 +1,6 @@ import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; import { genCkbJumpBtcVirtualTx } from 'rgbpp'; -import { getSecp256k1CellDep, buildRgbppLockArgs } from 'rgbpp/ckb'; +import { getSecp256k1CellDep, buildRgbppLockArgs, CompatibleXUDTRegistry } from 'rgbpp/ckb'; import { CKB_PRIVATE_KEY, isMainnet, collector, ckbAddress, BTC_TESTNET_TYPE } from '../../env'; import { readStepLog } from '../../shared/utils'; @@ -16,6 +16,13 @@ const leapFromCkbToBtc = async ({ outIndex, btcTxId, compatibleXudtTypeScript, t await retry(20, '10s', async () => { const toRgbppLockArgs = buildRgbppLockArgs(outIndex, btcTxId); + // Refresh the cache by fetching the latest compatible xUDT list from the specified URL. + // The default URL is: + // https://raw.githubusercontent.com/utxostack/typeid-contract-cell-deps/main/compatible-udt.json + // You can set your own trusted URL to fetch the compatible xUDT list. + // await CompatibleXUDTRegistry.refreshCache("https://your-own-trusted-compatible-xudt-url"); + await CompatibleXUDTRegistry.refreshCache(); + const ckbRawTx = await genCkbJumpBtcVirtualTx({ collector, fromCkbAddress: ckbAddress, diff --git a/tests/rgbpp/xudt/compatible-xudt/2-btc-transfer.ts b/tests/rgbpp/xudt/compatible-xudt/2-btc-transfer.ts index 9d8a8607..25f60071 100644 --- a/tests/rgbpp/xudt/compatible-xudt/2-btc-transfer.ts +++ b/tests/rgbpp/xudt/compatible-xudt/2-btc-transfer.ts @@ -1,4 +1,4 @@ -import { buildRgbppLockArgs } from 'rgbpp/ckb'; +import { buildRgbppLockArgs, CompatibleXUDTRegistry } from 'rgbpp/ckb'; import { buildRgbppTransferTx } from 'rgbpp'; import { isMainnet, collector, btcService, btcDataSource, BTC_TESTNET_TYPE, btcAccount } from '../../env'; import { getFastestFeeRate, readStepLog, writeStepLog } from '../../shared/utils'; @@ -21,6 +21,13 @@ const transfer = async ({ }: RgbppTransferParams) => { const { retry } = await import('zx'); + // Refresh the cache by fetching the latest compatible xUDT list from the specified URL. + // The default URL is: + // https://raw.githubusercontent.com/utxostack/typeid-contract-cell-deps/main/compatible-udt.json + // You can set your own trusted URL to fetch the compatible xUDT list. + // await CompatibleXUDTRegistry.refreshCache("https://your-own-trusted-compatible-xudt-url"); + await CompatibleXUDTRegistry.refreshCache(); + const feeRate = await getFastestFeeRate(); console.log('feeRate = ', feeRate); diff --git a/tests/rgbpp/xudt/compatible-xudt/3-btc-leap-ckb.ts b/tests/rgbpp/xudt/compatible-xudt/3-btc-leap-ckb.ts index b87f7c78..3bc6a39e 100644 --- a/tests/rgbpp/xudt/compatible-xudt/3-btc-leap-ckb.ts +++ b/tests/rgbpp/xudt/compatible-xudt/3-btc-leap-ckb.ts @@ -1,4 +1,4 @@ -import { buildRgbppLockArgs } from 'rgbpp/ckb'; +import { buildRgbppLockArgs, CompatibleXUDTRegistry } from 'rgbpp/ckb'; import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; import { genBtcJumpCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; import { isMainnet, collector, btcService, btcDataSource, btcAccount, BTC_TESTNET_TYPE } from '../../env'; @@ -21,6 +21,13 @@ const leapFromBtcToCKB = async ({ }: LeapToCkbParams) => { const { retry } = await import('zx'); + // Refresh the cache by fetching the latest compatible xUDT list from the specified URL. + // The default URL is: + // https://raw.githubusercontent.com/utxostack/typeid-contract-cell-deps/main/compatible-udt.json + // You can set your own trusted URL to fetch the compatible xUDT list. + // await CompatibleXUDTRegistry.refreshCache("https://your-own-trusted-compatible-xudt-url"); + await CompatibleXUDTRegistry.refreshCache(); + const feeRate = await getFastestFeeRate(); console.log('feeRate = ', feeRate); From c6cbeec41c850563bcac5d13f215112559ed1c89 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Mon, 20 Jan 2025 16:50:37 +0800 Subject: [PATCH 6/8] test: Add more CompatibleXUDTRegistry tests --- packages/ckb/src/utils/cell-dep.spec.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/ckb/src/utils/cell-dep.spec.ts b/packages/ckb/src/utils/cell-dep.spec.ts index b509757a..6ba9fa12 100644 --- a/packages/ckb/src/utils/cell-dep.spec.ts +++ b/packages/ckb/src/utils/cell-dep.spec.ts @@ -122,6 +122,12 @@ describe('dynamic fetch cell dep', () => { expect(scripts.length > 0).toBe(true); // RUSD Mainnet expect(scripts[0].codeHash).toBe('0x26a33e0815888a4a0614a0b7d09fa951e0993ff21e55905510104a0b1312032b'); + + await CompatibleXUDTRegistry.refreshCache(); + const latestScripts = CompatibleXUDTRegistry.getCompatibleTokens(); + expect(latestScripts.length > 0).toBe(true); + // RUSD Testnet + expect(latestScripts[0].codeHash).toBe('0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a'); }, { timeout: 10000 }, ); From 1b699b71abe0fde3addd0f3250da9a501ea03930 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Mon, 20 Jan 2025 18:19:38 +0800 Subject: [PATCH 7/8] chore: Update changeset --- .changeset/sweet-cheetahs-drop.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.changeset/sweet-cheetahs-drop.md b/.changeset/sweet-cheetahs-drop.md index 2d133157..fae53f2f 100644 --- a/.changeset/sweet-cheetahs-drop.md +++ b/.changeset/sweet-cheetahs-drop.md @@ -3,3 +3,6 @@ --- Add USDI to compatible xUDT list and remove jsdelivr CDN because of cache + - Fetch and cache compatible xUDT list from Vercel or GitHub server + - Use local static compatible xUDT list when the cache is empty + - Remove jsdelivr CDN because CDN cache time is too long, causing UTXO Airdrop cellDeps to become outdated From 92686f0788d27048b4b99e64b2fce24b0112a87f Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Tue, 21 Jan 2025 11:14:44 +0800 Subject: [PATCH 8/8] Fix some issues --- packages/ckb/src/utils/cell-dep.spec.ts | 4 ++++ packages/ckb/src/utils/cell-dep.ts | 9 ++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/ckb/src/utils/cell-dep.spec.ts b/packages/ckb/src/utils/cell-dep.spec.ts index 6ba9fa12..dd682f9b 100644 --- a/packages/ckb/src/utils/cell-dep.spec.ts +++ b/packages/ckb/src/utils/cell-dep.spec.ts @@ -122,12 +122,16 @@ describe('dynamic fetch cell dep', () => { expect(scripts.length > 0).toBe(true); // RUSD Mainnet expect(scripts[0].codeHash).toBe('0x26a33e0815888a4a0614a0b7d09fa951e0993ff21e55905510104a0b1312032b'); + // USDI Testnet + expect(scripts[3].codeHash).toBe('0xcc9dc33ef234e14bc788c43a4848556a5fb16401a04662fc55db9bb201987037'); await CompatibleXUDTRegistry.refreshCache(); const latestScripts = CompatibleXUDTRegistry.getCompatibleTokens(); expect(latestScripts.length > 0).toBe(true); // RUSD Testnet expect(latestScripts[0].codeHash).toBe('0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a'); + // USDI Mainnet + expect(latestScripts[3].codeHash).toBe('0xbfa35a9c38a676682b65ade8f02be164d48632281477e36f8dc2f41f79e56bfc'); }, { timeout: 10000 }, ); diff --git a/packages/ckb/src/utils/cell-dep.ts b/packages/ckb/src/utils/cell-dep.ts index dcd1dec5..5d71a57b 100644 --- a/packages/ckb/src/utils/cell-dep.ts +++ b/packages/ckb/src/utils/cell-dep.ts @@ -220,7 +220,7 @@ export class CompatibleXUDTRegistry { // If you want to get the latest compatible xUDT list, CompatibleXUDTRegistry.refreshCache should be called first static getCompatibleTokens(): CKBComponents.Script[] { const now = Date.now(); - if (this.cache.length > 0 || now - this.lastFetchTime > this.CACHE_DURATION) { + if (this.cache.length === 0 || now - this.lastFetchTime > this.CACHE_DURATION) { this.refreshCache(this.xudtUrl); } return this.cache.length > 0 ? this.cache : COMPATIBLE_XUDT_TYPE_SCRIPTS; @@ -239,9 +239,12 @@ export class CompatibleXUDTRegistry { * @returns A promise that resolves when the cache has been refreshed. */ static async refreshCache(url?: string): Promise { - this.xudtUrl = url ?? VERCEL_CELL_DEPS_JSON_STATIC_URL; + this.xudtUrl = url ?? VERCEL_STATIC_COMPATIBLE_XUDT_URL; + const isExternal = url !== VERCEL_STATIC_COMPATIBLE_XUDT_URL && url !== GITHUB_STATIC_COMPATIBLE_XUDT_URL; try { - const response = await Promise.any([request(this.xudtUrl), request(GITHUB_STATIC_COMPATIBLE_XUDT_URL)]); + const response = await (isExternal + ? request(this.xudtUrl) + : Promise.any([request(this.xudtUrl), request(GITHUB_STATIC_COMPATIBLE_XUDT_URL)])); if (response && response.data) { const xudtList = response.data as { codeHash: string }[]; this.cache = xudtList.map((xudt) => {