From cb25b924b4e46687a11ae64a0d993f98024f314e Mon Sep 17 00:00:00 2001 From: Shook <44739165+ShookLyngs@users.noreply.github.com> Date: Mon, 26 Aug 2024 16:43:39 +0800 Subject: [PATCH] refactor: use IS_MAINNET/TESTNET_TYPE constants and related utils in code, and fix minor typos (#211) --- src/routes/rgbpp/address.ts | 28 ++++++---------- src/routes/rgbpp/assets.ts | 11 +++---- src/services/bitcoin/index.ts | 4 +-- src/services/ckb.ts | 15 ++++----- src/services/paymaster.ts | 9 +++--- src/services/rgbpp.ts | 2 +- src/services/transaction.ts | 61 ++++++++--------------------------- src/services/unlocker.ts | 31 +++++++----------- 8 files changed, 53 insertions(+), 108 deletions(-) diff --git a/src/routes/rgbpp/address.ts b/src/routes/rgbpp/address.ts index 50431899..e6d46aba 100644 --- a/src/routes/rgbpp/address.ts +++ b/src/routes/rgbpp/address.ts @@ -5,13 +5,7 @@ import { ZodTypeProvider } from 'fastify-type-provider-zod'; import { CKBTransaction, Cell, IsomorphicTransaction, Script, XUDTBalance } from './types'; import z from 'zod'; import { Env } from '../../env'; -import { - isScriptEqual, - buildPreLockArgs, - getRgbppLockScript, - getXudtTypeScript, - isTypeAssetSupported, -} from '@rgbpp-sdk/ckb'; +import { isScriptEqual, buildPreLockArgs, getXudtTypeScript, isTypeAssetSupported } from '@rgbpp-sdk/ckb'; import { groupBy, uniq } from 'lodash'; import { BI } from '@ckb-lumos/lumos'; import { UTXO } from '../../services/bitcoin/schema'; @@ -20,8 +14,9 @@ import { TransactionWithStatus } from '../../services/ckb'; import { computeScriptHash } from '@ckb-lumos/lumos/utils'; import { filterCellsByTypeScript, getTypeScript } from '../../utils/typescript'; import { unpackRgbppLockArgs } from '@rgbpp-sdk/btc/lib/ckb/molecule'; -import { TestnetTypeMap } from '../../constants'; import { remove0x } from '@rgbpp-sdk/btc'; +import { isRgbppLock } from '../../utils/lockscript'; +import { IS_MAINNET } from '../../constants'; const addressRoutes: FastifyPluginCallback, Server, ZodTypeProvider> = (fastify, _, done) => { const env: Env = fastify.container.resolve('env'); @@ -37,7 +32,7 @@ const addressRoutes: FastifyPluginCallback, Server, ZodType /** * Get UTXOs by btc address */ - async function getUxtos(btc_address: string, no_cache?: string) { + async function getUtxos(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); @@ -65,12 +60,7 @@ const addressRoutes: FastifyPluginCallback, Server, ZodType * Filter RgbppLock cells by cells */ function getRgbppLockCellsByCells(cells: Cell[]): Cell[] { - const rgbppLockScript = getRgbppLockScript(env.NETWORK === 'mainnet', TestnetTypeMap[env.NETWORK]); - return cells.filter( - (cell) => - rgbppLockScript.codeHash === cell.cellOutput.lock.codeHash && - rgbppLockScript.hashType === cell.cellOutput.lock.hashType, - ); + return cells.filter((cell) => isRgbppLock(cell.cellOutput.lock)); } fastify.get( @@ -107,7 +97,7 @@ 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 utxos = await getUtxos(btc_address, no_cache); const cells = await getRgbppAssetsCells(btc_address, utxos, no_cache); const typeScript = getTypeScript(request.query.type_script); const assetCells = typeScript ? filterCellsByTypeScript(cells, typeScript) : cells; @@ -146,7 +136,7 @@ const addressRoutes: FastifyPluginCallback, Server, ZodType - as a hex string: '0x...' (You can pack by @ckb-lumos/codec blockchain.Script.pack({ "codeHash": "0x...", ... })) `, ) - .default(getXudtTypeScript(env.NETWORK === 'mainnet')), + .default(getXudtTypeScript(IS_MAINNET)), no_cache: z .enum(['true', 'false']) .default('false') @@ -165,7 +155,7 @@ const addressRoutes: FastifyPluginCallback, Server, ZodType const { no_cache } = request.query; const typeScript = getTypeScript(request.query.type_script); - if (!typeScript || !isTypeAssetSupported(typeScript, env.NETWORK === 'mainnet')) { + if (!typeScript || !isTypeAssetSupported(typeScript, IS_MAINNET)) { throw fastify.httpErrors.badRequest('Unsupported type asset'); } const scripts = fastify.ckb.getScripts(); @@ -174,7 +164,7 @@ const addressRoutes: FastifyPluginCallback, Server, ZodType } const xudtBalances: Record = {}; - const utxos = await getUxtos(btc_address, no_cache); + const utxos = await getUtxos(btc_address, no_cache); // Find confirmed RgbppLock XUDT assets const confirmedUtxos = utxos.filter((utxo) => utxo.status.confirmed); diff --git a/src/routes/rgbpp/assets.ts b/src/routes/rgbpp/assets.ts index b949cfb3..c4106aba 100644 --- a/src/routes/rgbpp/assets.ts +++ b/src/routes/rgbpp/assets.ts @@ -5,15 +5,13 @@ import z from 'zod'; import { Cell, Script, SporeTypeInfo, XUDTTypeInfo } from './types'; import { UTXO } from '../../services/bitcoin/schema'; import { getTypeScript } from '../../utils/typescript'; -import { Env } from '../../env'; import { IndexerCell, isSporeTypeSupported, isUDTTypeSupported } from '@rgbpp-sdk/ckb'; import { computeScriptHash } from '@ckb-lumos/lumos/utils'; import { getSporeConfig, unpackToRawClusterData, unpackToRawSporeData } from '../../utils/spore'; import { SearchKey } from '../../services/rgbpp'; +import { IS_MAINNET } from '../../constants'; const assetsRoute: FastifyPluginCallback, Server, ZodTypeProvider> = (fastify, _, done) => { - const env: Env = fastify.container.resolve('env'); - fastify.get( '/:btc_txid', { @@ -142,12 +140,11 @@ const assetsRoute: FastifyPluginCallback, Server, ZodTypePr }, }, async (request) => { - const isMainnet = env.NETWORK === 'mainnet'; const typeScript = getTypeScript(request.query.type_script); if (!typeScript) { return null; } - if (isUDTTypeSupported(typeScript, isMainnet)) { + if (isUDTTypeSupported(typeScript, IS_MAINNET)) { const infoCell = await fastify.ckb.getInfoCellData(typeScript); const typeHash = computeScriptHash(typeScript); if (!infoCell) { @@ -160,7 +157,7 @@ const assetsRoute: FastifyPluginCallback, Server, ZodTypePr ...infoCell, }; } - if (isSporeTypeSupported(typeScript, isMainnet)) { + if (isSporeTypeSupported(typeScript, IS_MAINNET)) { const searchKey: SearchKey = { script: typeScript, scriptType: 'type', @@ -173,7 +170,7 @@ const assetsRoute: FastifyPluginCallback, Server, ZodTypePr contentType: sporeData.contentType, }; if (sporeData.clusterId) { - const sporeConfig = getSporeConfig(isMainnet); + const sporeConfig = getSporeConfig(IS_MAINNET); const batchRequest = fastify.ckb.rpc.createBatchRequest( sporeConfig.scripts.Cluster.versions.map((version) => { const clusterScript = { diff --git a/src/services/bitcoin/index.ts b/src/services/bitcoin/index.ts index 04a2676e..4ee0c326 100644 --- a/src/services/bitcoin/index.ts +++ b/src/services/bitcoin/index.ts @@ -6,7 +6,7 @@ import { Cradle } from '../../container'; import { IBitcoinBroadcastBackuper, IBitcoinDataProvider } from './interface'; import { MempoolClient } from './mempool'; import { ElectrsClient } from './electrs'; -import { NetworkType } from '../../constants'; +import { IS_MAINNET, NetworkType } from '../../constants'; import { ChainInfo } from './schema'; // https://github.com/mempool/electrs/blob/d4f788fc3d7a2b4eca4c5629270e46baba7d0f19/src/errors.rs#L6 @@ -169,7 +169,7 @@ export default class BitcoinClient implements IBitcoinClient { const { difficulty, mediantime } = tip; return { - chain: this.cradle.env.NETWORK === 'mainnet' ? 'main' : 'test', + chain: IS_MAINNET ? 'main' : 'test', blocks: tip.height, bestblockhash: hash, difficulty, diff --git a/src/services/ckb.ts b/src/services/ckb.ts index 5927bf17..ee7c51fb 100644 --- a/src/services/ckb.ts +++ b/src/services/ckb.ts @@ -24,6 +24,7 @@ import DataCache from './base/data-cache'; import { scriptToHash } from '@nervosnetwork/ckb-sdk-utils'; import { Cell } from '../routes/rgbpp/types'; import { uniq } from 'lodash'; +import { IS_MAINNET } from '../constants'; export type TransactionWithStatus = Awaited>; @@ -164,11 +165,10 @@ export default class CKBClient { * Get the ckb script configs */ public getScripts() { - const isMainnet = this.cradle.env.NETWORK === 'mainnet'; - const xudtTypeScript = getXudtTypeScript(isMainnet); - const sporeTypeScript = getSporeTypeScript(isMainnet); - const uniqueCellTypeScript = getUniqueTypeScript(isMainnet); - const inscriptionTypeScript = getInscriptionInfoTypeScript(isMainnet); + const xudtTypeScript = getXudtTypeScript(IS_MAINNET); + const sporeTypeScript = getSporeTypeScript(IS_MAINNET); + const uniqueCellTypeScript = getUniqueTypeScript(IS_MAINNET); + const inscriptionTypeScript = getInscriptionInfoTypeScript(IS_MAINNET); return { XUDT: xudtTypeScript, SPORE: sporeTypeScript, @@ -297,12 +297,11 @@ export default class CKBClient { 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) => { - return cell.type && isUniqueCellTypeScript(cell.type, isMainnet); + return cell.type && isUniqueCellTypeScript(cell.type, IS_MAINNET); }); if (uniqueCellIndex !== -1) { const infoCellData = this.getUniqueCellData(tx, uniqueCellIndex, script); @@ -313,7 +312,7 @@ export default class CKBClient { } // check if the inscription cell is the info cell of the xudt type const inscriptionCellIndex = tx.transaction.outputs.findIndex((cell) => { - return cell.type && isInscriptionInfoTypeScript(cell.type, isMainnet); + return cell.type && isInscriptionInfoTypeScript(cell.type, IS_MAINNET); }); if (inscriptionCellIndex !== -1) { const infoCellData = this.getInscriptionInfoCellData(tx, inscriptionCellIndex, script); diff --git a/src/services/paymaster.ts b/src/services/paymaster.ts index 2e7754d8..ab3de174 100644 --- a/src/services/paymaster.ts +++ b/src/services/paymaster.ts @@ -5,6 +5,7 @@ import { AppendPaymasterCellAndSignTxParams, IndexerCell, appendPaymasterCellAnd import { hd, config, BI } from '@ckb-lumos/lumos'; import * as Sentry from '@sentry/node'; import { Transaction } from '../routes/bitcoin/types'; +import { IS_MAINNET } from '../constants'; interface IPaymaster { getNextCell(token: string): Promise; @@ -60,8 +61,7 @@ export default class Paymaster implements IPaymaster { private get lockScript() { const args = hd.key.privateKeyToBlake160(this.ckbPrivateKey); - const scripts = - this.cradle.env.NETWORK === 'mainnet' ? config.predefined.LINA.SCRIPTS : config.predefined.AGGRON4.SCRIPTS; + const scripts = IS_MAINNET ? config.MAINNET.SCRIPTS : config.TESTNET.SCRIPTS; const template = scripts['SECP256K1_BLAKE160']!; const lockScript = { codeHash: template.CODE_HASH, @@ -123,8 +123,7 @@ export default class Paymaster implements IPaymaster { * The paymaster CKB address to pay the time cells spent tx fee */ public get ckbAddress() { - const isMainnet = this.cradle.env.NETWORK === 'mainnet'; - const lumosConfig = isMainnet ? config.predefined.LINA : config.predefined.AGGRON4; + const lumosConfig = IS_MAINNET ? config.MAINNET : config.TESTNET; const args = hd.key.privateKeyToBlake160(this.ckbPrivateKey); const template = lumosConfig.SCRIPTS['SECP256K1_BLAKE160']; const lockScript = { @@ -296,7 +295,7 @@ export default class Paymaster implements IPaymaster { sumInputsCapacity, paymasterCell, secp256k1PrivateKey: this.ckbPrivateKey, - isMainnet: this.cradle.env.NETWORK === 'mainnet', + isMainnet: IS_MAINNET, }); this.cradle.logger.info(`[Paymaster] Signed transaction: ${JSON.stringify(signedTx)}`); return signedTx; diff --git a/src/services/rgbpp.ts b/src/services/rgbpp.ts index 3bf6aacb..f0e575cf 100644 --- a/src/services/rgbpp.ts +++ b/src/services/rgbpp.ts @@ -64,7 +64,7 @@ class RgbppCollectorError extends Error { * will be recollected when the utxos are updated or new collect job is enqueued. */ export default class RgbppCollector extends BaseQueueWorker { - private readonly limit: pLimit.Limit; + private limit: pLimit.Limit; private dataCache: DataCache; constructor(private cradle: Cradle) { diff --git a/src/services/transaction.ts b/src/services/transaction.ts index ba5562bf..7d44e0bd 100644 --- a/src/services/transaction.ts +++ b/src/services/transaction.ts @@ -5,8 +5,6 @@ import { RGBPP_TX_ID_PLACEHOLDER, appendCkbTxWitnesses, generateSporeTransferCoBuild, - getBtcTimeLockScript, - getRgbppLockScript, getSecp256k1CellDep, getSporeTypeDep, isClusterSporeTypeSupported, @@ -37,8 +35,9 @@ import { BitcoinClientAPIError } from './bitcoin'; import { HttpStatusCode } from 'axios'; import BaseQueueWorker from './base/queue-worker'; import { Env } from '../env'; -import { TestnetTypeMap } from '../constants'; import { getCommitmentFromBtcTx } from '../utils/commitment'; +import { isBtcTimeLock, isRgbppLock } from '../utils/lockscript'; +import { IS_MAINNET } from '../constants'; export interface ITransactionRequest { txid: string; @@ -123,30 +122,6 @@ export default class TransactionProcessor }; } - private get isMainnet() { - return this.cradle.env.NETWORK === 'mainnet'; - } - - private get testnetType() { - return TestnetTypeMap[this.cradle.env.NETWORK]; - } - - private get rgbppLockScript() { - return getRgbppLockScript(this.isMainnet, this.testnetType); - } - - private get btcTimeLockScript() { - return getBtcTimeLockScript(this.isMainnet, this.testnetType); - } - - private isRgbppLock(lock: CKBComponents.Script) { - return lock.codeHash === this.rgbppLockScript.codeHash && lock.hashType === this.rgbppLockScript.hashType; - } - - private isBtcTimeLock(lock: CKBComponents.Script) { - return lock.codeHash === this.btcTimeLockScript.codeHash && lock.hashType === this.btcTimeLockScript.hashType; - } - /** * Clear the btcTxId in the RGBPP_LOCK/BTC_TIME_LOCK script to avoid the mismatch between the CKB and BTC transactions * @param ckbRawTx - CKB Raw Transaction @@ -155,7 +130,7 @@ export default class TransactionProcessor private async resetOutputLockScript(ckbRawTx: CKBRawTransaction, txid: string) { const outputs = ckbRawTx.outputs.map((output) => { const { lock } = output; - if (this.isRgbppLock(lock)) { + if (isRgbppLock(lock)) { const unpack = RGBPPLock.unpack(lock.args); // https://github.com/ckb-cell/rgbpp-sdk/tree/main/examples/rgbpp#what-you-must-know-about-btc-transaction-id const btcTxid = bytes.hexify(bytes.bytify(unpack.btcTxid).reverse()); @@ -164,10 +139,10 @@ export default class TransactionProcessor } return { ...output, - lock: genRgbppLockScript(buildPreLockArgs(unpack.outIndex), this.isMainnet), + lock: genRgbppLockScript(buildPreLockArgs(unpack.outIndex), IS_MAINNET), }; } - if (this.isBtcTimeLock(lock)) { + if (isBtcTimeLock(lock)) { const btcTxid = btcTxIdFromBtcTimeLockArgs(lock.args); if (remove0x(btcTxid) !== txid) { return output; @@ -175,7 +150,7 @@ export default class TransactionProcessor const toLock = lockScriptFromBtcTimeLockArgs(lock.args); return { ...output, - lock: genBtcTimeLockScript(toLock, this.isMainnet), + lock: genBtcTimeLockScript(toLock, IS_MAINNET), }; } return output; @@ -253,31 +228,23 @@ export default class TransactionProcessor private getCkbRawTxWithRealBtcTxid(ckbVirtualResult: CKBVirtualResult, txid: string) { let ckbRawTx = ckbVirtualResult.ckbRawTx; const needUpdateCkbTx = ckbRawTx.outputs.some((output) => { - if (this.isRgbppLock(output.lock)) { + if (isRgbppLock(output.lock)) { const { btcTxid } = RGBPPLock.unpack(output.lock.args); const txid = remove0x(btcTxid); this.cradle.logger.debug(`[TransactionProcessor] RGBPP_LOCK args txid: ${btcTxid}`); - return ( - output.lock.codeHash === this.rgbppLockScript.codeHash && - output.lock.hashType === this.rgbppLockScript.hashType && - txid === RGBPP_TX_ID_PLACEHOLDER - ); + return txid === RGBPP_TX_ID_PLACEHOLDER; } - if (this.isBtcTimeLock(output.lock)) { + if (isBtcTimeLock(output.lock)) { const btcTxid = btcTxIdFromBtcTimeLockArgs(output.lock.args); const txid = remove0x(btcTxid); this.cradle.logger.debug(`[TransactionProcessor] BTC_TIME_LOCK args txid: ${txid}`); - return ( - output.lock.codeHash === this.btcTimeLockScript.codeHash && - output.lock.hashType === this.btcTimeLockScript.hashType && - txid === RGBPP_TX_ID_PLACEHOLDER - ); + return txid === RGBPP_TX_ID_PLACEHOLDER; } return false; }); if (needUpdateCkbTx) { this.cradle.logger.info(`[TransactionProcessor] Update CKB Raw Transaction with real BTC txid: ${txid}`); - ckbRawTx = updateCkbTxWithRealBtcTxId({ ckbRawTx, btcTxId: txid, isMainnet: this.isMainnet }); + ckbRawTx = updateCkbTxWithRealBtcTxId({ ckbRawTx, btcTxId: txid, isMainnet: IS_MAINNET }); } return ckbRawTx; } @@ -331,7 +298,7 @@ export default class TransactionProcessor * if the transaction has spore type dep, we need to append the spore cobuild witness to the transaction */ private hasSporeTypeDep(tx: CKBRawTransaction) { - const sporeTypeDep = getSporeTypeDep(this.isMainnet); + const sporeTypeDep = getSporeTypeDep(IS_MAINNET); const hasSporeTypeDep = tx.cellDeps.some((cellDep) => { return serializeCellDep(cellDep) === serializeCellDep(sporeTypeDep); }); @@ -351,7 +318,7 @@ export default class TransactionProcessor ); const sporeLiveCells = inputs .filter(({ status, cell }) => { - return status === 'live' && cell?.output.type && isClusterSporeTypeSupported(cell?.output.type, this.isMainnet); + return status === 'live' && cell?.output.type && isClusterSporeTypeSupported(cell?.output.type, IS_MAINNET); }) .map((liveCell) => liveCell.cell!); if (sporeLiveCells.length > 0) { @@ -413,7 +380,7 @@ export default class TransactionProcessor const { txid, ckbVirtualResult } = job.data; const { ckbRawTx } = ckbVirtualResult; // append the secp256k1 cell dep to the transaction - ckbRawTx.cellDeps.push(getSecp256k1CellDep(this.isMainnet)); + ckbRawTx.cellDeps.push(getSecp256k1CellDep(IS_MAINNET)); // update the job data to append the paymaster cell next time job.updateData({ txid, diff --git a/src/services/unlocker.ts b/src/services/unlocker.ts index f8ffbc2b..7edc15cc 100644 --- a/src/services/unlocker.ts +++ b/src/services/unlocker.ts @@ -6,7 +6,6 @@ import { IndexerCell, buildBtcTimeCellsSpentTx, buildSporeBtcTimeCellsSpentTx, - getBtcTimeLockScript, isClusterSporeTypeSupported, isTypeAssetSupported, isUDTTypeSupported, @@ -21,8 +20,10 @@ import { BTC_MAINNET_SPV_START_BLOCK_HEIGHT, BTC_SIGNET_SPV_START_BLOCK_HEIGHT, BTC_TESTNET_SPV_START_BLOCK_HEIGHT, - TestnetTypeMap, + TESTNET_TYPE, + IS_MAINNET, } from '../constants'; +import { getBtcTimeLock } from '../utils/lockscript'; interface IUnlocker { getNextBatchLockCell(): Promise; @@ -47,16 +48,8 @@ export default class Unlocker implements IUnlocker { }) as CellCollector; } - private get isMainnet() { - return this.cradle.env.NETWORK === 'mainnet'; - } - - private get testnetType() { - return TestnetTypeMap[this.cradle.env.NETWORK]; - } - private get lockScript() { - return getBtcTimeLockScript(this.isMainnet, this.testnetType); + return getBtcTimeLock(); } private get btcSpvStartBlockHeight() { @@ -80,7 +73,7 @@ export default class Unlocker implements IUnlocker { const { blocks } = await this.cradle.bitcoin.getBlockchainInfo(); for await (const cell of collect) { // allow supported asset types only - if (!cell.cellOutput.type || !isTypeAssetSupported(cell.cellOutput.type, this.isMainnet)) { + if (!cell.cellOutput.type || !isTypeAssetSupported(cell.cellOutput.type, IS_MAINNET)) { continue; } @@ -136,25 +129,25 @@ export default class Unlocker implements IUnlocker { const ckbRawTxs = []; // udt type cells unlock - const udtTypeCells = cells.filter((cell) => isUDTTypeSupported(cell.output.type!, this.isMainnet)); + const udtTypeCells = cells.filter((cell) => isUDTTypeSupported(cell.output.type!, IS_MAINNET)); if (udtTypeCells.length > 0) { const ckbRawTx = await buildBtcTimeCellsSpentTx({ btcTimeCells: udtTypeCells, btcAssetsApi, - isMainnet: this.isMainnet, - btcTestnetType: this.testnetType, + isMainnet: IS_MAINNET, + btcTestnetType: TESTNET_TYPE, }); ckbRawTxs.push(ckbRawTx); } // spore type cells unlock - const sporeTypeCells = cells.filter((cell) => isClusterSporeTypeSupported(cell.output.type!, this.isMainnet)); + const sporeTypeCells = cells.filter((cell) => isClusterSporeTypeSupported(cell.output.type!, IS_MAINNET)); if (sporeTypeCells.length > 0) { const ckbRawTx = await buildSporeBtcTimeCellsSpentTx({ btcTimeCells: sporeTypeCells, btcAssetsApi, - isMainnet: this.isMainnet, - btcTestnetType: this.testnetType, + isMainnet: IS_MAINNET, + btcTestnetType: TESTNET_TYPE, }); ckbRawTxs.push(ckbRawTx); } @@ -181,7 +174,7 @@ export default class Unlocker implements IUnlocker { collector, outputCapacityRange, ckbRawTx, - isMainnet: this.isMainnet, + isMainnet: IS_MAINNET, }); this.cradle.logger.debug(`[Unlocker] Transaction signed: ${JSON.stringify(signedTx)}`);