From f975d0fe9915f9539c61d2d8d3245f1520946b09 Mon Sep 17 00:00:00 2001 From: ahonn Date: Tue, 28 May 2024 17:09:53 +1000 Subject: [PATCH 01/11] test: update tests --- test/services/ckb.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/services/ckb.test.ts b/test/services/ckb.test.ts index 97eebf62..88f83d37 100644 --- a/test/services/ckb.test.ts +++ b/test/services/ckb.test.ts @@ -16,7 +16,7 @@ describe('CKBClient', () => { vi.clearAllMocks(); }); - // XTT + // PDD const xudtTypeScript: Script = { codeHash: '0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb', args: '0x8c556e92974a8dd8237719020a259d606359ac2cc958cb8bda77a1c3bb3cd93b', @@ -38,8 +38,8 @@ describe('CKBClient', () => { }; test('getUniqueCellData: should return the unique cell data', async () => { - // XTT (Unique cell transaction) - const tx = await ckb.rpc.getTransaction('0xe6e23718e45a9c36136367dfb1c47397a7b3db2ff130a1c062f40c795f0b103d'); + // PDD (Unique cell transaction) + const tx = await ckb.rpc.getTransaction('0x6a35da16ab1198008545c78b91abe22999f0dc823055553a13d7de29f3063111'); const index = tx.transaction.outputs.findIndex( (output) => output.type && isUniqueCellTypeScript(output.type, false), ); @@ -47,7 +47,7 @@ describe('CKBClient', () => { expect(data).toEqual({ decimal: 8, name: 'XUDT Test Token', - symbol: 'XTT', + symbol: 'PDD', }); }); From eb9f6c157994603a93bd95e22cdc001f66c96301 Mon Sep 17 00:00:00 2001 From: ahonn Date: Wed, 29 May 2024 19:29:11 +1000 Subject: [PATCH 02/11] chore: upgrade dependencies --- devbox.lock | 41 ++++++++++++++++++++------------------- src/services/paymaster.ts | 1 - src/services/rgbpp.ts | 6 +++--- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/devbox.lock b/devbox.lock index 18fac5d7..7657c0e5 100644 --- a/devbox.lock +++ b/devbox.lock @@ -2,63 +2,64 @@ "lockfile_version": "1", "packages": { "nodePackages.pnpm@latest": { - "last_modified": "2024-03-08T13:51:52Z", - "resolved": "github:NixOS/nixpkgs/a343533bccc62400e8a9560423486a3b6c11a23b#nodePackages.pnpm", + "last_modified": "2024-05-22T06:18:38Z", + "resolved": "github:NixOS/nixpkgs/3f316d2a50699a78afe5e77ca486ad553169061e#nodePackages.pnpm", "source": "devbox-search", - "version": "8.15.3", + "version": "8.15.5", "systems": { "aarch64-darwin": { - "store_path": "/nix/store/m9p6q42njy1k33fdzf2axqyhy8vh4vn5-pnpm-8.15.3" + "store_path": "/nix/store/98b2ljlansqmkpkd5pqfgwhcwr5kvsha-pnpm-8.15.5" }, "aarch64-linux": { - "store_path": "/nix/store/war7jm6ka7afc2v8a78hlq8v9m4pg38m-pnpm-8.15.3" + "store_path": "/nix/store/b0h4xyqwdk2zhyhw42bprjnj2i518sxn-pnpm-8.15.5" }, "x86_64-darwin": { - "store_path": "/nix/store/3w3bs2cdqx7sivcldcf6drwrhilv511m-pnpm-8.15.3" + "store_path": "/nix/store/7xyc072k4g6430vijvylidqacjxy5dbb-pnpm-8.15.5" }, "x86_64-linux": { - "store_path": "/nix/store/hcq09j80njlfghy65qmwhn5nq20nk8kl-pnpm-8.15.3" + "store_path": "/nix/store/77wblnm5dnmgnan3695j3mk4r7j75s5j-pnpm-8.15.5" } } }, "nodejs@latest": { - "last_modified": "2024-03-09T07:11:56Z", - "resolved": "github:NixOS/nixpkgs/0e7f98a5f30166cbed344569426850b21e4091d4#nodejs_21", + "last_modified": "2024-05-22T06:18:38Z", + "plugin_version": "0.0.2", + "resolved": "github:NixOS/nixpkgs/3f316d2a50699a78afe5e77ca486ad553169061e#nodejs_22", "source": "devbox-search", - "version": "21.7.1", + "version": "22.2.0", "systems": { "aarch64-darwin": { - "store_path": "/nix/store/mh1db6rni4mlcr473sh3fy6jg2m38jvg-nodejs-21.7.1" + "store_path": "/nix/store/rz5da1id31jgyax1yb6dms0mzpxkywds-nodejs-22.2.0" }, "aarch64-linux": { - "store_path": "/nix/store/ziyb3ny5f9hcwp0lsb9gwdv1pqsn03x1-nodejs-21.7.1" + "store_path": "/nix/store/dkg3sm7j61sfkpvg0bpi0hbjcccbg2wy-nodejs-22.2.0" }, "x86_64-darwin": { - "store_path": "/nix/store/0zaa3aarbsj38g62ihv94gz2hgvgh6bc-nodejs-21.7.1" + "store_path": "/nix/store/y8ns070yvn6ffbwzhmvk03lw7lh4ly02-nodejs-22.2.0" }, "x86_64-linux": { - "store_path": "/nix/store/4arhczh30ychpx6h2wpj5nhx39wm0nla-nodejs-21.7.1" + "store_path": "/nix/store/72m3szv59j74b12dmicmayvvlikh65qc-nodejs-22.2.0" } } }, "redis@latest": { - "last_modified": "2024-03-08T13:51:52Z", + "last_modified": "2024-05-22T06:18:38Z", "plugin_version": "0.0.2", - "resolved": "github:NixOS/nixpkgs/a343533bccc62400e8a9560423486a3b6c11a23b#redis", + "resolved": "github:NixOS/nixpkgs/3f316d2a50699a78afe5e77ca486ad553169061e#redis", "source": "devbox-search", "version": "7.2.4", "systems": { "aarch64-darwin": { - "store_path": "/nix/store/700kyznxcmlkqqabhwa64vmyg4aj6igj-redis-7.2.4" + "store_path": "/nix/store/f1hmasfrq0s1yag27kmdwv97cjxv85rm-redis-7.2.4" }, "aarch64-linux": { - "store_path": "/nix/store/xlc976dh4nb2aa0gzs0jfgld4cc3x8si-redis-7.2.4" + "store_path": "/nix/store/5ay0vkvk8l2n8fgxnmxdci1y1ldafnx8-redis-7.2.4" }, "x86_64-darwin": { - "store_path": "/nix/store/5v58fadclljqa2fmwq281bx5wma9cslb-redis-7.2.4" + "store_path": "/nix/store/5l40xjgzqsd56dx5zfwr2v6sfpk12lkl-redis-7.2.4" }, "x86_64-linux": { - "store_path": "/nix/store/zp1lapdicjxnjhiz8l6j2j4nn6sa9fg5-redis-7.2.4" + "store_path": "/nix/store/xlvzg81dgimxfjxpxwr2w3q1ca3l5lwa-redis-7.2.4" } } } diff --git a/src/services/paymaster.ts b/src/services/paymaster.ts index a6cf9a73..91e34d30 100644 --- a/src/services/paymaster.ts +++ b/src/services/paymaster.ts @@ -184,7 +184,6 @@ export default class Paymaster implements IPaymaster { this.refilling = true; const filled = await this.refillCellQueue(); if (filled + count < this.presetCount) { - // XXX: consider to send an alert email or other notifications this.cradle.logger.warn('Filled paymaster cells less than the preset count'); const error = new PaymasterCellNotEnoughError('Filled paymaster cells less than the preset count'); this.captureExceptionToSentryScope(error, { diff --git a/src/services/rgbpp.ts b/src/services/rgbpp.ts index 06df22c2..90ffcdd6 100644 --- a/src/services/rgbpp.ts +++ b/src/services/rgbpp.ts @@ -106,7 +106,7 @@ export default class RgbppCollector extends BaseQueueWorker { + utxos.map((utxo: UTXO) => { const { txid, vout } = utxo; const args = buildRgbppLockArgs(vout, txid); const searchKey: SearchKey = { @@ -176,7 +176,7 @@ export default class RgbppCollector extends BaseQueueWorker { const batchCells = await this.getRgbppCellsByBatchRequest(group, typeScript); - return batchCells.map((cells, index: number) => { + return batchCells.map((cells: Cell[], index: number) => { const utxo = group[index]; return { utxo, cells }; }); @@ -188,7 +188,7 @@ export default class RgbppCollector extends BaseQueueWorker cells.length > 0); + const pairs = data.flat().filter(({ cells }: RgbppUtxoCellsPair) => cells.length > 0); return pairs; } From 214f166a84dd2197ee135b78e83fd3fa3c1e33ba Mon Sep 17 00:00:00 2001 From: ahonn Date: Fri, 31 May 2024 16:05:21 +1000 Subject: [PATCH 03/11] feat: collect unconfirmed utxos and calucate pending rgbpp cells balance --- src/routes/rgbpp/address.ts | 129 +++++++++++++++++++++++++++++------- src/routes/rgbpp/types.ts | 4 +- 2 files changed, 108 insertions(+), 25 deletions(-) diff --git a/src/routes/rgbpp/address.ts b/src/routes/rgbpp/address.ts index a7a7dc86..d78eb9cb 100644 --- a/src/routes/rgbpp/address.ts +++ b/src/routes/rgbpp/address.ts @@ -10,6 +10,7 @@ import { Env } from '../../env'; import { getXudtTypeScript, isTypeAssetSupported, leToU128 } from '@rgbpp-sdk/ckb'; import { BI } from '@ckb-lumos/lumos'; import { computeScriptHash } from '@ckb-lumos/lumos/utils'; +import { UTXO } from '../../services/bitcoin/schema'; const addressRoutes: FastifyPluginCallback, Server, ZodTypeProvider> = (fastify, _, done) => { const env: Env = fastify.container.resolve('env'); @@ -39,14 +40,20 @@ const addressRoutes: FastifyPluginCallback, Server, ZodType } /** - * Get RGB++ assets by btc address + * Get UTXOs by btc address */ - async function getRgbppAssetsCells(btc_address: string, typeScript?: Script, no_cache?: string) { + async function getUxtos(btc_address: string, no_cache?: string) { const utxos = await fastify.utxoSyncer.getUtxosByAddress(btc_address, no_cache === 'true'); if (env.UTXO_SYNC_DATA_CACHE_ENABLE) { await fastify.utxoSyncer.enqueueSyncJob(btc_address); } + return utxos; + } + /** + * Get RGB++ assets by btc address + */ + async function getRgbppAssetsCells(btc_address: string, utxos: UTXO[], no_cache?: string) { const rgbppUtxoCellsPairs = await fastify.rgbppCollector.getRgbppUtxoCellsPairs( btc_address, utxos, @@ -56,23 +63,26 @@ const addressRoutes: FastifyPluginCallback, Server, ZodType await fastify.rgbppCollector.enqueueCollectJob(btc_address, utxos); } const cells = rgbppUtxoCellsPairs.map((pair) => pair.cells).flat(); - - if (typeScript) { - return cells.filter((cell) => { - if (!cell.cellOutput.type) { - return false; - } - // if typeScript.args is empty, only compare codeHash and hashType - if (!typeScript.args) { - const script = { ...cell.cellOutput.type, args: '' }; - return serializeScript(script) === serializeScript(typeScript); - } - return serializeScript(cell.cellOutput.type) === serializeScript(typeScript); - }); - } return cells; } + /** + * Filter cells by type script + */ + async function filterCellsByTypeScript(cells: Cell[], typeScript: Script) { + return cells.filter((cell) => { + if (!cell.cellOutput.type) { + return false; + } + // if typeScript.args is empty, only compare codeHash and hashType + if (!typeScript.args) { + const script = { ...cell.cellOutput.type, args: '' }; + return serializeScript(script) === serializeScript(typeScript); + } + return serializeScript(cell.cellOutput.type) === serializeScript(typeScript); + }); + } + fastify.get( '/:btc_address/assets', { @@ -107,8 +117,10 @@ const addressRoutes: FastifyPluginCallback, Server, ZodType async (request) => { const { btc_address } = request.params; const { no_cache } = request.query; + const utxos = await getUxtos(btc_address, no_cache); + const cells = await getRgbppAssetsCells(btc_address, utxos, no_cache); const typeScript = getTypeScript(request); - return getRgbppAssetsCells(btc_address, typeScript, no_cache); + return typeScript ? filterCellsByTypeScript(cells, typeScript) : cells; }, ); @@ -154,7 +166,10 @@ const addressRoutes: FastifyPluginCallback, Server, ZodType if (!typeScript || !isTypeAssetSupported(typeScript, env.NETWORK === 'mainnet')) { throw fastify.httpErrors.badRequest('Unsupported type asset'); } - const cells = await getRgbppAssetsCells(btc_address, typeScript, no_cache); + + const utxos = await getUxtos(btc_address, no_cache); + let cells = await getRgbppAssetsCells(btc_address, utxos, no_cache); + cells = typeScript ? await filterCellsByTypeScript(cells, typeScript) : cells; const scripts = fastify.ckb.getScripts(); if (serializeScript({ ...typeScript, args: '' }) !== serializeScript(scripts.XUDT)) { @@ -162,27 +177,93 @@ const addressRoutes: FastifyPluginCallback, Server, ZodType } const infoCellDataMap = new Map(); + const getInfoCellData = async (type: Script) => { + const typeHash = computeScriptHash(type); + if (!infoCellDataMap.has(typeHash)) { + const infoCellData = fastify.ckb.getInfoCellData(allInfoCellTxs, type); + infoCellDataMap.set(typeHash, infoCellData); + } + const infoCellData = infoCellDataMap.get(typeHash); + return infoCellData; + }; + const allInfoCellTxs = await fastify.ckb.getAllInfoCellTxs(); const xudtBalances: Record = {}; for await (const cell of cells) { const type = cell.cellOutput.type!; const typeHash = computeScriptHash(type); - if (!infoCellDataMap.has(typeHash)) { - const infoCellData = fastify.ckb.getInfoCellData(allInfoCellTxs, type); - infoCellDataMap.set(typeHash, infoCellData); + const infoCellData = await getInfoCellData(type); + const amount = BI.from(leToU128(cell.data)).toHexString(); + if (infoCellData) { + if (!xudtBalances[typeHash]) { + xudtBalances[typeHash] = { + ...infoCellData, + typeHash, + total_amount: amount, + avaliable_amount: amount, + pending_amount: '0x0', + }; + } else { + xudtBalances[typeHash].total_amount = BI.from(xudtBalances[typeHash].total_amount) + .add(BI.from(amount)) + .toHexString(); + xudtBalances[typeHash].avaliable_amount = BI.from(xudtBalances[typeHash].avaliable_amount) + .add(BI.from(amount)) + .toHexString(); + } } - const infoCellData = infoCellDataMap.get(typeHash); + } + + const unconfirmedUtxos = utxos.filter((utxo) => !utxo.status.confirmed); + const unconfirmedTxids = Array.from(new Set(...unconfirmedUtxos.map((utxo) => utxo.txid))); + + const pendingRgbppCkbTxOuputCells = await Promise.all( + unconfirmedTxids.map(async (txid) => { + const job = await fastify.transactionProcessor.getTransactionRequest(txid); + if (!job) { + return []; + } + const { ckbVirtualResult } = job.data; + const outputs = ckbVirtualResult.ckbRawTx.outputs; + return outputs.map((output, index) => { + const cell: Cell = { + outPoint: { + txHash: txid, + index: BI.from(index).toHexString(), + }, + cellOutput: output, + data: ckbVirtualResult.ckbRawTx.outputsData[index], + }; + return cell; + }); + }), + ); + const pendingRgbppCells = typeScript + ? await filterCellsByTypeScript(pendingRgbppCkbTxOuputCells.flat(), typeScript) + : pendingRgbppCkbTxOuputCells.flat(); + + for await (const cell of pendingRgbppCells) { + const type = cell.cellOutput.type!; + const typeHash = computeScriptHash(type); + const infoCellData = await getInfoCellData(type); const amount = BI.from(leToU128(cell.data)).toHexString(); if (infoCellData) { if (!xudtBalances[typeHash]) { xudtBalances[typeHash] = { ...infoCellData, typeHash, - amount, + total_amount: amount, + avaliable_amount: '0x0', + pending_amount: amount, }; } else { - xudtBalances[typeHash].amount = BI.from(xudtBalances[typeHash].amount).add(BI.from(amount)).toHexString(); + xudtBalances[typeHash].total_amount = BI.from(xudtBalances[typeHash].total_amount) + .add(BI.from(amount)) + .toHexString(); + xudtBalances[typeHash].pending_amount = BI.from(xudtBalances[typeHash].pending_amount) + .add(BI.from(amount)) + .toHexString(); } } } diff --git a/src/routes/rgbpp/types.ts b/src/routes/rgbpp/types.ts index 107cec16..b271c9c3 100644 --- a/src/routes/rgbpp/types.ts +++ b/src/routes/rgbpp/types.ts @@ -87,7 +87,9 @@ export const XUDTBalance = z.object({ name: z.string(), decimal: z.number(), symbol: z.string(), - amount: z.string(), + total_amount: z.string(), + avaliable_amount: z.string(), + pending_amount: z.string(), typeHash: z.string(), }); export type XUDTBalance = z.infer; From 84d89e04579006ac615ea17022ecdcdddf54e49f Mon Sep 17 00:00:00 2001 From: ahonn Date: Fri, 31 May 2024 16:41:47 +1000 Subject: [PATCH 04/11] refactor: optimize xudt info cell cache --- src/routes/rgbpp/address.ts | 15 +-------------- src/services/base/data-cache.ts | 8 ++++---- src/services/ckb.ts | 23 +++++++++++++++-------- 3 files changed, 20 insertions(+), 26 deletions(-) diff --git a/src/routes/rgbpp/address.ts b/src/routes/rgbpp/address.ts index d78eb9cb..02439fdf 100644 --- a/src/routes/rgbpp/address.ts +++ b/src/routes/rgbpp/address.ts @@ -176,24 +176,11 @@ const addressRoutes: FastifyPluginCallback, Server, ZodType throw fastify.httpErrors.badRequest('Unsupported type asset'); } - const infoCellDataMap = new Map(); - const getInfoCellData = async (type: Script) => { - const typeHash = computeScriptHash(type); - if (!infoCellDataMap.has(typeHash)) { - const infoCellData = fastify.ckb.getInfoCellData(allInfoCellTxs, type); - infoCellDataMap.set(typeHash, infoCellData); - } - const infoCellData = infoCellDataMap.get(typeHash); - return infoCellData; - }; - - const allInfoCellTxs = await fastify.ckb.getAllInfoCellTxs(); const xudtBalances: Record = {}; - for await (const cell of cells) { const type = cell.cellOutput.type!; const typeHash = computeScriptHash(type); - const infoCellData = await getInfoCellData(type); + const infoCellData = await fastify.ckb.getInfoCellData(type); const amount = BI.from(leToU128(cell.data)).toHexString(); if (infoCellData) { if (!xudtBalances[typeHash]) { diff --git a/src/services/base/data-cache.ts b/src/services/base/data-cache.ts index cc21c273..b91a7769 100644 --- a/src/services/base/data-cache.ts +++ b/src/services/base/data-cache.ts @@ -27,18 +27,18 @@ export default class DataCache { this.expire = options.expire; } - public async set(btcAddress: string, data: unknown) { + public async set(id: string, data: unknown) { const parsed = this.schema.safeParse(data); if (!parsed.success) { throw new DataCacheError(parsed.error.message); } - const key = `data-cache:${this.prefix}:${btcAddress}`; + const key = `data-cache:${this.prefix}:${id}`; await this.redis.set(key, JSON.stringify(parsed.data), 'PX', this.expire); return parsed.data; } - public async get(btcAddress: string): Promise { - const key = `data-cache:${this.prefix}:${btcAddress}`; + public async get(id: string): Promise { + const key = `data-cache:${this.prefix}:${id}`; const data = await this.redis.get(key); if (data) { const parsed = this.schema.safeParse(JSON.parse(data)); diff --git a/src/services/ckb.ts b/src/services/ckb.ts index 1b78ad9f..0b53d920 100644 --- a/src/services/ckb.ts +++ b/src/services/ckb.ts @@ -136,12 +136,12 @@ export class CKBRpcError extends Error { export default class CKBClient { public rpc: RPC; public indexer: Indexer; - private dataCahe: DataCache; + private dataCache: DataCache; constructor(private cradle: Cradle) { this.rpc = new RPC(cradle.env.CKB_RPC_URL); this.indexer = new Indexer(cradle.env.CKB_RPC_URL); - this.dataCahe = new DataCache(cradle.redis, { + this.dataCache = new DataCache(cradle.redis, { prefix: 'ckb-info-cell-txs', expire: 60 * 1000, }); @@ -215,9 +215,9 @@ export default class CKBClient { * Get all transactions that have the xudt type cell and info cell */ public async getAllInfoCellTxs() { - const cachedTxs = await this.dataCahe.get('all'); + const cachedTxs = await this.dataCache.get('all'); if (cachedTxs) { - return cachedTxs; + return cachedTxs as CKBComponents.TransactionWithStatus[]; } const scripts = this.getScripts(); @@ -249,18 +249,23 @@ export default class CKBClient { }); }); const txs: CKBComponents.TransactionWithStatus[] = await batchRequest.exec(); - await this.dataCahe.set('all', txs); + await this.dataCache.set('all', txs); return txs; } /** * Get the unique cell of the given xudt type - * @param txs - the transactions that have the xudt type cell and unique cell * @param script - the xudt type script */ - public getInfoCellData(txs: CKBComponents.TransactionWithStatus[], script: Script) { - const isMainnet = this.cradle.env.NETWORK === 'mainnet'; + public async getInfoCellData(script: Script) { + const typeHash = computeScriptHash(script); + const cachedData = await this.dataCache.get(`type:${typeHash}`); + if (cachedData) { + return cachedData as ReturnType; + } + const isMainnet = this.cradle.env.NETWORK === 'mainnet'; + const txs = await this.getAllInfoCellTxs(); for (const tx of txs) { // check if the unique cell is the info cell of the xudt type const uniqueCellIndex = tx.transaction.outputs.findIndex((cell) => { @@ -269,6 +274,7 @@ export default class CKBClient { if (uniqueCellIndex !== -1) { const infoCellData = this.getUniqueCellData(tx, uniqueCellIndex, script); if (infoCellData) { + await this.dataCache.set(`type:${typeHash}`, infoCellData); return infoCellData; } } @@ -279,6 +285,7 @@ export default class CKBClient { if (inscriptionCellIndex !== -1) { const infoCellData = this.getInscriptionInfoCellData(tx, inscriptionCellIndex, script); if (infoCellData) { + await this.dataCache.set(`type:${typeHash}`, infoCellData); return infoCellData; } } From 312be2069903c61ac566171dc5361ff0f116770b Mon Sep 17 00:00:00 2001 From: ahonn Date: Fri, 31 May 2024 17:01:45 +1000 Subject: [PATCH 05/11] refactor: refactor rgbpp balance api to imporve readibilty --- src/routes/rgbpp/address.ts | 113 ++++++++++-------------------------- src/routes/rgbpp/types.ts | 2 +- src/services/rgbpp.ts | 43 +++++++++++++- src/services/transaction.ts | 34 ++++++++++- 4 files changed, 104 insertions(+), 88 deletions(-) diff --git a/src/routes/rgbpp/address.ts b/src/routes/rgbpp/address.ts index 02439fdf..4fb40553 100644 --- a/src/routes/rgbpp/address.ts +++ b/src/routes/rgbpp/address.ts @@ -7,9 +7,8 @@ import { blockchain } from '@ckb-lumos/base'; import z from 'zod'; import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; import { Env } from '../../env'; -import { getXudtTypeScript, isTypeAssetSupported, leToU128 } from '@rgbpp-sdk/ckb'; +import { getXudtTypeScript, isTypeAssetSupported } from '@rgbpp-sdk/ckb'; import { BI } from '@ckb-lumos/lumos'; -import { computeScriptHash } from '@ckb-lumos/lumos/utils'; import { UTXO } from '../../services/bitcoin/schema'; const addressRoutes: FastifyPluginCallback, Server, ZodTypeProvider> = (fastify, _, done) => { @@ -166,94 +165,42 @@ const addressRoutes: FastifyPluginCallback, Server, ZodType if (!typeScript || !isTypeAssetSupported(typeScript, env.NETWORK === 'mainnet')) { throw fastify.httpErrors.badRequest('Unsupported type asset'); } - - const utxos = await getUxtos(btc_address, no_cache); - let cells = await getRgbppAssetsCells(btc_address, utxos, no_cache); - cells = typeScript ? await filterCellsByTypeScript(cells, typeScript) : cells; - const scripts = fastify.ckb.getScripts(); if (serializeScript({ ...typeScript, args: '' }) !== serializeScript(scripts.XUDT)) { throw fastify.httpErrors.badRequest('Unsupported type asset'); } + const utxos = await getUxtos(btc_address, no_cache); const xudtBalances: Record = {}; - for await (const cell of cells) { - const type = cell.cellOutput.type!; - const typeHash = computeScriptHash(type); - const infoCellData = await fastify.ckb.getInfoCellData(type); - const amount = BI.from(leToU128(cell.data)).toHexString(); - if (infoCellData) { - if (!xudtBalances[typeHash]) { - xudtBalances[typeHash] = { - ...infoCellData, - typeHash, - total_amount: amount, - avaliable_amount: amount, - pending_amount: '0x0', - }; - } else { - xudtBalances[typeHash].total_amount = BI.from(xudtBalances[typeHash].total_amount) - .add(BI.from(amount)) - .toHexString(); - xudtBalances[typeHash].avaliable_amount = BI.from(xudtBalances[typeHash].avaliable_amount) - .add(BI.from(amount)) - .toHexString(); - } - } - } - const unconfirmedUtxos = utxos.filter((utxo) => !utxo.status.confirmed); - const unconfirmedTxids = Array.from(new Set(...unconfirmedUtxos.map((utxo) => utxo.txid))); - - const pendingRgbppCkbTxOuputCells = await Promise.all( - unconfirmedTxids.map(async (txid) => { - const job = await fastify.transactionProcessor.getTransactionRequest(txid); - if (!job) { - return []; - } - const { ckbVirtualResult } = job.data; - const outputs = ckbVirtualResult.ckbRawTx.outputs; - return outputs.map((output, index) => { - const cell: Cell = { - outPoint: { - txHash: txid, - index: BI.from(index).toHexString(), - }, - cellOutput: output, - data: ckbVirtualResult.ckbRawTx.outputsData[index], - }; - return cell; - }); - }), - ); - const pendingRgbppCells = typeScript - ? await filterCellsByTypeScript(pendingRgbppCkbTxOuputCells.flat(), typeScript) - : pendingRgbppCkbTxOuputCells.flat(); - - for await (const cell of pendingRgbppCells) { - const type = cell.cellOutput.type!; - const typeHash = computeScriptHash(type); - const infoCellData = await getInfoCellData(type); - const amount = BI.from(leToU128(cell.data)).toHexString(); - if (infoCellData) { - if (!xudtBalances[typeHash]) { - xudtBalances[typeHash] = { - ...infoCellData, - typeHash, - total_amount: amount, - avaliable_amount: '0x0', - pending_amount: amount, - }; - } else { - xudtBalances[typeHash].total_amount = BI.from(xudtBalances[typeHash].total_amount) - .add(BI.from(amount)) - .toHexString(); - xudtBalances[typeHash].pending_amount = BI.from(xudtBalances[typeHash].pending_amount) - .add(BI.from(amount)) - .toHexString(); - } - } - } + let cells = await getRgbppAssetsCells(btc_address, utxos, no_cache); + cells = typeScript ? await filterCellsByTypeScript(cells, typeScript) : cells; + const availableXudtBalances = await fastify.rgbppCollector.getRgbppBalanceByCells(cells); + Object.keys(availableXudtBalances).forEach((key) => { + const { amount, ...xudtInfo } = availableXudtBalances[key]; + xudtBalances[key] = { + ...xudtInfo, + total_amount: amount, + available_amount: amount, + pending_amount: '0x0', + }; + }); + + const pendingUtxos = utxos.filter((utxo) => !utxo.status.confirmed); + const pendingTxids = Array.from(new Set(...pendingUtxos.map((utxo) => utxo.txid))); + let pendingOutputCells = await fastify.transactionProcessor.getPendingOuputCellsByTxids(pendingTxids); + pendingOutputCells = typeScript + ? await filterCellsByTypeScript(pendingOutputCells, typeScript) + : pendingOutputCells; + const pendingXudtBalances = await fastify.rgbppCollector.getRgbppBalanceByCells(pendingOutputCells); + Object.values(pendingXudtBalances).forEach(({ amount, typeHash }) => { + xudtBalances[typeHash].pending_amount = BI.from(xudtBalances[typeHash].pending_amount) + .add(BI.from(amount)) + .toHexString(); + xudtBalances[typeHash].total_amount = BI.from(xudtBalances[typeHash].total_amount) + .add(BI.from(amount)) + .toHexString(); + }); return { address: btc_address, diff --git a/src/routes/rgbpp/types.ts b/src/routes/rgbpp/types.ts index b271c9c3..bd1d2af1 100644 --- a/src/routes/rgbpp/types.ts +++ b/src/routes/rgbpp/types.ts @@ -88,7 +88,7 @@ export const XUDTBalance = z.object({ decimal: z.number(), symbol: z.string(), total_amount: z.string(), - avaliable_amount: z.string(), + available_amount: z.string(), pending_amount: z.string(), typeHash: z.string(), }); diff --git a/src/services/rgbpp.ts b/src/services/rgbpp.ts index 90ffcdd6..2cba34b0 100644 --- a/src/services/rgbpp.ts +++ b/src/services/rgbpp.ts @@ -2,15 +2,16 @@ import { UTXO } from './bitcoin/schema'; import pLimit from 'p-limit'; import asyncRetry from 'async-retry'; import { Cradle } from '../container'; -import { IndexerCell, buildRgbppLockArgs, genRgbppLockScript } from '@rgbpp-sdk/ckb'; +import { IndexerCell, buildRgbppLockArgs, genRgbppLockScript, leToU128 } from '@rgbpp-sdk/ckb'; import * as Sentry from '@sentry/node'; -import { RPC, Script } from '@ckb-lumos/lumos'; +import { BI, RPC, Script } from '@ckb-lumos/lumos'; import { Job } from 'bullmq'; import { z } from 'zod'; -import { Cell } from '../routes/rgbpp/types'; +import { Cell, XUDTBalance } from '../routes/rgbpp/types'; import BaseQueueWorker from './base/queue-worker'; import DataCache from './base/data-cache'; import { groupBy } from 'lodash'; +import { computeScriptHash } from '@ckb-lumos/lumos/utils'; type GetCellsParams = Parameters; type SearchKey = GetCellsParams[0]; @@ -89,6 +90,11 @@ export default class RgbppCollector extends BaseQueueWorker { const key = `${utxo.txid}:${utxo.vout}`; @@ -99,6 +105,37 @@ export default class RgbppCollector extends BaseQueueWorker & { + amount: string; + } + > = {}; + for await (const cell of cells) { + const type = cell.cellOutput.type!; + const typeHash = computeScriptHash(type); + const infoCellData = await this.cradle.ckb.getInfoCellData(type); + const amount = BI.from(leToU128(cell.data)).toHexString(); + if (infoCellData) { + if (!xudtBalances[typeHash]) { + xudtBalances[typeHash] = { + ...infoCellData, + typeHash, + amount: amount, + }; + } else { + xudtBalances[typeHash].amount = BI.from(xudtBalances[typeHash].amount).add(BI.from(amount)).toHexString(); + } + } + } + return xudtBalances; + } + /** * Get the rgbpp cells batch request for the utxos * @param utxos - the utxos to collect diff --git a/src/services/transaction.ts b/src/services/transaction.ts index 70cb8816..afabff1c 100644 --- a/src/services/transaction.ts +++ b/src/services/transaction.ts @@ -25,7 +25,7 @@ import { Transaction as BitcoinTransaction } from 'bitcoinjs-lib'; import { DelayedError, Job } from 'bullmq'; import { Cradle } from '../container'; import { Transaction } from '../routes/bitcoin/types'; -import { CKBRawTransaction, CKBVirtualResult } from '../routes/rgbpp/types'; +import { CKBRawTransaction, CKBVirtualResult, Cell } from '../routes/rgbpp/types'; import { BitcoinSPVError } from './spv'; import { BloomFilter } from 'bloom-filters'; import { BI } from '@ckb-lumos/lumos'; @@ -580,6 +580,38 @@ export default class TransactionProcessor return job; } + public async getPendingOuputCellsByTxids(txids: string[]) { + const pendingOutputCells = await Promise.all( + txids.map(async (txid) => { + const job = await this.getTransactionRequest(txid); + if (!job) { + return []; + } + + // get ckb output cells from the uncompleted job only + const state = await job.getState(); + if (state === 'completed') { + return []; + } + + const { ckbVirtualResult } = job.data; + const outputs = ckbVirtualResult.ckbRawTx.outputs; + return outputs.map((output, index) => { + const cell: Cell = { + outPoint: { + txHash: txid, + index: BI.from(index).toHexString(), + }, + cellOutput: output, + data: ckbVirtualResult.ckbRawTx.outputsData[index], + }; + return cell; + }); + }), + ); + return pendingOutputCells.flat(); + } + /** * Retry all failed jobs in the queue * @param maxAttempts - the max attempts to retry From 0e2e203ca916988f358317e845b22df79d82ad13 Mon Sep 17 00:00:00 2001 From: ahonn Date: Mon, 3 Jun 2024 12:15:03 +1000 Subject: [PATCH 06/11] test: add rgbpp address tests --- devbox.json | 2 +- devbox.lock | 58 ++- src/routes/rgbpp/address.ts | 2 +- test/__fixtures__/rgbpp-utxo-pairs.mock.json | 37 -- .../rgbpp/__snapshots__/address.test.ts.snap | 340 ++++++++++++++++++ test/routes/rgbpp/address.test.ts | 140 ++++++++ test/routes/rgbpp/transaction.test.ts | 2 +- 7 files changed, 534 insertions(+), 47 deletions(-) create mode 100644 test/routes/rgbpp/__snapshots__/address.test.ts.snap create mode 100644 test/routes/rgbpp/address.test.ts diff --git a/devbox.json b/devbox.json index dfbeeb85..53fcd406 100644 --- a/devbox.json +++ b/devbox.json @@ -1,6 +1,6 @@ { "packages": [ - "nodejs@latest", + "nodejs@20", "nodePackages.pnpm@latest", "redis@latest" ] diff --git a/devbox.lock b/devbox.lock index 7657c0e5..7930791c 100644 --- a/devbox.lock +++ b/devbox.lock @@ -21,24 +21,68 @@ } } }, - "nodejs@latest": { + "nodejs@20": { "last_modified": "2024-05-22T06:18:38Z", "plugin_version": "0.0.2", - "resolved": "github:NixOS/nixpkgs/3f316d2a50699a78afe5e77ca486ad553169061e#nodejs_22", + "resolved": "github:NixOS/nixpkgs/3f316d2a50699a78afe5e77ca486ad553169061e#nodejs_20", "source": "devbox-search", - "version": "22.2.0", + "version": "20.12.2", "systems": { "aarch64-darwin": { - "store_path": "/nix/store/rz5da1id31jgyax1yb6dms0mzpxkywds-nodejs-22.2.0" + "outputs": [ + { + "name": "out", + "path": "/nix/store/bzzs4kvjyvjjhs3rj08vqpvvzmfggvbv-nodejs-20.12.2", + "default": true + }, + { + "name": "libv8", + "path": "/nix/store/c56874bxzncqwy58kif6wfnzy017v1sl-nodejs-20.12.2-libv8" + } + ], + "store_path": "/nix/store/bzzs4kvjyvjjhs3rj08vqpvvzmfggvbv-nodejs-20.12.2" }, "aarch64-linux": { - "store_path": "/nix/store/dkg3sm7j61sfkpvg0bpi0hbjcccbg2wy-nodejs-22.2.0" + "outputs": [ + { + "name": "out", + "path": "/nix/store/y50zafzgnnkrj4hvmk23icv2ggvys8r9-nodejs-20.12.2", + "default": true + }, + { + "name": "libv8", + "path": "/nix/store/vc7y8h3c8pwbh4zbvjcyfqrd3fhdjhw6-nodejs-20.12.2-libv8" + } + ], + "store_path": "/nix/store/y50zafzgnnkrj4hvmk23icv2ggvys8r9-nodejs-20.12.2" }, "x86_64-darwin": { - "store_path": "/nix/store/y8ns070yvn6ffbwzhmvk03lw7lh4ly02-nodejs-22.2.0" + "outputs": [ + { + "name": "out", + "path": "/nix/store/l53svh1nfrcb83qbqvrrkangrcl1rr25-nodejs-20.12.2", + "default": true + }, + { + "name": "libv8", + "path": "/nix/store/q71hh22bfqjygd34gq16dv4dwfc33378-nodejs-20.12.2-libv8" + } + ], + "store_path": "/nix/store/l53svh1nfrcb83qbqvrrkangrcl1rr25-nodejs-20.12.2" }, "x86_64-linux": { - "store_path": "/nix/store/72m3szv59j74b12dmicmayvvlikh65qc-nodejs-22.2.0" + "outputs": [ + { + "name": "out", + "path": "/nix/store/6g9n96qf1yx139xklnmy3v4xhjvjgsji-nodejs-20.12.2", + "default": true + }, + { + "name": "libv8", + "path": "/nix/store/s7b0dqga0311mvq48mirnlm0p3dr4gm3-nodejs-20.12.2-libv8" + } + ], + "store_path": "/nix/store/6g9n96qf1yx139xklnmy3v4xhjvjgsji-nodejs-20.12.2" } } }, diff --git a/src/routes/rgbpp/address.ts b/src/routes/rgbpp/address.ts index 4fb40553..365de331 100644 --- a/src/routes/rgbpp/address.ts +++ b/src/routes/rgbpp/address.ts @@ -187,7 +187,7 @@ const addressRoutes: FastifyPluginCallback, Server, ZodType }); const pendingUtxos = utxos.filter((utxo) => !utxo.status.confirmed); - const pendingTxids = Array.from(new Set(...pendingUtxos.map((utxo) => utxo.txid))); + const pendingTxids = Array.from(new Set(pendingUtxos.map((utxo) => utxo.txid))); let pendingOutputCells = await fastify.transactionProcessor.getPendingOuputCellsByTxids(pendingTxids); pendingOutputCells = typeScript ? await filterCellsByTypeScript(pendingOutputCells, typeScript) diff --git a/test/__fixtures__/rgbpp-utxo-pairs.mock.json b/test/__fixtures__/rgbpp-utxo-pairs.mock.json index 195677f6..f956630e 100644 --- a/test/__fixtures__/rgbpp-utxo-pairs.mock.json +++ b/test/__fixtures__/rgbpp-utxo-pairs.mock.json @@ -1,41 +1,4 @@ [ - { - "utxo": { - "txid": "989f4e03179e17cbb6edd446f57ea6107a40ba23441056653f1cc34b7dd1e5ba", - "vout": 1, - "value": 546, - "status": { - "confirmed": true, - "block_height": 2812535, - "block_hash": "000000000000001d4c78f85fd7fda56916f448bb25f4b3b275f1cf6634e17bf8", - "block_time": 1715047029 - } - }, - "cells": [ - { - "cellOutput": { - "capacity": "0x5e9f52687", - "lock": { - "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", - "args": "0x01000000bae5d17d4bc31c3f6556104423ba407a10a67ef546d4edb6cb179e17034e9f98", - "hashType": "type" - }, - "type": { - "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", - "args": "0x30d3fbec9ceba691770d57c6d06bdb98cf0f82bef0ca6e87687a118d6ce1e7b7", - "hashType": "type" - } - }, - "data": "0x00e1f505000000000000000000000000", - "outPoint": { - "txHash": "0x5e0e3bc6429fe8ec6da213f4de31bb40581b36be221458ab1766bf86bcb49e42", - "index": "0x0" - }, - "blockNumber": "0xc8ebc1", - "txIndex": "0x3" - } - ] - }, { "utxo": { "txid": "0c05a2ba51c6284eb1411bd7d49df455da97a482a8ce47266b50a4d3d857ee29", diff --git a/test/routes/rgbpp/__snapshots__/address.test.ts.snap b/test/routes/rgbpp/__snapshots__/address.test.ts.snap new file mode 100644 index 00000000..b60450da --- /dev/null +++ b/test/routes/rgbpp/__snapshots__/address.test.ts.snap @@ -0,0 +1,340 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`/:btc_address/assets 1`] = ` +[ + { + "blockNumber": "0xc35b01", + "cellOutput": { + "capacity": "0x5e9f5203e", + "lock": { + "args": "0x0200000029ee57d8d3a4506b2647cea882a497da55f49dd4d71b41b14e28c651baa2050c", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0xc0d45407000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0x4f8f6042b3646e677c871be1629150407b520e48174612d428506995f6055558", + }, + "txIndex": "0x8", + }, + { + "blockNumber": "0xc87015", + "cellOutput": { + "capacity": "0x5e9e620d3", + "lock": { + "args": "0x02000000f42636cfd158d159c959ff931351636adff46b3cef5cd28d953b0fd07526d20b", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x008c8647000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0xe098e5919e496fc6efb601307578cc436df7d554b9a3994f03b85d0ad2e8e7a6", + }, + "txIndex": "0x1", + }, + { + "blockNumber": "0xcc3842", + "cellOutput": { + "capacity": "0xa7a358200", + "lock": { + "args": "0x000000008c8afb798a1637a284f1ef889e053a7f1e7030747f51cb86a31138c28b681aed", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xaf68a7bcf1423b57e7ce8636c28dedb463c6e69f62b1b35ca1ed9abf9a6b3d18", + "codeHash": "0x685a60219309029d01310311dba953d67029170ca4848a4ff638e57002130a0d", + "hashType": "data1", + }, + }, + "data": "0xd40000001000000024000000b0000000100000006170706c69636174696f6e2f6a736f6e880000007b226e616d65223a22556e69636f726e20426f78222c227265736f75726365223a7b2275726c223a2268747470733a2f2f6172736565642e77656233696e6672612e6465762f306b4e437450376169417253596f6c6e424f656466705545493948554b7273323142443772495247735677222c2274797065223a22696d6167652f6a706567227d7d20000000ed3d643329453a418a8902a40c225ca81f405904b4ec9509ff09048240d30a86", + "outPoint": { + "index": "0x0", + "txHash": "0xdd0226408c4c31b2466f7c3d661d4e3e3c8b429631212a525f6668765baadc80", + }, + "txIndex": "0x1", + }, + { + "blockNumber": "0xcb4375", + "cellOutput": { + "capacity": "0x5e9f53e00", + "lock": { + "args": "0x000000009b18c0f40491710e536b9916cb9d8326678b27ad5856cf51f0fdf031dec0f53e", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xc625c4ac0ba3ece5886d04958c3fc2d5558a21841c03577fad2d7c46e5b2b2b9", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x80969800000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0x3aeb2a7f8e00ca32fae9b658da88274f2dcfeff41108ea28b567dc9b79c7dd3c", + }, + "txIndex": "0x3", + }, + { + "blockNumber": "0xc35ba6", + "cellOutput": { + "capacity": "0x5e9f52f1f", + "lock": { + "args": "0x02000000bbd4d25df0dcc16d9e8cdd70872c1ce2a5acc4394a3cc32ab862ade346317d05", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0xa08d7313000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0x71b4f66ac7f657e3b96b5b0694de5fadb61740d2644eabb91090dd9bce93316a", + }, + "txIndex": "0x4", + }, + { + "blockNumber": "0xcb4378", + "cellOutput": { + "capacity": "0x5e9f53e00", + "lock": { + "args": "0x00000000b24761ad734952f78b5974e810f08a408965f27844772a35bfd6162dfe3eb4f7", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xc625c4ac0ba3ece5886d04958c3fc2d5558a21841c03577fad2d7c46e5b2b2b9", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x80f0fa02000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0xb5ab02c1583387fa7bc3cb7e61daccead6d4d6b9a1294555328d4bc209ed5f8f", + }, + "txIndex": "0x1", + }, + { + "blockNumber": "0xcc383d", + "cellOutput": { + "capacity": "0x94a39af00", + "lock": { + "args": "0x00000000906f620ad43ea196a10c077e9238515111cb0b6faa7eb69679e72528a17afafd", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xacb57628e8814a675ac3dfcdcd86b89da85399a82bfceedccb2c8a2200c48c1e", + "codeHash": "0x685a60219309029d01310311dba953d67029170ca4848a4ff638e57002130a0d", + "hashType": "data1", + }, + }, + "data": "0xa100000010000000190000007d00000005000000646f622f30600000007b22626c6f636b5f6e756d626572223a31333038343932382c2263656c6c5f6964223a363132303533383831383036373235383030302c22646e61223a226166323566336565383563383734623030343638316334333162373835626231227d20000000c1097c85aa781d2cd3c017dc911eceab94644cfe2dd714ae7f7bbe4b75accb08", + "outPoint": { + "index": "0x0", + "txHash": "0x3b1a2d2d00a5ef95b45d93cc1d9394a411319f956121d95104b784e8b469f538", + }, + "txIndex": "0x3", + }, + { + "blockNumber": "0xc35ba6", + "cellOutput": { + "capacity": "0x5e9f52f1f", + "lock": { + "args": "0x02000000976e945e25e9645ab5705c0bebe687e75f8b678fc6e0c9b26081b368f51563a4", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x01000000000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0x274865dc9e754ab8fc96cbc7be20093feca0073b91d3157aed2639f6e89ada90", + }, + "txIndex": "0x8", + }, + { + "blockNumber": "0xcc3d9d", + "cellOutput": { + "capacity": "0x5e9f53e00", + "lock": { + "args": "0x01000000a7fd61a66986273e1e8500e276e5ade9e1d66658e73cc1a4123a440ef6f78d36", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0x30d3fbec9ceba691770d57c6d06bdb98cf0f82bef0ca6e87687a118d6ce1e7b7", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x00e1f505000000000000000000000000", + "outPoint": { + "index": "0x1", + "txHash": "0xefcada73aa020bfc4c4dc7192f9a6a6e6152af77d1bb2c2380314b4130751bc4", + }, + "txIndex": "0x6", + }, + { + "blockNumber": "0xcb42df", + "cellOutput": { + "capacity": "0x5e9f53e00", + "lock": { + "args": "0x00000000fe7e313c6bb99211e222dd1a4ae62a046ef4170d1e74a7252a827b0636ef6965", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xc625c4ac0ba3ece5886d04958c3fc2d5558a21841c03577fad2d7c46e5b2b2b9", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x00e1f505000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0xeec5c357338f622f9bf586532be687f8fc1918566f27b4abb7fa5f9c1891af6b", + }, + "txIndex": "0x2", + }, + { + "blockNumber": "0xcb669c", + "cellOutput": { + "capacity": "0x5e9f53e00", + "lock": { + "args": "0x000000004db3c41e5993ba73c0c916494d3f0e09042f2dcd8d48abd64b13a2ed6a149ffc", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xc625c4ac0ba3ece5886d04958c3fc2d5558a21841c03577fad2d7c46e5b2b2b9", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0xa0860100000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0x2f6b86c4311dc854e779c0bbce110f397a0acc03dfe435aedf832b4f3de1a485", + }, + "txIndex": "0x1", + }, + { + "blockNumber": "0xcb7072", + "cellOutput": { + "capacity": "0xa7a358200", + "lock": { + "args": "0x00000000ab39226c7b575b968798ebdb7f72b2ecec3d7cd6d71c38d11f095b8e2a8e61f3", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0x76fd065c31d24a2c8219e7d56942fed3d49ff728697d98a1079edb06187ec91c", + "codeHash": "0x685a60219309029d01310311dba953d67029170ca4848a4ff638e57002130a0d", + "hashType": "data1", + }, + }, + "data": "0xd40000001000000024000000b0000000100000006170706c69636174696f6e2f6a736f6e880000007b226e616d65223a22556e69636f726e20426f78222c227265736f75726365223a7b2275726c223a2268747470733a2f2f6172736565642e77656233696e6672612e6465762f306b4e437450376169417253596f6c6e424f656466705545493948554b7273323142443772495247735677222c2274797065223a22696d6167652f6a706567227d7d20000000ed3d643329453a418a8902a40c225ca81f405904b4ec9509ff09048240d30a86", + "outPoint": { + "index": "0x0", + "txHash": "0xbd1886d03da82d0a012af423044d8f192598d3a7be454397497fd22aba2a784e", + }, + "txIndex": "0x1", + }, +] +`; + +exports[`/:btc_address/balance - with pending_amount 1`] = ` +{ + "address": "tb1pusqtndhyt8mcrggngd0lmah4xshc0aa8vpfsttvtzxd0hxhkrwns7977yu", + "xudt": [ + { + "available_amount": "0x624eee61", + "decimal": 8, + "name": "CKB Fist Inscription", + "pending_amount": "0x0", + "symbol": "CKBI", + "total_amount": "0x624eee61", + "typeHash": "0x7337d2075479d5c6789564516be1db11478e1d3ca70ad88050fe0bf3ff05acc2", + }, + { + "available_amount": "0x98aeea0", + "decimal": 8, + "name": "JoyID Dex Test Inscription", + "pending_amount": "0x0", + "symbol": "JDI", + "total_amount": "0x98aeea0", + "typeHash": "0x6d7dd4497d1ef095644e422d30b2456cfe32c6469346c77752a4d6b56f432a73", + }, + { + "available_amount": "0x5f5e100", + "decimal": 8, + "name": "", + "pending_amount": "0x5f5e100", + "symbol": "LP-UTXOSwap V1", + "total_amount": "0xbebc200", + "typeHash": "0x78e21efcf107e7886eadeadecd1a01cfb88f1e5617f4438685db55b3a540d202", + }, + ], +} +`; + +exports[`/:btc_address/balance - without pending_amount 1`] = ` +{ + "address": "tb1pusqtndhyt8mcrggngd0lmah4xshc0aa8vpfsttvtzxd0hxhkrwns7977yu", + "xudt": [ + { + "available_amount": "0x624eee61", + "decimal": 8, + "name": "CKB Fist Inscription", + "pending_amount": "0x0", + "symbol": "CKBI", + "total_amount": "0x624eee61", + "typeHash": "0x7337d2075479d5c6789564516be1db11478e1d3ca70ad88050fe0bf3ff05acc2", + }, + { + "available_amount": "0x98aeea0", + "decimal": 8, + "name": "JoyID Dex Test Inscription", + "pending_amount": "0x0", + "symbol": "JDI", + "total_amount": "0x98aeea0", + "typeHash": "0x6d7dd4497d1ef095644e422d30b2456cfe32c6469346c77752a4d6b56f432a73", + }, + { + "available_amount": "0x5f5e100", + "decimal": 8, + "name": "", + "pending_amount": "0x0", + "symbol": "LP-UTXOSwap V1", + "total_amount": "0x5f5e100", + "typeHash": "0x78e21efcf107e7886eadeadecd1a01cfb88f1e5617f4438685db55b3a540d202", + }, + ], +} +`; diff --git a/test/routes/rgbpp/address.test.ts b/test/routes/rgbpp/address.test.ts new file mode 100644 index 00000000..114471cb --- /dev/null +++ b/test/routes/rgbpp/address.test.ts @@ -0,0 +1,140 @@ +import { beforeEach, expect, test, vi } from 'vitest'; +import { buildFastify } from '../../../src/app'; +import { describe } from 'node:test'; +import mockUTXOs from '../../__fixtures__/utxo.mock.json'; +import mockRgbppUtxoPairs from '../../__fixtures__/rgbpp-utxo-pairs.mock.json'; +import { RgbppUtxoCellsPair } from '../../../src/services/rgbpp'; + +let token: string; + +describe('/rgbpp/v1/address', () => { + beforeEach(async () => { + const fastify = buildFastify(); + await fastify.ready(); + + const response = await fastify.inject({ + method: 'POST', + url: '/token/generate', + payload: { + app: 'test', + domain: 'test.com', + }, + }); + const data = response.json(); + token = data.token; + + await fastify.close(); + }); + + test('/:btc_address/assets', async () => { + const fastify = buildFastify(); + await fastify.ready(); + + const utxoSyncer = fastify.container.resolve('utxoSyncer'); + vi.spyOn(utxoSyncer, 'getUtxosByAddress').mockResolvedValueOnce(mockUTXOs); + const rgbppCollector = fastify.container.resolve('rgbppCollector'); + vi.spyOn(rgbppCollector, 'getRgbppUtxoCellsPairs').mockResolvedValueOnce( + mockRgbppUtxoPairs as RgbppUtxoCellsPair[], + ); + + const response = await fastify.inject({ + method: 'GET', + url: '/rgbpp/v1/address/tb1pusqtndhyt8mcrggngd0lmah4xshc0aa8vpfsttvtzxd0hxhkrwns7977yu/assets', + headers: { + Authorization: `Bearer ${token}`, + Origin: 'https://test.com', + }, + }); + const data = response.json(); + + expect(response.statusCode).toBe(200); + expect(data).toMatchSnapshot(); + + await fastify.close(); + }); + + test('/:btc_address/balance - without pending_amount', async () => { + const fastify = buildFastify(); + await fastify.ready(); + + const utxoSyncer = fastify.container.resolve('utxoSyncer'); + vi.spyOn(utxoSyncer, 'getUtxosByAddress').mockResolvedValueOnce(mockUTXOs); + const rgbppCollector = fastify.container.resolve('rgbppCollector'); + vi.spyOn(rgbppCollector, 'getRgbppUtxoCellsPairs').mockResolvedValueOnce( + mockRgbppUtxoPairs as RgbppUtxoCellsPair[], + ); + + const response = await fastify.inject({ + method: 'GET', + url: '/rgbpp/v1/address/tb1pusqtndhyt8mcrggngd0lmah4xshc0aa8vpfsttvtzxd0hxhkrwns7977yu/balance', + headers: { + Authorization: `Bearer ${token}`, + Origin: 'https://test.com', + }, + }); + const data = response.json(); + + expect(response.statusCode).toBe(200); + expect(data).toMatchSnapshot(); + + await fastify.close(); + }); + + test('/:btc_address/balance - with pending_amount', async () => { + const fastify = buildFastify(); + await fastify.ready(); + + const utxoSyncer = fastify.container.resolve('utxoSyncer'); + vi.spyOn(utxoSyncer, 'getUtxosByAddress').mockResolvedValueOnce(mockUTXOs); + const rgbppCollector = fastify.container.resolve('rgbppCollector'); + vi.spyOn(rgbppCollector, 'getRgbppUtxoCellsPairs').mockResolvedValueOnce( + mockRgbppUtxoPairs as RgbppUtxoCellsPair[], + ); + const transactionProcessor = fastify.container.resolve('transactionProcessor'); + const getPendingOuputCellsByTxidsSpy = vi + .spyOn(transactionProcessor, 'getPendingOuputCellsByTxids') + .mockResolvedValueOnce([ + { + cellOutput: { + capacity: '0x5e9f52687', + lock: { + codeHash: '0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248', + args: '0x01000000bae5d17d4bc31c3f6556104423ba407a10a67ef546d4edb6cb179e17034e9f98', + hashType: 'type', + }, + type: { + codeHash: '0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb', + args: '0x30d3fbec9ceba691770d57c6d06bdb98cf0f82bef0ca6e87687a118d6ce1e7b7', + hashType: 'type', + }, + }, + data: '0x00e1f505000000000000000000000000', + outPoint: { + txHash: '0x5e0e3bc6429fe8ec6da213f4de31bb40581b36be221458ab1766bf86bcb49e42', + index: '0x0', + }, + blockNumber: '0xc8ebc1', + txIndex: '0x3', + }, + ]); + + const response = await fastify.inject({ + method: 'GET', + url: '/rgbpp/v1/address/tb1pusqtndhyt8mcrggngd0lmah4xshc0aa8vpfsttvtzxd0hxhkrwns7977yu/balance', + headers: { + Authorization: `Bearer ${token}`, + Origin: 'https://test.com', + }, + }); + const data = response.json(); + + expect(getPendingOuputCellsByTxidsSpy).toHaveBeenCalledWith([ + '989f4e03179e17cbb6edd446f57ea6107a40ba23441056653f1cc34b7dd1e5ba', + 'aab2d8fc3f064087450057ccb6012893cf219043d8c915fe64c5322c0eeb6fd2', + ]); + expect(response.statusCode).toBe(200); + expect(data).toMatchSnapshot(); + + await fastify.close(); + }); +}); diff --git a/test/routes/rgbpp/transaction.test.ts b/test/routes/rgbpp/transaction.test.ts index d414fc3e..eec23337 100644 --- a/test/routes/rgbpp/transaction.test.ts +++ b/test/routes/rgbpp/transaction.test.ts @@ -7,7 +7,7 @@ import { Job } from 'bullmq'; let token: string; -describe('/bitcoin/v1/transaction', () => { +describe('/rgbpp/v1/transaction', () => { beforeEach(async () => { const fastify = buildFastify(); await fastify.ready(); From 511205b07a39a8c412b59cd0078d463724d3c6ac Mon Sep 17 00:00:00 2001 From: ahonn Date: Mon, 3 Jun 2024 14:01:12 +1000 Subject: [PATCH 07/11] test: update tests --- src/services/transaction.ts | 4 + .../services/__snapshots__/rgbpp.test.ts.snap | 982 ++++++++++++++++-- test/services/rgbpp.test.ts | 73 +- 3 files changed, 900 insertions(+), 159 deletions(-) diff --git a/src/services/transaction.ts b/src/services/transaction.ts index afabff1c..a3b0140d 100644 --- a/src/services/transaction.ts +++ b/src/services/transaction.ts @@ -580,6 +580,10 @@ export default class TransactionProcessor return job; } + /** + * get pending output cells by txids, get ckb output cells from the uncompleted job + * @param txids - the transaction ids + */ public async getPendingOuputCellsByTxids(txids: string[]) { const pendingOutputCells = await Promise.all( txids.map(async (txid) => { diff --git a/test/services/__snapshots__/rgbpp.test.ts.snap b/test/services/__snapshots__/rgbpp.test.ts.snap index dea78f97..54f05574 100644 --- a/test/services/__snapshots__/rgbpp.test.ts.snap +++ b/test/services/__snapshots__/rgbpp.test.ts.snap @@ -1,166 +1,948 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`RgbppCollector > collectRgbppUtxoCellsPairs: should return the utxo and the cells 1`] = ` +exports[`RgbppCollector > getRgbppBalanceByCells: should return the rgbpp balance by cells 1`] = ` +{ + "0x6d7dd4497d1ef095644e422d30b2456cfe32c6469346c77752a4d6b56f432a73": { + "amount": "0x98aeea0", + "decimal": 8, + "name": "JoyID Dex Test Inscription", + "symbol": "JDI", + "typeHash": "0x6d7dd4497d1ef095644e422d30b2456cfe32c6469346c77752a4d6b56f432a73", + }, + "0x7337d2075479d5c6789564516be1db11478e1d3ca70ad88050fe0bf3ff05acc2": { + "amount": "0x624eee61", + "decimal": 8, + "name": "CKB Fist Inscription", + "symbol": "CKBI", + "typeHash": "0x7337d2075479d5c6789564516be1db11478e1d3ca70ad88050fe0bf3ff05acc2", + }, + "0x78e21efcf107e7886eadeadecd1a01cfb88f1e5617f4438685db55b3a540d202": { + "amount": "0x5f5e100", + "decimal": 8, + "name": "", + "symbol": "LP-UTXOSwap V1", + "typeHash": "0x78e21efcf107e7886eadeadecd1a01cfb88f1e5617f4438685db55b3a540d202", + }, +} +`; + +exports[`RgbppCollector > getRgbppCellsByBatchRequest: should be filtered by typeScript 1`] = ` +[ + [], + [], + [], + [], + [], + [], + [], + [], + [ + { + "blockNumber": "0xcb4375", + "cellOutput": { + "capacity": "0x5e9f53e00", + "lock": { + "args": "0x000000009b18c0f40491710e536b9916cb9d8326678b27ad5856cf51f0fdf031dec0f53e", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xc625c4ac0ba3ece5886d04958c3fc2d5558a21841c03577fad2d7c46e5b2b2b9", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x80969800000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0x3aeb2a7f8e00ca32fae9b658da88274f2dcfeff41108ea28b567dc9b79c7dd3c", + }, + "txIndex": "0x3", + }, + ], + [], + [ + { + "blockNumber": "0xcb4378", + "cellOutput": { + "capacity": "0x5e9f53e00", + "lock": { + "args": "0x00000000b24761ad734952f78b5974e810f08a408965f27844772a35bfd6162dfe3eb4f7", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xc625c4ac0ba3ece5886d04958c3fc2d5558a21841c03577fad2d7c46e5b2b2b9", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x80f0fa02000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0xb5ab02c1583387fa7bc3cb7e61daccead6d4d6b9a1294555328d4bc209ed5f8f", + }, + "txIndex": "0x1", + }, + ], + [], + [], + [], + [ + { + "blockNumber": "0xcb42df", + "cellOutput": { + "capacity": "0x5e9f53e00", + "lock": { + "args": "0x00000000fe7e313c6bb99211e222dd1a4ae62a046ef4170d1e74a7252a827b0636ef6965", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xc625c4ac0ba3ece5886d04958c3fc2d5558a21841c03577fad2d7c46e5b2b2b9", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x00e1f505000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0xeec5c357338f622f9bf586532be687f8fc1918566f27b4abb7fa5f9c1891af6b", + }, + "txIndex": "0x2", + }, + ], + [ + { + "blockNumber": "0xcb669c", + "cellOutput": { + "capacity": "0x5e9f53e00", + "lock": { + "args": "0x000000004db3c41e5993ba73c0c916494d3f0e09042f2dcd8d48abd64b13a2ed6a149ffc", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xc625c4ac0ba3ece5886d04958c3fc2d5558a21841c03577fad2d7c46e5b2b2b9", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0xa0860100000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0x2f6b86c4311dc854e779c0bbce110f397a0acc03dfe435aedf832b4f3de1a485", + }, + "txIndex": "0x1", + }, + ], + [], +] +`; + +exports[`RgbppCollector > getRgbppCellsByBatchRequest: should return the batch request for the utxos 1`] = ` +[ + [ + { + "blockNumber": "0xc8ebc1", + "cellOutput": { + "capacity": "0x5e9f52687", + "lock": { + "args": "0x01000000bae5d17d4bc31c3f6556104423ba407a10a67ef546d4edb6cb179e17034e9f98", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0x30d3fbec9ceba691770d57c6d06bdb98cf0f82bef0ca6e87687a118d6ce1e7b7", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x00e1f505000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0x5e0e3bc6429fe8ec6da213f4de31bb40581b36be221458ab1766bf86bcb49e42", + }, + "txIndex": "0x3", + }, + ], + [], + [], + [ + { + "blockNumber": "0xc35b01", + "cellOutput": { + "capacity": "0x5e9f5203e", + "lock": { + "args": "0x0200000029ee57d8d3a4506b2647cea882a497da55f49dd4d71b41b14e28c651baa2050c", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0xc0d45407000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0x4f8f6042b3646e677c871be1629150407b520e48174612d428506995f6055558", + }, + "txIndex": "0x8", + }, + ], + [ + { + "blockNumber": "0xc87015", + "cellOutput": { + "capacity": "0x5e9e620d3", + "lock": { + "args": "0x02000000f42636cfd158d159c959ff931351636adff46b3cef5cd28d953b0fd07526d20b", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x008c8647000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0xe098e5919e496fc6efb601307578cc436df7d554b9a3994f03b85d0ad2e8e7a6", + }, + "txIndex": "0x1", + }, + ], + [], + [], + [ + { + "blockNumber": "0xcc3842", + "cellOutput": { + "capacity": "0xa7a358200", + "lock": { + "args": "0x000000008c8afb798a1637a284f1ef889e053a7f1e7030747f51cb86a31138c28b681aed", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xaf68a7bcf1423b57e7ce8636c28dedb463c6e69f62b1b35ca1ed9abf9a6b3d18", + "codeHash": "0x685a60219309029d01310311dba953d67029170ca4848a4ff638e57002130a0d", + "hashType": "data1", + }, + }, + "data": "0xd40000001000000024000000b0000000100000006170706c69636174696f6e2f6a736f6e880000007b226e616d65223a22556e69636f726e20426f78222c227265736f75726365223a7b2275726c223a2268747470733a2f2f6172736565642e77656233696e6672612e6465762f306b4e437450376169417253596f6c6e424f656466705545493948554b7273323142443772495247735677222c2274797065223a22696d6167652f6a706567227d7d20000000ed3d643329453a418a8902a40c225ca81f405904b4ec9509ff09048240d30a86", + "outPoint": { + "index": "0x0", + "txHash": "0xdd0226408c4c31b2466f7c3d661d4e3e3c8b429631212a525f6668765baadc80", + }, + "txIndex": "0x1", + }, + ], + [ + { + "blockNumber": "0xcb4375", + "cellOutput": { + "capacity": "0x5e9f53e00", + "lock": { + "args": "0x000000009b18c0f40491710e536b9916cb9d8326678b27ad5856cf51f0fdf031dec0f53e", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xc625c4ac0ba3ece5886d04958c3fc2d5558a21841c03577fad2d7c46e5b2b2b9", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x80969800000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0x3aeb2a7f8e00ca32fae9b658da88274f2dcfeff41108ea28b567dc9b79c7dd3c", + }, + "txIndex": "0x3", + }, + ], + [ + { + "blockNumber": "0xc35ba6", + "cellOutput": { + "capacity": "0x5e9f52f1f", + "lock": { + "args": "0x02000000bbd4d25df0dcc16d9e8cdd70872c1ce2a5acc4394a3cc32ab862ade346317d05", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0xa08d7313000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0x71b4f66ac7f657e3b96b5b0694de5fadb61740d2644eabb91090dd9bce93316a", + }, + "txIndex": "0x4", + }, + ], + [ + { + "blockNumber": "0xcb4378", + "cellOutput": { + "capacity": "0x5e9f53e00", + "lock": { + "args": "0x00000000b24761ad734952f78b5974e810f08a408965f27844772a35bfd6162dfe3eb4f7", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xc625c4ac0ba3ece5886d04958c3fc2d5558a21841c03577fad2d7c46e5b2b2b9", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x80f0fa02000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0xb5ab02c1583387fa7bc3cb7e61daccead6d4d6b9a1294555328d4bc209ed5f8f", + }, + "txIndex": "0x1", + }, + ], + [ + { + "blockNumber": "0xcc383d", + "cellOutput": { + "capacity": "0x94a39af00", + "lock": { + "args": "0x00000000906f620ad43ea196a10c077e9238515111cb0b6faa7eb69679e72528a17afafd", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xacb57628e8814a675ac3dfcdcd86b89da85399a82bfceedccb2c8a2200c48c1e", + "codeHash": "0x685a60219309029d01310311dba953d67029170ca4848a4ff638e57002130a0d", + "hashType": "data1", + }, + }, + "data": "0xa100000010000000190000007d00000005000000646f622f30600000007b22626c6f636b5f6e756d626572223a31333038343932382c2263656c6c5f6964223a363132303533383831383036373235383030302c22646e61223a226166323566336565383563383734623030343638316334333162373835626231227d20000000c1097c85aa781d2cd3c017dc911eceab94644cfe2dd714ae7f7bbe4b75accb08", + "outPoint": { + "index": "0x0", + "txHash": "0x3b1a2d2d00a5ef95b45d93cc1d9394a411319f956121d95104b784e8b469f538", + }, + "txIndex": "0x3", + }, + ], + [ + { + "blockNumber": "0xc35ba6", + "cellOutput": { + "capacity": "0x5e9f52f1f", + "lock": { + "args": "0x02000000976e945e25e9645ab5705c0bebe687e75f8b678fc6e0c9b26081b368f51563a4", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x01000000000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0x274865dc9e754ab8fc96cbc7be20093feca0073b91d3157aed2639f6e89ada90", + }, + "txIndex": "0x8", + }, + ], + [ + { + "blockNumber": "0xcc3d9d", + "cellOutput": { + "capacity": "0x5e9f53e00", + "lock": { + "args": "0x01000000a7fd61a66986273e1e8500e276e5ade9e1d66658e73cc1a4123a440ef6f78d36", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0x30d3fbec9ceba691770d57c6d06bdb98cf0f82bef0ca6e87687a118d6ce1e7b7", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x00e1f505000000000000000000000000", + "outPoint": { + "index": "0x1", + "txHash": "0xefcada73aa020bfc4c4dc7192f9a6a6e6152af77d1bb2c2380314b4130751bc4", + }, + "txIndex": "0x6", + }, + ], + [ + { + "blockNumber": "0xcb42df", + "cellOutput": { + "capacity": "0x5e9f53e00", + "lock": { + "args": "0x00000000fe7e313c6bb99211e222dd1a4ae62a046ef4170d1e74a7252a827b0636ef6965", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xc625c4ac0ba3ece5886d04958c3fc2d5558a21841c03577fad2d7c46e5b2b2b9", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x00e1f505000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0xeec5c357338f622f9bf586532be687f8fc1918566f27b4abb7fa5f9c1891af6b", + }, + "txIndex": "0x2", + }, + ], + [ + { + "blockNumber": "0xcb669c", + "cellOutput": { + "capacity": "0x5e9f53e00", + "lock": { + "args": "0x000000004db3c41e5993ba73c0c916494d3f0e09042f2dcd8d48abd64b13a2ed6a149ffc", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xc625c4ac0ba3ece5886d04958c3fc2d5558a21841c03577fad2d7c46e5b2b2b9", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0xa0860100000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0x2f6b86c4311dc854e779c0bbce110f397a0acc03dfe435aedf832b4f3de1a485", + }, + "txIndex": "0x1", + }, + ], + [ + { + "blockNumber": "0xcb7072", + "cellOutput": { + "capacity": "0xa7a358200", + "lock": { + "args": "0x00000000ab39226c7b575b968798ebdb7f72b2ecec3d7cd6d71c38d11f095b8e2a8e61f3", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0x76fd065c31d24a2c8219e7d56942fed3d49ff728697d98a1079edb06187ec91c", + "codeHash": "0x685a60219309029d01310311dba953d67029170ca4848a4ff638e57002130a0d", + "hashType": "data1", + }, + }, + "data": "0xd40000001000000024000000b0000000100000006170706c69636174696f6e2f6a736f6e880000007b226e616d65223a22556e69636f726e20426f78222c227265736f75726365223a7b2275726c223a2268747470733a2f2f6172736565642e77656233696e6672612e6465762f306b4e437450376169417253596f6c6e424f656466705545493948554b7273323142443772495247735677222c2274797065223a22696d6167652f6a706567227d7d20000000ed3d643329453a418a8902a40c225ca81f405904b4ec9509ff09048240d30a86", + "outPoint": { + "index": "0x0", + "txHash": "0xbd1886d03da82d0a012af423044d8f192598d3a7be454397497fd22aba2a784e", + }, + "txIndex": "0x1", + }, + ], +] +`; + +exports[`RgbppCollector > getRgbppCellsByBatchRequest: should return the utxo and the cells 1`] = ` [ { "cells": [ { - "blockNumber": "0x123", + "blockNumber": "0xc8ebc1", + "cellOutput": { + "capacity": "0x5e9f52687", + "lock": { + "args": "0x01000000bae5d17d4bc31c3f6556104423ba407a10a67ef546d4edb6cb179e17034e9f98", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0x30d3fbec9ceba691770d57c6d06bdb98cf0f82bef0ca6e87687a118d6ce1e7b7", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x00e1f505000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0x5e0e3bc6429fe8ec6da213f4de31bb40581b36be221458ab1766bf86bcb49e42", + }, + "txIndex": "0x3", + }, + ], + "utxo": { + "status": { + "block_hash": "000000000000001d4c78f85fd7fda56916f448bb25f4b3b275f1cf6634e17bf8", + "block_height": 2812535, + "block_time": 1715047029, + "confirmed": false, + }, + "txid": "989f4e03179e17cbb6edd446f57ea6107a40ba23441056653f1cc34b7dd1e5ba", + "value": 546, + "vout": 1, + }, + }, + { + "cells": [ + { + "blockNumber": "0xc35b01", + "cellOutput": { + "capacity": "0x5e9f5203e", + "lock": { + "args": "0x0200000029ee57d8d3a4506b2647cea882a497da55f49dd4d71b41b14e28c651baa2050c", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0xc0d45407000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0x4f8f6042b3646e677c871be1629150407b520e48174612d428506995f6055558", + }, + "txIndex": "0x8", + }, + ], + "utxo": { + "status": { + "block_hash": "00000000000000000b871290b8d050dc6b57104deada7f6c26d59d567c7ac94a", + "block_height": 2585022, + "block_time": 1712125215, + "confirmed": true, + }, + "txid": "0c05a2ba51c6284eb1411bd7d49df455da97a482a8ce47266b50a4d3d857ee29", + "value": 546, + "vout": 2, + }, + }, + { + "cells": [ + { + "blockNumber": "0xc87015", + "cellOutput": { + "capacity": "0x5e9e620d3", + "lock": { + "args": "0x02000000f42636cfd158d159c959ff931351636adff46b3cef5cd28d953b0fd07526d20b", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x008c8647000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0xe098e5919e496fc6efb601307578cc436df7d554b9a3994f03b85d0ad2e8e7a6", + }, + "txIndex": "0x1", + }, + ], + "utxo": { + "status": { + "block_hash": "000000000000009de2006782c905136c925bbb4bb89e504e970affe1c20bbfee", + "block_height": 2811244, + "block_time": 1714790623, + "confirmed": true, + }, + "txid": "0bd22675d00f3b958dd25cef3c6bf4df6a63511393ff59c959d158d1cf3626f4", + "value": 546, + "vout": 2, + }, + }, + { + "cells": [ + { + "blockNumber": "0xcc3842", "cellOutput": { - "capacity": "0x123", + "capacity": "0xa7a358200", "lock": { - "args": "0x0000000009b1c4d969cc25cbbde6f73bf2920b62a00916f1148493ef28bfb677f0a94f2c", + "args": "0x000000008c8afb798a1637a284f1ef889e053a7f1e7030747f51cb86a31138c28b681aed", "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", "hashType": "type", }, "type": { - "args": "0x", + "args": "0xaf68a7bcf1423b57e7ce8636c28dedb463c6e69f62b1b35ca1ed9abf9a6b3d18", + "codeHash": "0x685a60219309029d01310311dba953d67029170ca4848a4ff638e57002130a0d", + "hashType": "data1", + }, + }, + "data": "0xd40000001000000024000000b0000000100000006170706c69636174696f6e2f6a736f6e880000007b226e616d65223a22556e69636f726e20426f78222c227265736f75726365223a7b2275726c223a2268747470733a2f2f6172736565642e77656233696e6672612e6465762f306b4e437450376169417253596f6c6e424f656466705545493948554b7273323142443772495247735677222c2274797065223a22696d6167652f6a706567227d7d20000000ed3d643329453a418a8902a40c225ca81f405904b4ec9509ff09048240d30a86", + "outPoint": { + "index": "0x0", + "txHash": "0xdd0226408c4c31b2466f7c3d661d4e3e3c8b429631212a525f6668765baadc80", + }, + "txIndex": "0x1", + }, + ], + "utxo": { + "status": { + "block_hash": "00000000000000074d01a1844db22ada24e70043bac0d05a83aa2234cd5c3de9", + "block_height": 2817185, + "block_time": 1716459057, + "confirmed": true, + }, + "txid": "ed1a688bc23811a386cb517f7430701e7f3a059e88eff184a237168a79fb8a8c", + "value": 546, + "vout": 0, + }, + }, + { + "cells": [ + { + "blockNumber": "0xcb4375", + "cellOutput": { + "capacity": "0x5e9f53e00", + "lock": { + "args": "0x000000009b18c0f40491710e536b9916cb9d8326678b27ad5856cf51f0fdf031dec0f53e", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xc625c4ac0ba3ece5886d04958c3fc2d5558a21841c03577fad2d7c46e5b2b2b9", "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", "hashType": "type", }, }, - "data": "0x", + "data": "0x80969800000000000000000000000000", "outPoint": { "index": "0x0", - "txHash": "0x", + "txHash": "0x3aeb2a7f8e00ca32fae9b658da88274f2dcfeff41108ea28b567dc9b79c7dd3c", }, - "txIndex": "0x0", + "txIndex": "0x3", }, ], "utxo": { "status": { + "block_hash": "0000000000000007270b0f8be9b3b61c49a09dd7af0bb0f800aef8dbbf594e35", + "block_height": 2816698, + "block_time": 1716276487, "confirmed": true, }, - "txid": "0x2c4fa9f077b6bf28ef938414f11609a0620b92f23bf7e6bdcb25cc69d9c4b109", - "value": 100000000, + "txid": "3ef5c0de31f0fdf051cf5658ad278b6726839dcb16996b530e719104f4c0189b", + "value": 546, "vout": 0, }, }, { "cells": [ { - "blockNumber": "0x456", + "blockNumber": "0xc35ba6", "cellOutput": { - "capacity": "0x123", + "capacity": "0x5e9f52f1f", "lock": { - "args": "0x0100000009b1c4d969cc25cbbde6f73bf2920b62a00916f1148493ef28bfb677f0a94f2c", + "args": "0x02000000bbd4d25df0dcc16d9e8cdd70872c1ce2a5acc4394a3cc32ab862ade346317d05", "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", "hashType": "type", }, "type": { - "args": "0x", + "args": "0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b", "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", "hashType": "type", }, }, - "data": "0x", + "data": "0xa08d7313000000000000000000000000", "outPoint": { "index": "0x0", - "txHash": "0x", + "txHash": "0x71b4f66ac7f657e3b96b5b0694de5fadb61740d2644eabb91090dd9bce93316a", }, - "txIndex": "0x0", + "txIndex": "0x4", }, ], "utxo": { "status": { + "block_hash": "0000000000000365f0619dc58091519f4e7bdddc44b3b10f0a4ccfa668da1a31", + "block_height": 2585023, + "block_time": 1712126418, "confirmed": true, }, - "txid": "0x2c4fa9f077b6bf28ef938414f11609a0620b92f23bf7e6bdcb25cc69d9c4b109", - "value": 200000000, - "vout": 1, + "txid": "057d3146e3ad62b82ac33c4a39c4aca5e21c2c8770dd8c9e6dc1dcf05dd2d4bb", + "value": 546, + "vout": 2, }, }, -] -`; - -exports[`RgbppCollector > getRgbppCellsBatchRequest: should be filtered by typeScript 1`] = ` -[ - [ - "getCells", - { - "filter": { - "script": { - "args": "0x", - "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", - "hashType": "data", + { + "cells": [ + { + "blockNumber": "0xcb4378", + "cellOutput": { + "capacity": "0x5e9f53e00", + "lock": { + "args": "0x00000000b24761ad734952f78b5974e810f08a408965f27844772a35bfd6162dfe3eb4f7", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xc625c4ac0ba3ece5886d04958c3fc2d5558a21841c03577fad2d7c46e5b2b2b9", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x80f0fa02000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0xb5ab02c1583387fa7bc3cb7e61daccead6d4d6b9a1294555328d4bc209ed5f8f", }, + "txIndex": "0x1", }, - "script": { - "args": "0x0000000009b1c4d969cc25cbbde6f73bf2920b62a00916f1148493ef28bfb677f0a94f2c", - "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", - "hashType": "type", + ], + "utxo": { + "status": { + "block_hash": "0000000000000007270b0f8be9b3b61c49a09dd7af0bb0f800aef8dbbf594e35", + "block_height": 2816698, + "block_time": 1716276487, + "confirmed": true, }, - "scriptType": "lock", + "txid": "f7b43efe2d16d6bf352a774478f26589408af010e874598bf7524973ad6147b2", + "value": 546, + "vout": 0, }, - "desc", - "0x64", - ], - [ - "getCells", - { - "filter": { - "script": { - "args": "0x", - "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", - "hashType": "data", + }, + { + "cells": [ + { + "blockNumber": "0xcc383d", + "cellOutput": { + "capacity": "0x94a39af00", + "lock": { + "args": "0x00000000906f620ad43ea196a10c077e9238515111cb0b6faa7eb69679e72528a17afafd", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xacb57628e8814a675ac3dfcdcd86b89da85399a82bfceedccb2c8a2200c48c1e", + "codeHash": "0x685a60219309029d01310311dba953d67029170ca4848a4ff638e57002130a0d", + "hashType": "data1", + }, }, + "data": "0xa100000010000000190000007d00000005000000646f622f30600000007b22626c6f636b5f6e756d626572223a31333038343932382c2263656c6c5f6964223a363132303533383831383036373235383030302c22646e61223a226166323566336565383563383734623030343638316334333162373835626231227d20000000c1097c85aa781d2cd3c017dc911eceab94644cfe2dd714ae7f7bbe4b75accb08", + "outPoint": { + "index": "0x0", + "txHash": "0x3b1a2d2d00a5ef95b45d93cc1d9394a411319f956121d95104b784e8b469f538", + }, + "txIndex": "0x3", }, - "script": { - "args": "0x0100000009b1c4d969cc25cbbde6f73bf2920b62a00916f1148493ef28bfb677f0a94f2c", - "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", - "hashType": "type", + ], + "utxo": { + "status": { + "block_hash": "0000000000000002d2dc7f2a5ff816564d746298563451852b9d33a5452bd206", + "block_height": 2816987, + "block_time": 1716365229, + "confirmed": true, }, - "scriptType": "lock", + "txid": "fdfa7aa12825e77996b67eaa6f0bcb11515138927e070ca196a13ed40a626f90", + "value": 546, + "vout": 0, }, - "desc", - "0x64", - ], -] -`; - -exports[`RgbppCollector > getRgbppCellsBatchRequest: should return the batch request for the utxos 1`] = ` -[ - [ - "getCells", - { - "script": { - "args": "0x0000000009b1c4d969cc25cbbde6f73bf2920b62a00916f1148493ef28bfb677f0a94f2c", - "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", - "hashType": "type", + }, + { + "cells": [ + { + "blockNumber": "0xc35ba6", + "cellOutput": { + "capacity": "0x5e9f52f1f", + "lock": { + "args": "0x02000000976e945e25e9645ab5705c0bebe687e75f8b678fc6e0c9b26081b368f51563a4", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x01000000000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0x274865dc9e754ab8fc96cbc7be20093feca0073b91d3157aed2639f6e89ada90", + }, + "txIndex": "0x8", + }, + ], + "utxo": { + "status": { + "block_hash": "0000000000000365f0619dc58091519f4e7bdddc44b3b10f0a4ccfa668da1a31", + "block_height": 2585023, + "block_time": 1712126418, + "confirmed": true, }, - "scriptType": "lock", + "txid": "a46315f568b38160b2c9e0c68f678b5fe787e6eb0b5c70b55a64e9255e946e97", + "value": 546, + "vout": 2, }, - "desc", - "0x64", - ], - [ - "getCells", - { - "script": { - "args": "0x0100000009b1c4d969cc25cbbde6f73bf2920b62a00916f1148493ef28bfb677f0a94f2c", - "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", - "hashType": "type", + }, + { + "cells": [ + { + "blockNumber": "0xcc3d9d", + "cellOutput": { + "capacity": "0x5e9f53e00", + "lock": { + "args": "0x01000000a7fd61a66986273e1e8500e276e5ade9e1d66658e73cc1a4123a440ef6f78d36", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0x30d3fbec9ceba691770d57c6d06bdb98cf0f82bef0ca6e87687a118d6ce1e7b7", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x00e1f505000000000000000000000000", + "outPoint": { + "index": "0x1", + "txHash": "0xefcada73aa020bfc4c4dc7192f9a6a6e6152af77d1bb2c2380314b4130751bc4", + }, + "txIndex": "0x6", }, - "scriptType": "lock", + ], + "utxo": { + "status": { + "block_hash": "000000000000000136b682e35e2ccce1a8b2d408f81607237ddf27f3acdb92ba", + "block_height": 2818010, + "block_time": 1716787908, + "confirmed": true, + }, + "txid": "368df7f60e443a12a4c13ce75866d6e1e9ade576e200851e3e278669a661fda7", + "value": 546, + "vout": 1, }, - "desc", - "0x64", - ], -] -`; - -exports[`RgbppCollector > getRgbppCellsByBatchRequest: should be filtered by typeScript 1`] = ` -[ - [], - [], -] -`; - -exports[`RgbppCollector > getRgbppCellsByBatchRequest: should return the batch request for the utxos 1`] = ` -[ - [], - [], + }, + { + "cells": [ + { + "blockNumber": "0xcb42df", + "cellOutput": { + "capacity": "0x5e9f53e00", + "lock": { + "args": "0x00000000fe7e313c6bb99211e222dd1a4ae62a046ef4170d1e74a7252a827b0636ef6965", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xc625c4ac0ba3ece5886d04958c3fc2d5558a21841c03577fad2d7c46e5b2b2b9", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0x00e1f505000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0xeec5c357338f622f9bf586532be687f8fc1918566f27b4abb7fa5f9c1891af6b", + }, + "txIndex": "0x2", + }, + ], + "utxo": { + "status": { + "block_hash": "0000000000000001f67d59ba0b956a30a68bed4154c02c29a34b4ff84e54eb26", + "block_height": 2816662, + "block_time": 1716265235, + "confirmed": true, + }, + "txid": "6569ef36067b822a25a7741e0d17f46e042ae64a1add22e21192b96b3c317efe", + "value": 546, + "vout": 0, + }, + }, + { + "cells": [ + { + "blockNumber": "0xcb669c", + "cellOutput": { + "capacity": "0x5e9f53e00", + "lock": { + "args": "0x000000004db3c41e5993ba73c0c916494d3f0e09042f2dcd8d48abd64b13a2ed6a149ffc", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0xc625c4ac0ba3ece5886d04958c3fc2d5558a21841c03577fad2d7c46e5b2b2b9", + "codeHash": "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + "hashType": "type", + }, + }, + "data": "0xa0860100000000000000000000000000", + "outPoint": { + "index": "0x0", + "txHash": "0x2f6b86c4311dc854e779c0bbce110f397a0acc03dfe435aedf832b4f3de1a485", + }, + "txIndex": "0x1", + }, + ], + "utxo": { + "status": { + "block_hash": "000000000000000a2d71867394388670e82b65ae1588306d06a2e6c070dec47e", + "block_height": 2816711, + "block_time": 1716280561, + "confirmed": true, + }, + "txid": "fc9f146aeda2134bd6ab488dcd2d2f04090e3f4d4916c9c073ba93591ec4b34d", + "value": 546, + "vout": 0, + }, + }, + { + "cells": [ + { + "blockNumber": "0xcb7072", + "cellOutput": { + "capacity": "0xa7a358200", + "lock": { + "args": "0x00000000ab39226c7b575b968798ebdb7f72b2ecec3d7cd6d71c38d11f095b8e2a8e61f3", + "codeHash": "0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248", + "hashType": "type", + }, + "type": { + "args": "0x76fd065c31d24a2c8219e7d56942fed3d49ff728697d98a1079edb06187ec91c", + "codeHash": "0x685a60219309029d01310311dba953d67029170ca4848a4ff638e57002130a0d", + "hashType": "data1", + }, + }, + "data": "0xd40000001000000024000000b0000000100000006170706c69636174696f6e2f6a736f6e880000007b226e616d65223a22556e69636f726e20426f78222c227265736f75726365223a7b2275726c223a2268747470733a2f2f6172736565642e77656233696e6672612e6465762f306b4e437450376169417253596f6c6e424f656466705545493948554b7273323142443772495247735677222c2274797065223a22696d6167652f6a706567227d7d20000000ed3d643329453a418a8902a40c225ca81f405904b4ec9509ff09048240d30a86", + "outPoint": { + "index": "0x0", + "txHash": "0xbd1886d03da82d0a012af423044d8f192598d3a7be454397497fd22aba2a784e", + }, + "txIndex": "0x1", + }, + ], + "utxo": { + "status": { + "block_hash": "000000000000000838d3bf989d702597827cd9830b8bedeaba49a5f2621053fa", + "block_height": 2816899, + "block_time": 1716348699, + "confirmed": true, + }, + "txid": "f3618e2a8e5b091fd1381cd7d67c3dececb2727fdbeb9887965b577b6c2239ab", + "value": 546, + "vout": 0, + }, + }, ] `; - -exports[`RgbppCollector > getRgbppCellsByBatchRequest: should return the utxo and the cells 1`] = `[]`; diff --git a/test/services/rgbpp.test.ts b/test/services/rgbpp.test.ts index b1d187d1..a57222ae 100644 --- a/test/services/rgbpp.test.ts +++ b/test/services/rgbpp.test.ts @@ -1,16 +1,9 @@ import container from '../../src/container'; import { describe, test, beforeEach, afterEach, vi, expect } from 'vitest'; import RgbppCollector from '../../src/services/rgbpp'; -import { UTXO } from '../../src/services/bitcoin/schema'; -import { Script } from '@ckb-lumos/base'; -// import { IndexerCell } from '@ckb-lumos/ckb-indexer/lib/type'; -// import { buildRgbppLockArgs, genRgbppLockScript } from '@rgbpp-sdk/ckb'; - -// const xudtTypeScript = { -// codeHash: '0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb', -// hashType: 'type', -// args: '0x', -// }; +import { Cell, Script } from '@ckb-lumos/base'; +import mockUtxos from '../__fixtures__/utxo.mock.json'; +import mockRgbppUtxoPairs from '../__fixtures__/rgbpp-utxo-pairs.mock.json'; describe('RgbppCollector', () => { let rgbppCollector: RgbppCollector; @@ -25,67 +18,29 @@ describe('RgbppCollector', () => { }); test('getRgbppCellsByBatchRequest: should return the batch request for the utxos', async () => { - const utxos: UTXO[] = [ - { - txid: '0x2c4fa9f077b6bf28ef938414f11609a0620b92f23bf7e6bdcb25cc69d9c4b109', - vout: 0, - value: 100000000, - status: { confirmed: true }, - }, - { - txid: '0x2c4fa9f077b6bf28ef938414f11609a0620b92f23bf7e6bdcb25cc69d9c4b109', - vout: 1, - value: 200000000, - status: { confirmed: true }, - }, - ]; - - const cells = await rgbppCollector.getRgbppCellsByBatchRequest(utxos); + const cells = await rgbppCollector.getRgbppCellsByBatchRequest(mockUtxos); expect(cells).toMatchSnapshot(); }); test('getRgbppCellsByBatchRequest: should be filtered by typeScript', async () => { - const utxos: UTXO[] = [ - { - txid: '0x2c4fa9f077b6bf28ef938414f11609a0620b92f23bf7e6bdcb25cc69d9c4b109', - vout: 0, - value: 100000000, - status: { confirmed: true }, - }, - { - txid: '0x2c4fa9f077b6bf28ef938414f11609a0620b92f23bf7e6bdcb25cc69d9c4b109', - vout: 1, - value: 200000000, - status: { confirmed: true }, - }, - ]; - const typeScript: Script = { codeHash: '0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb', - hashType: 'data', - args: '0x', + hashType: 'type', + args: '0xc625c4ac0ba3ece5886d04958c3fc2d5558a21841c03577fad2d7c46e5b2b2b9', }; - const cells = await rgbppCollector.getRgbppCellsByBatchRequest(utxos, typeScript); + const cells = await rgbppCollector.getRgbppCellsByBatchRequest(mockUtxos, typeScript); expect(cells).toMatchSnapshot(); }); test('getRgbppCellsByBatchRequest: should return the utxo and the cells', async () => { - const utxos: UTXO[] = [ - { - txid: '0x2c4fa9f077b6bf28ef938414f11609a0620b92f23bf7e6bdcb25cc69d9c4b109', - vout: 0, - value: 100000000, - status: { confirmed: true }, - }, - { - txid: '0x2c4fa9f077b6bf28ef938414f11609a0620b92f23bf7e6bdcb25cc69d9c4b109', - vout: 1, - value: 200000000, - status: { confirmed: true }, - }, - ]; - const rgbppUtxoCellsPairs = await rgbppCollector.collectRgbppUtxoCellsPairs(utxos); + const rgbppUtxoCellsPairs = await rgbppCollector.collectRgbppUtxoCellsPairs(mockUtxos); expect(rgbppUtxoCellsPairs).toMatchSnapshot(); }); + + test('getRgbppBalanceByCells: should return the rgbpp balance by cells', async () => { + const cells = mockRgbppUtxoPairs.map((pair) => pair.cells).flat(); + const balance = await rgbppCollector.getRgbppBalanceByCells(cells as Cell[]); + expect(balance).toMatchSnapshot(); + }); }); From 30cdc139249819db7626f4ff97819cb3705e2ec5 Mon Sep 17 00:00:00 2001 From: ahonn Date: Mon, 3 Jun 2024 16:29:15 +1000 Subject: [PATCH 08/11] refactor: use isScriptEqual from rgbpp/ckb instead of serializeScript --- src/routes/rgbpp/address.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/routes/rgbpp/address.ts b/src/routes/rgbpp/address.ts index 365de331..35964bbc 100644 --- a/src/routes/rgbpp/address.ts +++ b/src/routes/rgbpp/address.ts @@ -5,9 +5,8 @@ import { ZodTypeProvider } from 'fastify-type-provider-zod'; import { Cell, Script, XUDTBalance } from './types'; import { blockchain } from '@ckb-lumos/base'; import z from 'zod'; -import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; import { Env } from '../../env'; -import { getXudtTypeScript, isTypeAssetSupported } from '@rgbpp-sdk/ckb'; +import { getXudtTypeScript, isScriptEqual, isTypeAssetSupported } from '@rgbpp-sdk/ckb'; import { BI } from '@ckb-lumos/lumos'; import { UTXO } from '../../services/bitcoin/schema'; @@ -76,9 +75,9 @@ const addressRoutes: FastifyPluginCallback, Server, ZodType // if typeScript.args is empty, only compare codeHash and hashType if (!typeScript.args) { const script = { ...cell.cellOutput.type, args: '' }; - return serializeScript(script) === serializeScript(typeScript); + return isScriptEqual(script, typeScript); } - return serializeScript(cell.cellOutput.type) === serializeScript(typeScript); + return isScriptEqual(cell.cellOutput.type, typeScript); }); } @@ -166,7 +165,7 @@ const addressRoutes: FastifyPluginCallback, Server, ZodType throw fastify.httpErrors.badRequest('Unsupported type asset'); } const scripts = fastify.ckb.getScripts(); - if (serializeScript({ ...typeScript, args: '' }) !== serializeScript(scripts.XUDT)) { + if (isScriptEqual({ ...typeScript, args: '' }, scripts.XUDT)) { throw fastify.httpErrors.badRequest('Unsupported type asset'); } From a0aeca7f49e859ed598744ec0e6b23a6c5be84f0 Mon Sep 17 00:00:00 2001 From: ahonn Date: Mon, 3 Jun 2024 16:30:06 +1000 Subject: [PATCH 09/11] refactor: delete unnecessary for await --- src/services/rgbpp.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/rgbpp.ts b/src/services/rgbpp.ts index 2cba34b0..7b26b035 100644 --- a/src/services/rgbpp.ts +++ b/src/services/rgbpp.ts @@ -116,7 +116,7 @@ export default class RgbppCollector extends BaseQueueWorker = {}; - for await (const cell of cells) { + for (const cell of cells) { const type = cell.cellOutput.type!; const typeHash = computeScriptHash(type); const infoCellData = await this.cradle.ckb.getInfoCellData(type); From f2b3241b968b641c99398a9a2d4d17ef97967db8 Mon Sep 17 00:00:00 2001 From: Yuexun Date: Mon, 3 Jun 2024 16:32:09 +1000 Subject: [PATCH 10/11] fix: add missing failed state condition to avoid incorrect calc Co-authored-by: Flouse <1297478+Flouse@users.noreply.github.com> --- src/services/transaction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/transaction.ts b/src/services/transaction.ts index a3b0140d..9628ce96 100644 --- a/src/services/transaction.ts +++ b/src/services/transaction.ts @@ -594,7 +594,7 @@ export default class TransactionProcessor // get ckb output cells from the uncompleted job only const state = await job.getState(); - if (state === 'completed') { + if (state === 'completed' || state === 'failed') { return []; } From 8b1ed2f0f64ccc3c784ee82cef232cb27b171be9 Mon Sep 17 00:00:00 2001 From: ahonn Date: Mon, 3 Jun 2024 16:50:44 +1000 Subject: [PATCH 11/11] fix: read xudt data first 32 bytes as amount --- src/routes/rgbpp/address.ts | 2 +- src/services/rgbpp.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/routes/rgbpp/address.ts b/src/routes/rgbpp/address.ts index 35964bbc..07f1ee8e 100644 --- a/src/routes/rgbpp/address.ts +++ b/src/routes/rgbpp/address.ts @@ -165,7 +165,7 @@ const addressRoutes: FastifyPluginCallback, Server, ZodType throw fastify.httpErrors.badRequest('Unsupported type asset'); } const scripts = fastify.ckb.getScripts(); - if (isScriptEqual({ ...typeScript, args: '' }, scripts.XUDT)) { + if (!isScriptEqual({ ...typeScript, args: '' }, scripts.XUDT)) { throw fastify.httpErrors.badRequest('Unsupported type asset'); } diff --git a/src/services/rgbpp.ts b/src/services/rgbpp.ts index 7b26b035..9a8af0bf 100644 --- a/src/services/rgbpp.ts +++ b/src/services/rgbpp.ts @@ -12,6 +12,7 @@ import BaseQueueWorker from './base/queue-worker'; import DataCache from './base/data-cache'; import { groupBy } from 'lodash'; import { computeScriptHash } from '@ckb-lumos/lumos/utils'; +import { remove0x } from '@rgbpp-sdk/btc'; type GetCellsParams = Parameters; type SearchKey = GetCellsParams[0]; @@ -120,7 +121,8 @@ export default class RgbppCollector extends BaseQueueWorker