From 13aca675f63a7e5ed1c5a21cbe9ea3df93667d13 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Thu, 9 May 2024 15:49:27 +0800 Subject: [PATCH 01/78] feat: Add rgbpp root package --- README.md | 1 + packages/rgbpp/README.md | 15 +++++++++++++++ packages/rgbpp/package.json | 26 ++++++++++++++++++++++++++ packages/rgbpp/src/index.ts | 7 +++++++ packages/rgbpp/tsconfig.build.json | 9 +++++++++ packages/rgbpp/tsconfig.json | 27 +++++++++++++++++++++++++++ pnpm-lock.yaml | 12 ++++++++++++ 7 files changed, 97 insertions(+) create mode 100644 packages/rgbpp/README.md create mode 100644 packages/rgbpp/package.json create mode 100644 packages/rgbpp/src/index.ts create mode 100644 packages/rgbpp/tsconfig.build.json create mode 100644 packages/rgbpp/tsconfig.json diff --git a/README.md b/README.md index b49a837b..2a56ca8d 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ This repository offers utilities for Bitcoin and RGB++ asset integration. ### Packages in this repository +- [rgbpp-sdk](./packages/rgbpp): A root package to integrate of common functions from the RGB++ SDK sub-packages(btc/ckb/service). - [@rgbpp-sdk/btc](./packages/btc): Bitcoin part of the SDK - [@rgbpp-sdk/ckb](./packages/ckb): Nervos CKB part of the SDK - [@rgbpp-sdk/service](./packages/service): A wrapped class to interact with `Bitcoin/RGB++ Assets Service` diff --git a/packages/rgbpp/README.md b/packages/rgbpp/README.md new file mode 100644 index 00000000..8680c297 --- /dev/null +++ b/packages/rgbpp/README.md @@ -0,0 +1,15 @@ +# rgbpp + +RGB++ SDK + +A root package to integrate of common functions from the RGB++ SDK sub-packages(btc/ckb/service). + +## Installation + +``` +$ npm i rgbpp +# or +$ yarn add rgbpp +# or +$ pnpm add rgbpp +``` \ No newline at end of file diff --git a/packages/rgbpp/package.json b/packages/rgbpp/package.json new file mode 100644 index 00000000..95f755bb --- /dev/null +++ b/packages/rgbpp/package.json @@ -0,0 +1,26 @@ +{ + "name": "rgbpp", + "version": "0.1.0", + "scripts": { + "build": "tsc -p tsconfig.build.json", + "lint": "tsc && eslint --ext .ts src/* && prettier --check 'src/*.ts'", + "lint:fix": "tsc && eslint --fix --ext .ts src/* && prettier --write 'src/*.ts'", + "clean": "pnpm run clean:cache & pnpm run clean:build", + "clean:build": "rimraf lib && pnpm run clean:buildinfo", + "clean:buildinfo": "rimraf tsconfig.*tsbuildinfo", + "clean:cache": "rimraf .turbo" + }, + "main": "lib", + "files": [ + "lib" + ], + "types": "./lib/index.d.ts", + "dependencies": { + "@rgbpp-sdk/btc": "workspace", + "@rgbpp-sdk/ckb": "workspace", + "@rgbpp-sdk/service": "workspace" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/rgbpp/src/index.ts b/packages/rgbpp/src/index.ts new file mode 100644 index 00000000..a21775e0 --- /dev/null +++ b/packages/rgbpp/src/index.ts @@ -0,0 +1,7 @@ +export { remove0x } from '@rgbpp-sdk/ckb'; +export { ErrorCodes, ErrorMessages } from '@rgbpp-sdk/btc'; +export { ErrorCodes as ServiceErrorCodes, ErrorMessages as ServiceErrorMessage } from '@rgbpp-sdk/service'; + +export * from '@rgbpp-sdk/ckb'; +export * from '@rgbpp-sdk/service'; +export * from '@rgbpp-sdk/btc'; diff --git a/packages/rgbpp/tsconfig.build.json b/packages/rgbpp/tsconfig.build.json new file mode 100644 index 00000000..f800f1bf --- /dev/null +++ b/packages/rgbpp/tsconfig.build.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "CommonJS", + "rootDir": "src", + "outDir": "lib", + "noEmit": false + } +} diff --git a/packages/rgbpp/tsconfig.json b/packages/rgbpp/tsconfig.json new file mode 100644 index 00000000..cf4cb2bf --- /dev/null +++ b/packages/rgbpp/tsconfig.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "target": "ES2015", + "lib": ["dom", "dom.iterable", "esnext"], + "module": "ES2020", + "outDir": "./lib", + "composite": false, + "resolveJsonModule": true, + "strictNullChecks": true, + "noEmit": true, + "declaration": true, + "declarationMap": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "inlineSources": false, + "isolatedModules": true, + "moduleResolution": "node", + "noUnusedLocals": false, + "noUnusedParameters": false, + "preserveWatchOutput": true, + "skipLibCheck": true, + "strict": true + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bce19ada..a8e05f10 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -248,6 +248,18 @@ importers: specifier: ^1.4.0 version: 1.4.0(@types/node@20.12.2) + packages/rgbpp: + dependencies: + '@rgbpp-sdk/btc': + specifier: workspace + version: link:../btc + '@rgbpp-sdk/ckb': + specifier: workspace + version: link:../ckb + '@rgbpp-sdk/service': + specifier: workspace + version: link:../service + packages/service: dependencies: '@ckb-lumos/base': From 5206cdf513f2ca7560c8e3cbb35c3b9ac66717b7 Mon Sep 17 00:00:00 2001 From: Flouse <1297478+Flouse@users.noreply.github.com> Date: Thu, 9 May 2024 17:02:19 +0800 Subject: [PATCH 02/78] docs: update README related to assets-api (#158) --- README.md | 20 ++++++++++---------- packages/service/README.md | 23 +++++++++++++++++------ 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index b49a837b..b620175e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This repository offers utilities for Bitcoin and RGB++ asset integration. - [@rgbpp-sdk/btc](./packages/btc): Bitcoin part of the SDK - [@rgbpp-sdk/ckb](./packages/ckb): Nervos CKB part of the SDK -- [@rgbpp-sdk/service](./packages/service): A wrapped class to interact with `Bitcoin/RGB++ Assets Service` +- [@rgbpp-sdk/service](./packages/service): Wrapped interfaces of `Bitcoin/RGB++ Assets Service` ## RGB++ Code Examples @@ -15,7 +15,7 @@ This repository offers utilities for Bitcoin and RGB++ asset integration. ## Related CKB Scripts (Contracts) - [CKB Bitcoin SPV Type Script](https://github.com/ckb-cell/ckb-bitcoin-spv-contracts/tree/master/contracts/ckb-bitcoin-spv-type-lock): A [type script](https://docs.nervos.org/docs/basics/glossary#type-script) for [Bitcoin SPV](https://bitcoinwiki.org/wiki/simplified-payment-verification) clients which synchronize [Bitcoin](https://bitcoin.org) state into [CKB](https://github.com/nervosnetwork/ckb) -- [RgbppLockScript and BtcTimeLockScript](https://github.com/ckb-cell/rgbpp-sdk/blob/cf25ea014d4e0fc24723df8eea8bd61f59e1060a/packages/ckb/src/constants/index.ts#L11-L121) +- [RgbppLockScript and BtcTimeLockScript](https://github.com/ckb-cell/rgbpp-sdk/blob/63df2dcd95b1b735b5d235e156e4361a3c87b0ac/packages/ckb/src/constants/index.ts#L12-L206) * design: https://github.com/ckb-cell/RGBPlusPlus-design/blob/main/docs/light-paper-en.md * testnet: https://pudge.explorer.nervos.org/scripts#RGB++ * mainnet: https://explorer.nervos.org/scripts#RGB++ @@ -36,25 +36,25 @@ This repository offers utilities for Bitcoin and RGB++ asset integration. 2. **[BTC → CKB](https://github.com/ckb-cell/rgbpp-sdk/blob/develop/packages/ckb/README.md#rgb-spore-leap-from-btc-to-ckb)** 3. **[CKB → BTC](https://github.com/ckb-cell/rgbpp-sdk/blob/develop/packages/ckb/README.md#rgb-spore-leap-from-ckb-to-btc)** *(isomorphic rgbpp_btc_tx is not required in this workflow)* - > [!IMPORTANT] + > [!IMPORTANT] > It's recommended to save the `rgbpp_ckb_tx_virtual` locally in case you need it in the future. 2. **Creation of `rgbpp_btc_tx` through [@rgbpp-sdk/btc](https://github.com/ckb-cell/rgbpp-sdk/tree/develop/packages/btc)** - 1. construct isomorphic rgbpp_btc_tx based on rgbpp_ckb_tx_virtual and rgbpp commitment - 2. sign and broadcast rgbpp_btc_tx to obtain `rgbpp_btc_txid` + 1. construct isomorphic `rgbpp_btc_tx` based on `rgbpp_ckb_tx_virtual` and rgbpp commitment + 2. sign and broadcast `rgbpp_btc_tx` to obtain `rgbpp_btc_txid` 3. JoyID or dApp sends `rgbpp_btc_txid` and `rgbpp_ckb_tx_virtual` to RGB++ CKB transaction Queue (API Endpoint: `/rgbpp/v1/transaction/ckb-tx`) 4. `RGB++ CKB transaction Queue` will process the following things: 1. **verify** the received requests 2. continuously fetch request from the queue through a **cron job** - 3. check whether the **confirmations** of req.rgbpp_btc_txid is sufficient - 4. generate the **witnesses for RgbppLocks** in the rgbpp_ckb_tx_virtual - 5. add a **paymaster cell** into rgbpp_ckb_tx_virtual.inputs if the CKB capacity is insufficient + 3. check whether the **confirmations** of `req.rgbpp_btc_txid` is sufficient + 4. generate the **witnesses for RgbppLocks** in the `rgbpp_ckb_tx_virtual` + 5. add a **paymaster cell** into `rgbpp_ckb_tx_virtual`.inputs if the CKB capacity is insufficient 1. need to **verify the existence of paymaster UTXO** in the rgbpp_btc_tx 2. sign the paymaster cell and the entire transaction if needed - 6. **finalize** the rgbpp_ckb_tx_virtual to a rgbpp_ckb_tx - 7. **broadcast** rgbpp_ckb_tx and mark the job as completed upon tx-confirmation + 6. **finalize** the `rgbpp_ckb_tx_virtual` to a `rgbpp_ckb_tx` + 7. **broadcast** `rgbpp_ckb_tx` and mark the job as completed upon tx-confirmation ### Notes diff --git a/packages/service/README.md b/packages/service/README.md index 478cce02..3fef78cd 100644 --- a/packages/service/README.md +++ b/packages/service/README.md @@ -10,6 +10,9 @@ The `@rgbpp-sdk/service` package provides a wrapped class to interact with `Bitc - Simplify RGB++ assets workflows with **RGB++ CKB transaction Queue** and cron jobs - More detailed API documentation can be found on [Testnet](https://btc-assets-api.testnet.mibao.pro/docs) and [Mainnet](https://api.rgbpp.io/docs) +> [!NOTE] +> `Bitcoin/RGB++ Assets Service` is designed to streamline the transaction workflow. Developers have the option to implement its features by themselves without limitation. + ## Installation ```bash @@ -25,14 +28,22 @@ $ pnpm add @rgbpp-sdk/service ### Get an access token -The BtcAssetsApi is currently limited to verified apps only. -If you're a developer and want to access the BtcAssetsApi service, -please email us to request a JWT token for your app: f@cell.studio. +#### Testnet + +You can get a testnet access token through the [/token/generate](https://btc-assets-api.testnet.mibao.pro/docs/static/index.html#/Token/post_token_generate) API directly. + +#### Mainnet -In the email, you should provide us some information about your app: +The mainnet BtcAssetsApi is currently limited to verified apps only. + +When your app development is ready on testnet, and requires a mainnet access token, +please email us at f@cell.studio to request a mainnet JWT token. + +In the email, please provide the following information about your app: - `name`: Your app name, e.g. "rgbpp-app" -- `domain`: Your app domain, e.g. "rgbpp.app" (without protocol) +- `domain`: Your app domain, e.g. "rgbpp.app" (without protocol prefix) + ### Initialize the service @@ -83,7 +94,7 @@ console.log(res); // } ``` -All available APIs in the [BtcAssetsApi](#btcassetsapi-1) section. +All available APIs in the [BtcAssetsApi](#types) section. ### Handling service errors From 816ff05590b6e3f8a80d3c2e2571579f0f6d9076 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Thu, 9 May 2024 17:30:35 +0800 Subject: [PATCH 03/78] feat: Add sub path for rgbpp package --- packages/rgbpp/src/btc.ts | 1 + packages/rgbpp/src/ckb.ts | 1 + packages/rgbpp/src/index.ts | 40 +++++++++++++++++++++++++++++------ packages/rgbpp/src/service.ts | 1 + 4 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 packages/rgbpp/src/btc.ts create mode 100644 packages/rgbpp/src/ckb.ts create mode 100644 packages/rgbpp/src/service.ts diff --git a/packages/rgbpp/src/btc.ts b/packages/rgbpp/src/btc.ts new file mode 100644 index 00000000..749dca24 --- /dev/null +++ b/packages/rgbpp/src/btc.ts @@ -0,0 +1 @@ +export * from '@rgbpp-sdk/btc'; diff --git a/packages/rgbpp/src/ckb.ts b/packages/rgbpp/src/ckb.ts new file mode 100644 index 00000000..550abcff --- /dev/null +++ b/packages/rgbpp/src/ckb.ts @@ -0,0 +1 @@ +export * from '@rgbpp-sdk/service'; diff --git a/packages/rgbpp/src/index.ts b/packages/rgbpp/src/index.ts index a21775e0..6bd74faf 100644 --- a/packages/rgbpp/src/index.ts +++ b/packages/rgbpp/src/index.ts @@ -1,7 +1,35 @@ -export { remove0x } from '@rgbpp-sdk/ckb'; -export { ErrorCodes, ErrorMessages } from '@rgbpp-sdk/btc'; -export { ErrorCodes as ServiceErrorCodes, ErrorMessages as ServiceErrorMessage } from '@rgbpp-sdk/service'; +export { + genCreateClusterCkbVirtualTx, + genCreateSporeCkbVirtualTx, + genLeapSporeFromBtcToCkbVirtualTx, + genTransferSporeCkbVirtualTx, + genBtcTransferCkbVirtualTx, + genCkbJumpBtcVirtualTx, + genBtcBatchTransferCkbVirtualTx, + genLeapSporeFromCkbToBtcRawTx, + genRgbppLaunchCkbVirtualTx, + genBtcJumpCkbVirtualTx, + buildBtcTimeCellsSpentTx, + buildSporeBtcTimeCellsSpentTx, + signBtcTimeCellSpentTx, +} from '@rgbpp-sdk/ckb'; +export type { + CreateClusterCkbVirtualTxParams, + CreateSporeCkbVirtualTxParams, + LeapSporeFromBtcToCkbVirtualTxParams, + TransferSporeCkbVirtualTxParams, + BtcTransferVirtualTxParams, + BtcJumpCkbVirtualTxParams, + BtcBatchTransferVirtualTxParams, + CkbJumpBtcVirtualTxParams, + SporeCreateVirtualTxResult, + BtcTransferVirtualTxResult, + BtcJumpCkbVirtualTxResult, + BtcBatchTransferVirtualTxResult, + SporeTransferVirtualTxResult, + SporeLeapVirtualTxResult, + SporeVirtualTxResult, +} from '@rgbpp-sdk/ckb'; -export * from '@rgbpp-sdk/ckb'; -export * from '@rgbpp-sdk/service'; -export * from '@rgbpp-sdk/btc'; +export { BtcAssetsApi } from '@rgbpp-sdk/service'; +export { sendBtc, sendUtxos, sendRgbppUtxos } from '@rgbpp-sdk/btc'; diff --git a/packages/rgbpp/src/service.ts b/packages/rgbpp/src/service.ts new file mode 100644 index 00000000..749dca24 --- /dev/null +++ b/packages/rgbpp/src/service.ts @@ -0,0 +1 @@ +export * from '@rgbpp-sdk/btc'; From 0caba5a65df26989f042bfa051667cdd4f8198c8 Mon Sep 17 00:00:00 2001 From: Shook Date: Thu, 9 May 2024 18:28:58 +0800 Subject: [PATCH 04/78] feat: export basic apis/types of btc/service in rgbpp --- packages/rgbpp/src/index.ts | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/rgbpp/src/index.ts b/packages/rgbpp/src/index.ts index 6bd74faf..d1bed25d 100644 --- a/packages/rgbpp/src/index.ts +++ b/packages/rgbpp/src/index.ts @@ -1,3 +1,6 @@ +/** + * ckb + */ export { genCreateClusterCkbVirtualTx, genCreateSporeCkbVirtualTx, @@ -31,5 +34,21 @@ export type { SporeVirtualTxResult, } from '@rgbpp-sdk/ckb'; +/** + * service + */ export { BtcAssetsApi } from '@rgbpp-sdk/service'; -export { sendBtc, sendUtxos, sendRgbppUtxos } from '@rgbpp-sdk/btc'; + +/** + * btc + */ +export { + DataSource, + sendBtc, + sendUtxos, + sendRgbppUtxos, + createSendBtcBuilder, + createSendUtxosBuilder, + createSendRgbppUtxosBuilder, +} from '@rgbpp-sdk/btc'; +export type { NetworkType, AddressType, SendBtcProps, SendUtxosProps, SendRgbppUtxosProps } from '@rgbpp-sdk/btc'; From 05059edeaa2366f332bc472649bf5ac13530d694 Mon Sep 17 00:00:00 2001 From: Shook Date: Thu, 9 May 2024 18:42:21 +0800 Subject: [PATCH 05/78] feat: define sub paths of rgbpp --- packages/rgbpp/package.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/rgbpp/package.json b/packages/rgbpp/package.json index 95f755bb..cad776f9 100644 --- a/packages/rgbpp/package.json +++ b/packages/rgbpp/package.json @@ -11,6 +11,24 @@ "clean:cache": "rimraf .turbo" }, "main": "lib", + "exports": { + ".": { + "types": "./lib/index.d.ts", + "default": "./lib/index.js" + }, + "./btc": { + "types": "./lib/btc.d.ts", + "default": "./lib/btc.js" + }, + "./ckb": { + "types": "./lib/ckb.d.ts", + "default": "./lib/ckb.js" + }, + "./service": { + "types": "./lib/service.d.ts", + "default": "./lib/service.js" + } + }, "files": [ "lib" ], From 217cc771058dcdb935e94fa21f2df7dae9667d32 Mon Sep 17 00:00:00 2001 From: Dylan Max Date: Thu, 9 May 2024 19:01:36 +0800 Subject: [PATCH 06/78] Update README.md Co-authored-by: Shook <44739165+ShookLyngs@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2a56ca8d..9734d66d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This repository offers utilities for Bitcoin and RGB++ asset integration. ### Packages in this repository -- [rgbpp-sdk](./packages/rgbpp): A root package to integrate of common functions from the RGB++ SDK sub-packages(btc/ckb/service). +- [rgbpp](./packages/rgbpp): A root package to integrate of common functions from the RGB++ SDK sub-packages(btc/ckb/service). - [@rgbpp-sdk/btc](./packages/btc): Bitcoin part of the SDK - [@rgbpp-sdk/ckb](./packages/ckb): Nervos CKB part of the SDK - [@rgbpp-sdk/service](./packages/service): A wrapped class to interact with `Bitcoin/RGB++ Assets Service` From 2c42c8048f71ad811093af9e341dbaafdb952a72 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Thu, 9 May 2024 20:00:14 +0800 Subject: [PATCH 07/78] refactor: Collect all rgbpp inputs without isMax --- packages/ckb/src/collector/index.ts | 3 ++- packages/ckb/src/rgbpp/launch.ts | 2 +- packages/ckb/src/types/collector.ts | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ckb/src/collector/index.ts b/packages/ckb/src/collector/index.ts index 88b5739a..89a2641b 100644 --- a/packages/ckb/src/collector/index.ts +++ b/packages/ckb/src/collector/index.ts @@ -110,6 +110,7 @@ export class Collector { const changeCapacity = config?.minCapacity ?? MIN_CAPACITY; const inputs: CKBComponents.CellInput[] = []; let sumInputsCapacity = BigInt(0); + const isRgbppLock = liveCells.length > 0 && isRgbppLockCellIgnoreChain(liveCells[0].output); for (const cell of liveCells) { inputs.push({ previousOutput: { @@ -119,7 +120,7 @@ export class Collector { since: '0x0', }); sumInputsCapacity += BigInt(cell.output.capacity); - if (sumInputsCapacity >= needCapacity + changeCapacity + fee && !config?.isMax) { + if (sumInputsCapacity >= needCapacity + changeCapacity + fee && !isRgbppLock) { break; } } diff --git a/packages/ckb/src/rgbpp/launch.ts b/packages/ckb/src/rgbpp/launch.ts index 905750b0..a851bfcd 100644 --- a/packages/ckb/src/rgbpp/launch.ts +++ b/packages/ckb/src/rgbpp/launch.ts @@ -57,7 +57,7 @@ export const genRgbppLaunchCkbVirtualTx = async ({ const infoCellCapacity = calculateRgbppTokenInfoCellCapacity(rgbppTokenInfo, isMainnet); const txFee = MAX_FEE; - const { inputs, sumInputsCapacity } = collector.collectInputs(emptyCells, infoCellCapacity, txFee, { isMax: true }); + const { inputs, sumInputsCapacity } = collector.collectInputs(emptyCells, infoCellCapacity, txFee); let rgbppCellCapacity = sumInputsCapacity - infoCellCapacity; const outputs: CKBComponents.CellOutput[] = [ diff --git a/packages/ckb/src/types/collector.ts b/packages/ckb/src/types/collector.ts index 9bbb7716..f1db7bc8 100644 --- a/packages/ckb/src/types/collector.ts +++ b/packages/ckb/src/types/collector.ts @@ -24,7 +24,6 @@ export interface CollectUdtResult extends CollectResult { } export interface CollectConfig { - isMax?: boolean; minCapacity?: bigint; errMsg?: string; } From c0aaa61dbb98635fb5e22d640c71cca54ad1585c Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Thu, 9 May 2024 20:07:17 +0800 Subject: [PATCH 08/78] chore: Upgrade vite version --- apps/vite/package.json | 2 +- pnpm-lock.yaml | 435 ++--------------------------------------- 2 files changed, 14 insertions(+), 423 deletions(-) diff --git a/apps/vite/package.json b/apps/vite/package.json index 7c8824b2..c2c54150 100644 --- a/apps/vite/package.json +++ b/apps/vite/package.json @@ -27,7 +27,7 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.5", "typescript": "^5.2.2", - "vite": "^5.1.4", + "vite": "^5.2.11", "vite-plugin-node-polyfills": "^0.21.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bce19ada..c5473966 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -114,7 +114,7 @@ importers: version: 7.0.2(eslint@8.56.0)(typescript@5.4.2) '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.2.1(vite@5.1.4) + version: 4.2.1(vite@5.2.11) eslint: specifier: ^8.56.0 version: 8.56.0 @@ -128,11 +128,11 @@ importers: specifier: ^5.2.2 version: 5.4.2 vite: - specifier: ^5.1.4 - version: 5.1.4(@types/node@20.12.2) + specifier: ^5.2.11 + version: 5.2.11(@types/node@20.12.2) vite-plugin-node-polyfills: specifier: ^0.21.0 - version: 0.21.0(vite@5.1.4) + version: 0.21.0(vite@5.2.11) examples/rgbpp: dependencies: @@ -960,15 +960,6 @@ packages: '@jridgewell/trace-mapping': 0.3.9 dev: true - /@esbuild/aix-ppc64@0.19.12: - resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [aix] - requiresBuild: true - dev: true - optional: true - /@esbuild/aix-ppc64@0.20.2: resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} engines: {node: '>=12'} @@ -978,15 +969,6 @@ packages: dev: true optional: true - /@esbuild/android-arm64@0.19.12: - resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/android-arm64@0.20.2: resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} engines: {node: '>=12'} @@ -996,15 +978,6 @@ packages: dev: true optional: true - /@esbuild/android-arm@0.19.12: - resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/android-arm@0.20.2: resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} engines: {node: '>=12'} @@ -1014,15 +987,6 @@ packages: dev: true optional: true - /@esbuild/android-x64@0.19.12: - resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/android-x64@0.20.2: resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} engines: {node: '>=12'} @@ -1032,15 +996,6 @@ packages: dev: true optional: true - /@esbuild/darwin-arm64@0.19.12: - resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - /@esbuild/darwin-arm64@0.20.2: resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} engines: {node: '>=12'} @@ -1050,15 +1005,6 @@ packages: dev: true optional: true - /@esbuild/darwin-x64@0.19.12: - resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - /@esbuild/darwin-x64@0.20.2: resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} engines: {node: '>=12'} @@ -1068,15 +1014,6 @@ packages: dev: true optional: true - /@esbuild/freebsd-arm64@0.19.12: - resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/freebsd-arm64@0.20.2: resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} engines: {node: '>=12'} @@ -1086,15 +1023,6 @@ packages: dev: true optional: true - /@esbuild/freebsd-x64@0.19.12: - resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/freebsd-x64@0.20.2: resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} engines: {node: '>=12'} @@ -1104,15 +1032,6 @@ packages: dev: true optional: true - /@esbuild/linux-arm64@0.19.12: - resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-arm64@0.20.2: resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} engines: {node: '>=12'} @@ -1122,15 +1041,6 @@ packages: dev: true optional: true - /@esbuild/linux-arm@0.19.12: - resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-arm@0.20.2: resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} engines: {node: '>=12'} @@ -1140,15 +1050,6 @@ packages: dev: true optional: true - /@esbuild/linux-ia32@0.19.12: - resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-ia32@0.20.2: resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} engines: {node: '>=12'} @@ -1158,15 +1059,6 @@ packages: dev: true optional: true - /@esbuild/linux-loong64@0.19.12: - resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-loong64@0.20.2: resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} engines: {node: '>=12'} @@ -1176,15 +1068,6 @@ packages: dev: true optional: true - /@esbuild/linux-mips64el@0.19.12: - resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-mips64el@0.20.2: resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} engines: {node: '>=12'} @@ -1194,15 +1077,6 @@ packages: dev: true optional: true - /@esbuild/linux-ppc64@0.19.12: - resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-ppc64@0.20.2: resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} engines: {node: '>=12'} @@ -1212,15 +1086,6 @@ packages: dev: true optional: true - /@esbuild/linux-riscv64@0.19.12: - resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-riscv64@0.20.2: resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} engines: {node: '>=12'} @@ -1230,15 +1095,6 @@ packages: dev: true optional: true - /@esbuild/linux-s390x@0.19.12: - resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-s390x@0.20.2: resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} engines: {node: '>=12'} @@ -1248,15 +1104,6 @@ packages: dev: true optional: true - /@esbuild/linux-x64@0.19.12: - resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-x64@0.20.2: resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} engines: {node: '>=12'} @@ -1266,15 +1113,6 @@ packages: dev: true optional: true - /@esbuild/netbsd-x64@0.19.12: - resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/netbsd-x64@0.20.2: resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} engines: {node: '>=12'} @@ -1284,15 +1122,6 @@ packages: dev: true optional: true - /@esbuild/openbsd-x64@0.19.12: - resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/openbsd-x64@0.20.2: resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} engines: {node: '>=12'} @@ -1302,15 +1131,6 @@ packages: dev: true optional: true - /@esbuild/sunos-x64@0.19.12: - resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - /@esbuild/sunos-x64@0.20.2: resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} engines: {node: '>=12'} @@ -1320,15 +1140,6 @@ packages: dev: true optional: true - /@esbuild/win32-arm64@0.19.12: - resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - /@esbuild/win32-arm64@0.20.2: resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} engines: {node: '>=12'} @@ -1338,15 +1149,6 @@ packages: dev: true optional: true - /@esbuild/win32-ia32@0.19.12: - resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - /@esbuild/win32-ia32@0.20.2: resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} engines: {node: '>=12'} @@ -1356,15 +1158,6 @@ packages: dev: true optional: true - /@esbuild/win32-x64@0.19.12: - resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - /@esbuild/win32-x64@0.20.2: resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} engines: {node: '>=12'} @@ -1697,14 +1490,6 @@ packages: picomatch: 2.3.1 dev: true - /@rollup/rollup-android-arm-eabi@4.13.0: - resolution: {integrity: sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-android-arm-eabi@4.13.2: resolution: {integrity: sha512-3XFIDKWMFZrMnao1mJhnOT1h2g0169Os848NhhmGweEcfJ4rCi+3yMCOLG4zA61rbJdkcrM/DjVZm9Hg5p5w7g==} cpu: [arm] @@ -1713,14 +1498,6 @@ packages: dev: true optional: true - /@rollup/rollup-android-arm64@4.13.0: - resolution: {integrity: sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-android-arm64@4.13.2: resolution: {integrity: sha512-GdxxXbAuM7Y/YQM9/TwwP+L0omeE/lJAR1J+olu36c3LqqZEBdsIWeQ91KBe6nxwOnb06Xh7JS2U5ooWU5/LgQ==} cpu: [arm64] @@ -1729,14 +1506,6 @@ packages: dev: true optional: true - /@rollup/rollup-darwin-arm64@4.13.0: - resolution: {integrity: sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-darwin-arm64@4.13.2: resolution: {integrity: sha512-mCMlpzlBgOTdaFs83I4XRr8wNPveJiJX1RLfv4hggyIVhfB5mJfN4P8Z6yKh+oE4Luz+qq1P3kVdWrCKcMYrrA==} cpu: [arm64] @@ -1745,14 +1514,6 @@ packages: dev: true optional: true - /@rollup/rollup-darwin-x64@4.13.0: - resolution: {integrity: sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-darwin-x64@4.13.2: resolution: {integrity: sha512-yUoEvnH0FBef/NbB1u6d3HNGyruAKnN74LrPAfDQL3O32e3k3OSfLrPgSJmgb3PJrBZWfPyt6m4ZhAFa2nZp2A==} cpu: [x64] @@ -1761,14 +1522,6 @@ packages: dev: true optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.13.0: - resolution: {integrity: sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.13.2: resolution: {integrity: sha512-GYbLs5ErswU/Xs7aGXqzc3RrdEjKdmoCrgzhJWyFL0r5fL3qd1NPcDKDowDnmcoSiGJeU68/Vy+OMUluRxPiLQ==} cpu: [arm] @@ -1777,14 +1530,6 @@ packages: dev: true optional: true - /@rollup/rollup-linux-arm64-gnu@4.13.0: - resolution: {integrity: sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-linux-arm64-gnu@4.13.2: resolution: {integrity: sha512-L1+D8/wqGnKQIlh4Zre9i4R4b4noxzH5DDciyahX4oOz62CphY7WDWqJoQ66zNR4oScLNOqQJfNSIAe/6TPUmQ==} cpu: [arm64] @@ -1793,14 +1538,6 @@ packages: dev: true optional: true - /@rollup/rollup-linux-arm64-musl@4.13.0: - resolution: {integrity: sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-linux-arm64-musl@4.13.2: resolution: {integrity: sha512-tK5eoKFkXdz6vjfkSTCupUzCo40xueTOiOO6PeEIadlNBkadH1wNOH8ILCPIl8by/Gmb5AGAeQOFeLev7iZDOA==} cpu: [arm64] @@ -1817,14 +1554,6 @@ packages: dev: true optional: true - /@rollup/rollup-linux-riscv64-gnu@4.13.0: - resolution: {integrity: sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-linux-riscv64-gnu@4.13.2: resolution: {integrity: sha512-C3GSKvMtdudHCN5HdmAMSRYR2kkhgdOfye4w0xzyii7lebVr4riCgmM6lRiSCnJn2w1Xz7ZZzHKuLrjx5620kw==} cpu: [riscv64] @@ -1841,14 +1570,6 @@ packages: dev: true optional: true - /@rollup/rollup-linux-x64-gnu@4.13.0: - resolution: {integrity: sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-linux-x64-gnu@4.13.2: resolution: {integrity: sha512-xXMLUAMzrtsvh3cZ448vbXqlUa7ZL8z0MwHp63K2IIID2+DeP5iWIT6g1SN7hg1VxPzqx0xZdiDM9l4n9LRU1A==} cpu: [x64] @@ -1857,14 +1578,6 @@ packages: dev: true optional: true - /@rollup/rollup-linux-x64-musl@4.13.0: - resolution: {integrity: sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-linux-x64-musl@4.13.2: resolution: {integrity: sha512-M/JYAWickafUijWPai4ehrjzVPKRCyDb1SLuO+ZyPfoXgeCEAlgPkNXewFZx0zcnoIe3ay4UjXIMdXQXOZXWqA==} cpu: [x64] @@ -1873,14 +1586,6 @@ packages: dev: true optional: true - /@rollup/rollup-win32-arm64-msvc@4.13.0: - resolution: {integrity: sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-win32-arm64-msvc@4.13.2: resolution: {integrity: sha512-2YWwoVg9KRkIKaXSh0mz3NmfurpmYoBBTAXA9qt7VXk0Xy12PoOP40EFuau+ajgALbbhi4uTj3tSG3tVseCjuA==} cpu: [arm64] @@ -1889,14 +1594,6 @@ packages: dev: true optional: true - /@rollup/rollup-win32-ia32-msvc@4.13.0: - resolution: {integrity: sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-win32-ia32-msvc@4.13.2: resolution: {integrity: sha512-2FSsE9aQ6OWD20E498NYKEQLneShWes0NGMPQwxWOdws35qQXH+FplabOSP5zEe1pVjurSDOGEVCE2agFwSEsw==} cpu: [ia32] @@ -1905,14 +1602,6 @@ packages: dev: true optional: true - /@rollup/rollup-win32-x64-msvc@4.13.0: - resolution: {integrity: sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-win32-x64-msvc@4.13.2: resolution: {integrity: sha512-7h7J2nokcdPePdKykd8wtc8QqqkqxIrUz7MHj6aNr8waBRU//NLDVnNjQnqQO6fqtjrtCdftpbTuOKAyrAQETQ==} cpu: [x64] @@ -2341,7 +2030,7 @@ packages: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} dev: true - /@vitejs/plugin-react@4.2.1(vite@5.1.4): + /@vitejs/plugin-react@4.2.1(vite@5.2.11): resolution: {integrity: sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -2352,7 +2041,7 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.23.3(@babel/core@7.24.0) '@types/babel__core': 7.20.5 react-refresh: 0.14.0 - vite: 5.1.4(@types/node@20.12.2) + vite: 5.2.11(@types/node@20.12.2) transitivePeerDependencies: - supports-color dev: true @@ -3450,37 +3139,6 @@ packages: is-symbol: 1.0.4 dev: true - /esbuild@0.19.12: - resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/aix-ppc64': 0.19.12 - '@esbuild/android-arm': 0.19.12 - '@esbuild/android-arm64': 0.19.12 - '@esbuild/android-x64': 0.19.12 - '@esbuild/darwin-arm64': 0.19.12 - '@esbuild/darwin-x64': 0.19.12 - '@esbuild/freebsd-arm64': 0.19.12 - '@esbuild/freebsd-x64': 0.19.12 - '@esbuild/linux-arm': 0.19.12 - '@esbuild/linux-arm64': 0.19.12 - '@esbuild/linux-ia32': 0.19.12 - '@esbuild/linux-loong64': 0.19.12 - '@esbuild/linux-mips64el': 0.19.12 - '@esbuild/linux-ppc64': 0.19.12 - '@esbuild/linux-riscv64': 0.19.12 - '@esbuild/linux-s390x': 0.19.12 - '@esbuild/linux-x64': 0.19.12 - '@esbuild/netbsd-x64': 0.19.12 - '@esbuild/openbsd-x64': 0.19.12 - '@esbuild/sunos-x64': 0.19.12 - '@esbuild/win32-arm64': 0.19.12 - '@esbuild/win32-ia32': 0.19.12 - '@esbuild/win32-x64': 0.19.12 - dev: true - /esbuild@0.20.2: resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} engines: {node: '>=12'} @@ -5166,15 +4824,6 @@ packages: source-map-js: 1.1.0 dev: false - /postcss@8.4.36: - resolution: {integrity: sha512-/n7eumA6ZjFHAsbX30yhHup/IMkOmlmvtEi7P+6RMYf+bGJSUHc3geH4a0NSZxAz/RJfiS9tooCTs9LAVYUZKw==} - engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.7 - picocolors: 1.0.0 - source-map-js: 1.1.0 - dev: true - /postcss@8.4.38: resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} engines: {node: ^10 || ^12 || >=14} @@ -5482,29 +5131,6 @@ packages: hash-base: 3.1.0 inherits: 2.0.4 - /rollup@4.13.0: - resolution: {integrity: sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - dependencies: - '@types/estree': 1.0.5 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.13.0 - '@rollup/rollup-android-arm64': 4.13.0 - '@rollup/rollup-darwin-arm64': 4.13.0 - '@rollup/rollup-darwin-x64': 4.13.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.13.0 - '@rollup/rollup-linux-arm64-gnu': 4.13.0 - '@rollup/rollup-linux-arm64-musl': 4.13.0 - '@rollup/rollup-linux-riscv64-gnu': 4.13.0 - '@rollup/rollup-linux-x64-gnu': 4.13.0 - '@rollup/rollup-linux-x64-musl': 4.13.0 - '@rollup/rollup-win32-arm64-msvc': 4.13.0 - '@rollup/rollup-win32-ia32-msvc': 4.13.0 - '@rollup/rollup-win32-x64-msvc': 4.13.0 - fsevents: 2.3.3 - dev: true - /rollup@4.13.2: resolution: {integrity: sha512-MIlLgsdMprDBXC+4hsPgzWUasLO9CE4zOkj/u6j+Z6j5A4zRY+CtiXAdJyPtgCsc42g658Aeh1DlrdVEJhsL2g==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -5721,6 +5347,7 @@ packages: /source-map-js@1.1.0: resolution: {integrity: sha512-9vC2SfsJzlej6MAaMPLu8HiBSHGdRAJ9hVFYN1ibZoNkeanmDmLUcIrj6G9DGL7XMJ54AKg/G75akXl1/izTOw==} engines: {node: '>=0.10.0'} + dev: false /source-map-js@1.2.0: resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} @@ -6322,7 +5949,7 @@ packages: debug: 4.3.4 pathe: 1.1.2 picocolors: 1.0.0 - vite: 5.2.7(@types/node@20.12.2) + vite: 5.2.11(@types/node@20.12.2) transitivePeerDependencies: - '@types/node' - less @@ -6334,56 +5961,20 @@ packages: - terser dev: true - /vite-plugin-node-polyfills@0.21.0(vite@5.1.4): + /vite-plugin-node-polyfills@0.21.0(vite@5.2.11): resolution: {integrity: sha512-Sk4DiKnmxN8E0vhgEhzLudfJQfaT8k4/gJ25xvUPG54KjLJ6HAmDKbr4rzDD/QWEY+Lwg80KE85fGYBQihEPQA==} peerDependencies: vite: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 dependencies: '@rollup/plugin-inject': 5.0.5 node-stdlib-browser: 1.2.0 - vite: 5.1.4(@types/node@20.12.2) + vite: 5.2.11(@types/node@20.12.2) transitivePeerDependencies: - rollup dev: true - /vite@5.1.4(@types/node@20.12.2): - resolution: {integrity: sha512-n+MPqzq+d9nMVTKyewqw6kSt+R3CkvF9QAKY8obiQn8g1fwTscKxyfaYnC632HtBXAQGc1Yjomphwn1dtwGAHg==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || >=20.0.0 - less: '*' - lightningcss: ^1.21.0 - sass: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - dependencies: - '@types/node': 20.12.2 - esbuild: 0.19.12 - postcss: 8.4.36 - rollup: 4.13.0 - optionalDependencies: - fsevents: 2.3.3 - dev: true - - /vite@5.2.7(@types/node@20.12.2): - resolution: {integrity: sha512-k14PWOKLI6pMaSzAuGtT+Cf0YmIx12z9YGon39onaJNy8DLBfBJrzg9FQEmkAM5lpHBZs9wksWAsyF/HkpEwJA==} + /vite@5.2.11(@types/node@20.12.2): + resolution: {integrity: sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -6461,7 +6052,7 @@ packages: strip-literal: 2.1.0 tinybench: 2.6.0 tinypool: 0.8.3 - vite: 5.2.7(@types/node@20.12.2) + vite: 5.2.11(@types/node@20.12.2) vite-node: 1.4.0(@types/node@20.12.2) why-is-node-running: 2.2.2 transitivePeerDependencies: From a9b9796f5ef8d27a9ad94d09a832bb9a7fe56c8e Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Thu, 9 May 2024 20:37:52 +0800 Subject: [PATCH 09/78] chore: Update changeset --- .changeset/large-nails-greet.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/large-nails-greet.md diff --git a/.changeset/large-nails-greet.md b/.changeset/large-nails-greet.md new file mode 100644 index 00000000..05b46c33 --- /dev/null +++ b/.changeset/large-nails-greet.md @@ -0,0 +1,5 @@ +--- +"@rgbpp-sdk/ckb": minor +--- + +refactor: Collect all RGB++ inputs without isMax parameter From 664b13f1ed4faec18d050555289b0087c638fdf6 Mon Sep 17 00:00:00 2001 From: Shook Date: Fri, 10 May 2024 11:24:45 +0800 Subject: [PATCH 10/78] feat: export BtcAssetsApiError in rgbpp/index.ts --- packages/rgbpp/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rgbpp/src/index.ts b/packages/rgbpp/src/index.ts index d1bed25d..fb5988ce 100644 --- a/packages/rgbpp/src/index.ts +++ b/packages/rgbpp/src/index.ts @@ -37,7 +37,7 @@ export type { /** * service */ -export { BtcAssetsApi } from '@rgbpp-sdk/service'; +export { BtcAssetsApi, BtcAssetsApiError } from '@rgbpp-sdk/service'; /** * btc From d8d1f895f8bb7247edea46014bc23d93c582c7fe Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Fri, 10 May 2024 14:22:46 +0800 Subject: [PATCH 11/78] docs: Remove rgbpp package from README --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 9734d66d..b49a837b 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ This repository offers utilities for Bitcoin and RGB++ asset integration. ### Packages in this repository -- [rgbpp](./packages/rgbpp): A root package to integrate of common functions from the RGB++ SDK sub-packages(btc/ckb/service). - [@rgbpp-sdk/btc](./packages/btc): Bitcoin part of the SDK - [@rgbpp-sdk/ckb](./packages/ckb): Nervos CKB part of the SDK - [@rgbpp-sdk/service](./packages/service): A wrapped class to interact with `Bitcoin/RGB++ Assets Service` From db1cdf18e6ced49d9199befcbf78d87c391f795b Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Fri, 10 May 2024 14:57:09 +0800 Subject: [PATCH 12/78] fix: Update sub path for related packages --- packages/rgbpp/src/ckb.ts | 2 +- packages/rgbpp/src/service.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rgbpp/src/ckb.ts b/packages/rgbpp/src/ckb.ts index 550abcff..8232ce2c 100644 --- a/packages/rgbpp/src/ckb.ts +++ b/packages/rgbpp/src/ckb.ts @@ -1 +1 @@ -export * from '@rgbpp-sdk/service'; +export * from '@rgbpp-sdk/ckb'; diff --git a/packages/rgbpp/src/service.ts b/packages/rgbpp/src/service.ts index 749dca24..550abcff 100644 --- a/packages/rgbpp/src/service.ts +++ b/packages/rgbpp/src/service.ts @@ -1 +1 @@ -export * from '@rgbpp-sdk/btc'; +export * from '@rgbpp-sdk/service'; From 20215e121b70aaf638a3303df40c0bcd26ee2f79 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Fri, 10 May 2024 15:13:48 +0800 Subject: [PATCH 13/78] chore: Update changeset --- .changeset/flat-starfishes-confess.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/flat-starfishes-confess.md diff --git a/.changeset/flat-starfishes-confess.md b/.changeset/flat-starfishes-confess.md new file mode 100644 index 00000000..6040e217 --- /dev/null +++ b/.changeset/flat-starfishes-confess.md @@ -0,0 +1,5 @@ +--- +"rgbpp": major +--- + +feat: Add rgbpp sub package From 7abf72b03b933e9bdb55f8408ed6033017192412 Mon Sep 17 00:00:00 2001 From: Shook Date: Fri, 10 May 2024 15:16:26 +0800 Subject: [PATCH 14/78] chore: link rgbpp version as other @rgbpp-sdk/* packages --- .changeset/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/config.json b/.changeset/config.json index cc1698ea..d0a8cd83 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -2,7 +2,7 @@ "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json", "changelog": ["@changesets/changelog-github", { "repo": "ckb-cell/rgbpp-sdk" }], "commit": false, - "fixed": [["@rgbpp-sdk/*"]], + "fixed": [["@rgbpp-sdk/*", "rgbpp"]], "linked": [], "access": "public", "baseBranch": "main", From 58f8dff2322793500bd7f822c1a2fe8af9d78889 Mon Sep 17 00:00:00 2001 From: Shook Date: Fri, 10 May 2024 15:18:52 +0800 Subject: [PATCH 15/78] refactor: use "workspace:*" as comparator for @rgbpp-sdk/* dependencies --- packages/rgbpp/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/rgbpp/package.json b/packages/rgbpp/package.json index cad776f9..517e6649 100644 --- a/packages/rgbpp/package.json +++ b/packages/rgbpp/package.json @@ -34,9 +34,9 @@ ], "types": "./lib/index.d.ts", "dependencies": { - "@rgbpp-sdk/btc": "workspace", - "@rgbpp-sdk/ckb": "workspace", - "@rgbpp-sdk/service": "workspace" + "@rgbpp-sdk/btc": "workspace:*", + "@rgbpp-sdk/ckb": "workspace:*", + "@rgbpp-sdk/service": "workspace:*" }, "publishConfig": { "access": "public" From 8231d8c750bfb63ac27193152dd120348063ea1e Mon Sep 17 00:00:00 2001 From: Shook Date: Fri, 10 May 2024 15:29:27 +0800 Subject: [PATCH 16/78] chore: update pnpm-lock.yaml --- pnpm-lock.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a8e05f10..5b9effb8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -251,13 +251,13 @@ importers: packages/rgbpp: dependencies: '@rgbpp-sdk/btc': - specifier: workspace + specifier: workspace:* version: link:../btc '@rgbpp-sdk/ckb': - specifier: workspace + specifier: workspace:* version: link:../ckb '@rgbpp-sdk/service': - specifier: workspace + specifier: workspace:* version: link:../service packages/service: From d37cf5b1aaf50f42a2f900f9b6aa073a916840b2 Mon Sep 17 00:00:00 2001 From: Shook <44739165+ShookLyngs@users.noreply.github.com> Date: Sat, 11 May 2024 11:45:52 +0800 Subject: [PATCH 17/78] fix: message of INSUFFICIENT_UTXO error when collected < targetAmount (#166) --- .changeset/slimy-rockets-watch.md | 5 +++++ packages/btc/src/transaction/build.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/slimy-rockets-watch.md diff --git a/.changeset/slimy-rockets-watch.md b/.changeset/slimy-rockets-watch.md new file mode 100644 index 00000000..10201d25 --- /dev/null +++ b/.changeset/slimy-rockets-watch.md @@ -0,0 +1,5 @@ +--- +"@rgbpp-sdk/btc": patch +--- + +Fix the message of INSUFFICIENT_UTXO error when collection failed diff --git a/packages/btc/src/transaction/build.ts b/packages/btc/src/transaction/build.ts index 9e8451c6..9ff8de23 100644 --- a/packages/btc/src/transaction/build.ts +++ b/packages/btc/src/transaction/build.ts @@ -310,7 +310,7 @@ export class TxBuilder { // If not collected enough satoshi, throw error const insufficientBalance = collected < targetAmount; if (insufficientBalance) { - const recommendedDeposit = collected - targetAmount + this.minUtxoSatoshi; + const recommendedDeposit = targetAmount - collected + this.minUtxoSatoshi; throw TxBuildError.withComment( ErrorCodes.INSUFFICIENT_UTXO, `expected: ${targetAmount}, actual: ${collected}. You may wanna deposit more satoshi to prevent the error, for example: ${recommendedDeposit}`, From 601741bfd3e23fa624071b767237fe89a8507dd1 Mon Sep 17 00:00:00 2001 From: Shook <44739165+ShookLyngs@users.noreply.github.com> Date: Sat, 11 May 2024 15:12:14 +0800 Subject: [PATCH 18/78] chore: rename env vars "SERVICE_*" -> "BTC_SERVICE_*" (#164) --- .github/workflows/test.yaml | 6 +++--- apps/next/.env.example | 4 ++-- apps/next/src/app/page.tsx | 4 ++-- apps/vite/.env.example | 4 ++-- apps/vite/src/App.tsx | 5 ++++- packages/btc/.env.example | 6 +++--- packages/btc/tests/shared/env.ts | 6 +++--- packages/service/.env.example | 6 +++--- packages/service/tests/Service.test.ts | 12 ++++++------ 9 files changed, 28 insertions(+), 25 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 5240d084..1fb20fed 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -52,6 +52,6 @@ jobs: - name: Run tests for packages run: pnpm run test:packages env: - VITE_SERVICE_URL: ${{ secrets.SERVICE_URL }} - VITE_SERVICE_TOKEN: ${{ secrets.SERVICE_TOKEN }} - VITE_SERVICE_ORIGIN: ${{ secrets.SERVICE_ORIGIN }} + VITE_BTC_SERVICE_URL: ${{ secrets.SERVICE_URL }} + VITE_BTC_SERVICE_TOKEN: ${{ secrets.SERVICE_TOKEN }} + VITE_BTC_SERVICE_ORIGIN: ${{ secrets.SERVICE_ORIGIN }} diff --git a/apps/next/.env.example b/apps/next/.env.example index 126ccc3d..22e91499 100644 --- a/apps/next/.env.example +++ b/apps/next/.env.example @@ -1,2 +1,2 @@ -NEXT_PUBLIC_SERVICE_URL= -NEXT_PUBLIC_SERVICE_TOKEN= +NEXT_PUBLIC_BTC_SERVICE_URL= +NEXT_PUBLIC_BTC_SERVICE_TOKEN= diff --git a/apps/next/src/app/page.tsx b/apps/next/src/app/page.tsx index 10cdf1b4..f68107e2 100644 --- a/apps/next/src/app/page.tsx +++ b/apps/next/src/app/page.tsx @@ -7,8 +7,8 @@ export default function Home() { const networkType = NetworkType.TESTNET; const service = BtcAssetsApi.fromToken( - process.env.NEXT_PUBLIC_SERVICE_URL!, - process.env.NEXT_PUBLIC_SERVICE_TOKEN!, + process.env.NEXT_PUBLIC_BTC_SERVICE_URL!, + process.env.NEXT_PUBLIC_BTC_SERVICE_TOKEN!, ); const source = new DataSource(service, networkType); diff --git a/apps/vite/.env.example b/apps/vite/.env.example index 2b514fe0..23e23fcf 100644 --- a/apps/vite/.env.example +++ b/apps/vite/.env.example @@ -1,2 +1,2 @@ -VITE_SERVICE_URL= -VITE_SERVICE_TOKEN= \ No newline at end of file +VITE_BTC_SERVICE_URL= +VITE_BTC_SERVICE_TOKEN= diff --git a/apps/vite/src/App.tsx b/apps/vite/src/App.tsx index 9a28c179..02edecef 100644 --- a/apps/vite/src/App.tsx +++ b/apps/vite/src/App.tsx @@ -6,7 +6,10 @@ function App() { async function send() { const networkType = NetworkType.TESTNET; - const service = BtcAssetsApi.fromToken(import.meta.env.VITE_SERVICE_URL!, import.meta.env.VITE_SERVICE_TOKEN!); + const service = BtcAssetsApi.fromToken( + import.meta.env.VITE_BTC_SERVICE_URL!, + import.meta.env.VITE_BTC_SERVICE_TOKEN!, + ); const source = new DataSource(service, networkType); const psbt = await sendBtc({ diff --git a/packages/btc/.env.example b/packages/btc/.env.example index df8eb3d3..15c08d44 100644 --- a/packages/btc/.env.example +++ b/packages/btc/.env.example @@ -1,3 +1,3 @@ -VITE_SERVICE_URL= # URL of the service -VITE_SERVICE_TOKEN= # JWT token to access the service -VITE_SERVICE_ORIGIN= # URL representing your token's domain +VITE_BTC_SERVICE_URL= # URL of the service +VITE_BTC_SERVICE_TOKEN= # JWT token to access the service +VITE_BTC_SERVICE_ORIGIN= # URL representing your token's domain diff --git a/packages/btc/tests/shared/env.ts b/packages/btc/tests/shared/env.ts index 79c6e203..195a200b 100644 --- a/packages/btc/tests/shared/env.ts +++ b/packages/btc/tests/shared/env.ts @@ -6,9 +6,9 @@ export const config = networkTypeToConfig(networkType); export const network = config.network; export const service = BtcAssetsApi.fromToken( - process.env.VITE_SERVICE_URL!, - process.env.VITE_SERVICE_TOKEN!, - process.env.VITE_SERVICE_ORIGIN!, + process.env.VITE_BTC_SERVICE_URL!, + process.env.VITE_BTC_SERVICE_TOKEN!, + process.env.VITE_BTC_SERVICE_ORIGIN!, ); export const source = new DataSource(service, networkType); diff --git a/packages/service/.env.example b/packages/service/.env.example index df8eb3d3..15c08d44 100644 --- a/packages/service/.env.example +++ b/packages/service/.env.example @@ -1,3 +1,3 @@ -VITE_SERVICE_URL= # URL of the service -VITE_SERVICE_TOKEN= # JWT token to access the service -VITE_SERVICE_ORIGIN= # URL representing your token's domain +VITE_BTC_SERVICE_URL= # URL of the service +VITE_BTC_SERVICE_TOKEN= # JWT token to access the service +VITE_BTC_SERVICE_ORIGIN= # URL representing your token's domain diff --git a/packages/service/tests/Service.test.ts b/packages/service/tests/Service.test.ts index edfd0910..1bb509cf 100644 --- a/packages/service/tests/Service.test.ts +++ b/packages/service/tests/Service.test.ts @@ -11,15 +11,15 @@ describe( () => { const btcAddress = 'tb1qm06rvrq8jyyckzc5v709u7qpthel9j4d9f7nh3'; const service = BtcAssetsApi.fromToken( - process.env.VITE_SERVICE_URL!, - process.env.VITE_SERVICE_TOKEN!, - process.env.VITE_SERVICE_ORIGIN!, + process.env.VITE_BTC_SERVICE_URL!, + process.env.VITE_BTC_SERVICE_TOKEN!, + process.env.VITE_BTC_SERVICE_ORIGIN!, ); describe('Initiation and token generation', () => { it('Generate a valid token', async () => { const serviceWithApp = new BtcAssetsApi({ - url: process.env.VITE_SERVICE_URL!, + url: process.env.VITE_BTC_SERVICE_URL!, app: 'btc-test-app', domain: 'btc-test.app', origin: 'https://btc-test.app', @@ -36,14 +36,14 @@ describe( expect( () => new BtcAssetsApi({ - url: process.env.VITE_SERVICE_URL!, + url: process.env.VITE_BTC_SERVICE_URL!, domain: 'https://btc-test.app', }), ).toThrow(`${ErrorMessages[ErrorCodes.ASSETS_API_INVALID_PARAM]}: domain`); }); it('Try generate token without the "app" param', async () => { const serviceWithoutApp = new BtcAssetsApi({ - url: process.env.VITE_SERVICE_URL!, + url: process.env.VITE_BTC_SERVICE_URL!, domain: 'btc-test.app', }); From 9332adba1d7b34a5ca4c56433bb61f7fc040fdf8 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Sat, 11 May 2024 15:04:48 +0800 Subject: [PATCH 19/78] fix: Check rgbpp capacity for change and paymaster cell --- packages/ckb/src/rgbpp/btc-jump-ckb.ts | 15 +++++++++------ packages/ckb/src/rgbpp/btc-transfer.ts | 15 +++++++++------ packages/ckb/src/utils/rgbpp.spec.ts | 13 +++++++++++++ packages/ckb/src/utils/rgbpp.ts | 11 ++++++++++- 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/packages/ckb/src/rgbpp/btc-jump-ckb.ts b/packages/ckb/src/rgbpp/btc-jump-ckb.ts index 7fd2538b..6e3de3e4 100644 --- a/packages/ckb/src/rgbpp/btc-jump-ckb.ts +++ b/packages/ckb/src/rgbpp/btc-jump-ckb.ts @@ -20,6 +20,7 @@ import { genBtcTimeLockScript, genRgbppLockScript, throwErrorWhenRgbppCellsInvalid, + isRgbppCapacitySufficientForChange, } from '../utils/rgbpp'; import { Hex, IndexerCell } from '../types'; import { @@ -95,9 +96,10 @@ export const genBtcJumpCkbVirtualTx = async ({ throw new Error('The lock script size of the to ckb address is too large'); } - const needChange = sumAmount > transferAmount; + let needPaymasterCell = false; + const needRgbppChange = sumAmount > transferAmount; // To simplify, when the xUDT does not need change, all the capacity of the inputs will be given to the receiver - const receiverOutputCapacity = needChange ? BigInt(rgbppTargetCells[0].output.capacity) : sumInputsCapacity; + const receiverOutputCapacity = needRgbppChange ? BigInt(rgbppTargetCells[0].output.capacity) : sumInputsCapacity; // The BTC time cell does not need to be bound to the BTC UTXO const outputs: CKBComponents.CellOutput[] = [ { @@ -108,9 +110,11 @@ export const genBtcJumpCkbVirtualTx = async ({ ]; const outputsData = [append0x(u128ToLe(transferAmount))]; - if (needChange) { - // When the number of sender's inputs is greater than 1, the sender needs to recover the excess capacity. - const udtChangeCapacity = inputs.length > 1 ? sumInputsCapacity - receiverOutputCapacity : rgbppCellCapacity; + if (needRgbppChange) { + const isCapacitySufficient = isRgbppCapacitySufficientForChange(sumInputsCapacity, receiverOutputCapacity); + needPaymasterCell = !isCapacitySufficient; + // When the capacity of inputs is enough for the outputs, the sender needs to recover the excess capacity. + const udtChangeCapacity = isCapacitySufficient ? sumInputsCapacity - receiverOutputCapacity : rgbppCellCapacity; outputs.push({ // The Vouts[0] for OP_RETURN and Vouts[1] for RGBPP assets, BTC time cells don't need btc tx out_index lock: genRgbppLockScript(buildPreLockArgs(1), isMainnet), @@ -136,7 +140,6 @@ export const genBtcJumpCkbVirtualTx = async ({ } const cellDeps = [getRgbppLockDep(isMainnet), getXudtDep(isMainnet), getRgbppLockConfigDep(isMainnet)]; - const needPaymasterCell = inputs.length < outputs.length; if (needPaymasterCell) { cellDeps.push(getSecp256k1CellDep(isMainnet)); } diff --git a/packages/ckb/src/rgbpp/btc-transfer.ts b/packages/ckb/src/rgbpp/btc-transfer.ts index ab5a59a1..dd53fbaf 100644 --- a/packages/ckb/src/rgbpp/btc-transfer.ts +++ b/packages/ckb/src/rgbpp/btc-transfer.ts @@ -23,6 +23,7 @@ import { compareInputs, estimateWitnessSize, genRgbppLockScript, + isRgbppCapacitySufficientForChange, throwErrorWhenRgbppCellsInvalid, throwErrorWhenTxInputsExceeded, } from '../utils/rgbpp'; @@ -96,6 +97,7 @@ export const genBtcTransferCkbVirtualTx = async ({ let sumInputsCapacity = BigInt(0); const outputs: CKBComponents.CellOutput[] = []; const outputsData: Hex[] = []; + let needPaymasterCell = false; // The non-target RGBPP outputs correspond to the RGBPP inputs one-to-one, and the outputs are still bound to the sender’s BTC UTXOs const handleNonTargetRgbppCells = (targetRgbppOutputLen: number) => { @@ -142,9 +144,9 @@ export const genBtcTransferCkbVirtualTx = async ({ const rgbppCellCapacity = calculateRgbppCellCapacity(xudtType); - const needChange = collectResult.sumAmount > transferAmount; + const needRgbppChange = collectResult.sumAmount > transferAmount; // To simplify, when the xUDT does not need change, all the capacity of the inputs will be given to the receiver - const receiverOutputCapacity = needChange ? BigInt(rgbppTargetCells[0].output.capacity) : sumInputsCapacity; + const receiverOutputCapacity = needRgbppChange ? BigInt(rgbppTargetCells[0].output.capacity) : sumInputsCapacity; // The Vouts[0] for OP_RETURN and Vouts[1] for target transfer RGBPP assets outputs.push({ lock: genRgbppLockScript(buildPreLockArgs(1), isMainnet), @@ -153,9 +155,11 @@ export const genBtcTransferCkbVirtualTx = async ({ }); outputsData.push(append0x(u128ToLe(transferAmount))); - if (needChange) { - // When the number of sender's inputs is greater than 1, the sender needs to recover the excess capacity. - const udtChangeCapacity = inputs.length > 1 ? sumInputsCapacity - receiverOutputCapacity : rgbppCellCapacity; + if (needRgbppChange) { + const isCapacitySufficient = isRgbppCapacitySufficientForChange(sumInputsCapacity, receiverOutputCapacity); + needPaymasterCell = !isCapacitySufficient; + // When the capacity of inputs is enough for the outputs, the sender needs to recover the excess capacity. + const udtChangeCapacity = isCapacitySufficient ? sumInputsCapacity - receiverOutputCapacity : rgbppCellCapacity; // The Vouts[2] for target change RGBPP assets outputs.push({ lock: genRgbppLockScript(buildPreLockArgs(2), isMainnet), @@ -169,7 +173,6 @@ export const genBtcTransferCkbVirtualTx = async ({ } const cellDeps = [getRgbppLockDep(isMainnet), getXudtDep(isMainnet), getRgbppLockConfigDep(isMainnet)]; - const needPaymasterCell = inputs.length < outputs.length; if (needPaymasterCell) { cellDeps.push(getSecp256k1CellDep(isMainnet)); } diff --git a/packages/ckb/src/utils/rgbpp.spec.ts b/packages/ckb/src/utils/rgbpp.spec.ts index e4c720a0..560ce034 100644 --- a/packages/ckb/src/utils/rgbpp.spec.ts +++ b/packages/ckb/src/utils/rgbpp.spec.ts @@ -16,6 +16,7 @@ import { transformSpvProof, throwErrorWhenTxInputsExceeded, throwErrorWhenRgbppCellsInvalid, + isRgbppCapacitySufficientForChange, } from './rgbpp'; import { getXudtTypeScript } from '../constants'; import { IndexerCell, RgbppCkbVirtualTx } from '../types'; @@ -376,4 +377,16 @@ describe('rgbpp tests', () => { } } }); + + it('isRgbppCapacityEnoughForChange', () => { + expect(false).toBe( + isRgbppCapacitySufficientForChange(BigInt(500) * BigInt(10000_0000), BigInt(254) * BigInt(10000_0000)), + ); + expect(false).toBe( + isRgbppCapacitySufficientForChange(BigInt(507) * BigInt(10000_0000), BigInt(254) * BigInt(10000_0000)), + ); + expect(true).toBe( + isRgbppCapacitySufficientForChange(BigInt(508) * BigInt(10000_0000), BigInt(254) * BigInt(10000_0000)), + ); + }); }); diff --git a/packages/ckb/src/utils/rgbpp.ts b/packages/ckb/src/utils/rgbpp.ts index 684cab7c..842d544b 100644 --- a/packages/ckb/src/utils/rgbpp.ts +++ b/packages/ckb/src/utils/rgbpp.ts @@ -3,6 +3,7 @@ import { Hex, IndexerCell, RgbppCkbVirtualTx, RgbppTokenInfo, SpvClientCellTxPro import { append0x, remove0x, reverseHex, u32ToLe, u8ToHex, utf8ToHex } from './hex'; import { BTC_JUMP_CONFIRMATION_BLOCKS, + CKB_UNIT, RGBPP_TX_ID_PLACEHOLDER, RGBPP_TX_INPUTS_MAX_LENGTH, RGBPP_TX_WITNESS_MAX_SIZE, @@ -28,7 +29,7 @@ import { RgbppCkbTxInputsExceededError, RgbppUtxoBindMultiTypeAssetsError, } from '../error'; -import { isScriptEqual, isUDTTypeSupported } from './ckb-tx'; +import { calculateRgbppCellCapacity, isScriptEqual, isUDTTypeSupported } from './ckb-tx'; export const genRgbppLockScript = (rgbppLockArgs: Hex, isMainnet: boolean) => { return { @@ -253,3 +254,11 @@ export const throwErrorWhenRgbppCellsInvalid = ( throw new NoRgbppLiveCellError('No rgbpp cells found with the xudt type script and the rgbpp lock args'); } }; + +export const isRgbppCapacitySufficientForChange = ( + sumUdtInputsCapacity: bigint, + receiverOutputCapacity: bigint, +): boolean => { + const rgbppOccupiedCapacity = calculateRgbppCellCapacity() - CKB_UNIT; + return sumUdtInputsCapacity > receiverOutputCapacity + rgbppOccupiedCapacity; +}; From e59322e7c6b9aff682bc1c8517337e3611dc122d Mon Sep 17 00:00:00 2001 From: Shook Date: Sat, 11 May 2024 01:28:04 +0800 Subject: [PATCH 20/78] style: replace all "void 0" to "undefined" --- .changeset/silly-emus-raise.md | 6 ++++++ packages/btc/src/address.ts | 8 ++++---- packages/btc/src/query/source.ts | 4 ++-- packages/btc/src/utils.ts | 2 +- packages/service/src/error.ts | 2 +- packages/service/src/service/base.ts | 10 +++++----- 6 files changed, 19 insertions(+), 13 deletions(-) create mode 100644 .changeset/silly-emus-raise.md diff --git a/.changeset/silly-emus-raise.md b/.changeset/silly-emus-raise.md new file mode 100644 index 00000000..4f113c3b --- /dev/null +++ b/.changeset/silly-emus-raise.md @@ -0,0 +1,6 @@ +--- +"@rgbpp-sdk/service": minor +"@rgbpp-sdk/btc": minor +--- + +Replace all "void 0" to "undefined" in the btc/service lib diff --git a/packages/btc/src/address.ts b/packages/btc/src/address.ts index cbde4b6a..fa562d45 100644 --- a/packages/btc/src/address.ts +++ b/packages/btc/src/address.ts @@ -28,7 +28,7 @@ export function isSupportedFromAddress(address: string) { */ export function publicKeyToPayment(publicKey: string, addressType: AddressType, networkType: NetworkType) { if (!publicKey) { - return void 0; + return undefined; } const network = networkTypeToNetwork(networkType); @@ -64,7 +64,7 @@ export function publicKeyToPayment(publicKey: string, addressType: AddressType, }); } - return void 0; + return undefined; } /** @@ -147,7 +147,7 @@ export function decodeAddress(address: string): { addressType = AddressType.P2TR; } } - if (networkType !== void 0 && addressType !== void 0) { + if (networkType !== undefined && addressType !== undefined) { return { networkType, addressType, @@ -182,7 +182,7 @@ export function decodeAddress(address: string): { addressType = AddressType.P2SH_P2WPKH; } - if (networkType !== void 0 && addressType !== void 0) { + if (networkType !== undefined && addressType !== undefined) { return { networkType, addressType, diff --git a/packages/btc/src/query/source.ts b/packages/btc/src/query/source.ts index f5a0f536..d350afc1 100644 --- a/packages/btc/src/query/source.ts +++ b/packages/btc/src/query/source.ts @@ -35,14 +35,14 @@ export class DataSource { const txId = remove0x(hash); const tx = await this.service.getBtcTransaction(txId); if (!tx) { - return void 0; + return undefined; } if (requireConfirmed && !tx.status.confirmed) { throw TxBuildError.withComment(ErrorCodes.UNCONFIRMED_UTXO, `hash: ${hash}, index: ${index}`); } const vout = tx.vout[index]; if (!vout) { - return void 0; + return undefined; } const scriptBuffer = Buffer.from(vout.scriptpubkey, 'hex'); diff --git a/packages/btc/src/utils.ts b/packages/btc/src/utils.ts index c9b29896..bc63977f 100644 --- a/packages/btc/src/utils.ts +++ b/packages/btc/src/utils.ts @@ -72,6 +72,6 @@ export function utf8ToBuffer(text: string): Uint8Array { * Note if using for RGBPP proof, shouldn't set the "withWitness" param to "true". */ export function transactionToHex(tx: bitcoin.Transaction, withWitness?: boolean): string { - const buffer: Buffer = tx['__toBuffer'](void 0, void 0, withWitness ?? false); + const buffer: Buffer = tx['__toBuffer'](undefined, undefined, withWitness ?? false); return buffer.toString('hex'); } diff --git a/packages/service/src/error.ts b/packages/service/src/error.ts index fcb6c34f..e1da2e1a 100644 --- a/packages/service/src/error.ts +++ b/packages/service/src/error.ts @@ -37,7 +37,7 @@ export class BtcAssetsApiError extends Error { static withComment(code: ErrorCodes, comment?: string, context?: BtcAssetsApiContext): BtcAssetsApiError { const prefixMessage = ErrorMessages[code] ?? ErrorMessages[ErrorCodes.UNKNOWN]; - const message = comment ? `${prefixMessage}: ${comment}` : void 0; + const message = comment ? `${prefixMessage}: ${comment}` : undefined; return new BtcAssetsApiError({ code, message, context }); } } diff --git a/packages/service/src/service/base.ts b/packages/service/src/service/base.ts index 5a1ece03..b8bab5cd 100644 --- a/packages/service/src/service/base.ts +++ b/packages/service/src/service/base.ts @@ -33,8 +33,8 @@ export class BtcAssetsApiBase implements BaseApis { } const packedParams = params ? '?' + new URLSearchParams(pickBy(params, (val) => val !== undefined)).toString() : ''; - const withOriginHeaders = this.origin ? { origin: this.origin } : void 0; - const withAuthHeaders = requireToken && this.token ? { Authorization: `Bearer ${this.token}` } : void 0; + const withOriginHeaders = this.origin ? { origin: this.origin } : undefined; + const withAuthHeaders = requireToken && this.token ? { Authorization: `Bearer ${this.token}` } : undefined; const url = `${this.url}${route}${packedParams}`; const res = await fetch(url, { method, @@ -97,7 +97,7 @@ export class BtcAssetsApiBase implements BaseApis { throw BtcAssetsApiError.withComment(ErrorCodes.ASSETS_API_RESPONSE_ERROR, comment, context); } if (status !== 200) { - return void 0 as T; + return undefined as T; } return json! as T; @@ -141,8 +141,8 @@ export class BtcAssetsApiBase implements BaseApis { function tryParseBody(body: unknown): Record | undefined { try { - return typeof body === 'string' ? JSON.parse(body) : void 0; + return typeof body === 'string' ? JSON.parse(body) : undefined; } catch { - return void 0; + return undefined; } } From 84ee5ad4e35af7daa4318847a1116b0a068f874c Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Mon, 13 May 2024 14:37:34 +0800 Subject: [PATCH 21/78] feat: Add checkCkbTxInputsCapacitySufficient function --- packages/ckb/src/utils/ckb-tx.spec.ts | 124 +++++++++++++++++++++++++- packages/ckb/src/utils/ckb-tx.ts | 26 ++++++ packages/ckb/src/utils/rgbpp.ts | 3 + 3 files changed, 152 insertions(+), 1 deletion(-) diff --git a/packages/ckb/src/utils/ckb-tx.spec.ts b/packages/ckb/src/utils/ckb-tx.spec.ts index efe37556..3ff2d3fc 100644 --- a/packages/ckb/src/utils/ckb-tx.spec.ts +++ b/packages/ckb/src/utils/ckb-tx.spec.ts @@ -10,9 +10,12 @@ import { isLockArgsSizeExceeded, isScriptEqual, isTypeAssetSupported, + checkCkbTxInputsCapacitySufficient, } from './ckb-tx'; -import { utf8ToHex } from '.'; import { hexToBytes } from '@nervosnetwork/ckb-sdk-utils'; +import { Collector } from '../collector'; +import { NoLiveCellError } from '../error'; +import { utf8ToHex } from './hex'; describe('ckb tx utils', () => { it('calculateTransactionFee', () => { @@ -168,4 +171,123 @@ describe('ckb tx utils', () => { ), ); }); + + it('checkCkbTxInputsCapacitySufficient', { timeout: 20000 }, async () => { + const collector = new Collector({ + ckbNodeUrl: 'https://testnet.ckb.dev/rpc', + ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', + }); + const ckbTxWithDeadCell: CKBComponents.RawTransaction = { + cellDeps: [], + headerDeps: [], + inputs: [ + { + previousOutput: { + index: '0x1', + txHash: '0x1a6d2b18faed84293b81ada9d00600a3cdb637fa43a5cfa20eb63934757352ea', + }, + since: '0x0', + }, + ], + outputs: [ + { + capacity: '0x5e9f53e00', + lock: { + args: '0x01000000850cf65f93ed86e53044e94049ae76115ab25a4897de9247f947d390dcf4a4fc', + codeHash: '0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248', + hashType: 'type', + }, + type: { + args: '0x6b6a9580fc2aceb920c63adea27a667acfc180f67cf875b36f31b42546ac4920', + codeHash: '0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb', + hashType: 'type', + }, + }, + ], + outputsData: ['0x00743ba40b0000000000000000000000'], + version: '0x0', + witnesses: [], + }; + try { + await checkCkbTxInputsCapacitySufficient(ckbTxWithDeadCell, collector); + } catch (error) { + if (error instanceof NoLiveCellError) { + expect(102).toBe(error.code); + expect('The cell with the specific out point is dead').toBe(error.message); + } + } + + const invalidCkbTx: CKBComponents.RawTransaction = { + cellDeps: [], + headerDeps: [], + inputs: [ + { + previousOutput: { + index: '0x0', + txHash: '0xeb6ea53459efc83755e4ede6ff54b7698913379e678c6018e1eac87241f964f2', + }, + since: '0x0', + }, + { + previousOutput: { + index: '0x0', + txHash: '0x80314ab559ddc7b2f9e523f968b2d930b1a7b53f690091e6666570b46f54b804', + }, + since: '0x0', + }, + ], + outputs: [ + { + capacity: '0x65e9f53e00', + lock: { + args: '0x01000000850cf65f93ed86e53044e94049ae76115ab25a4897de9247f947d390dcf4a4fc', + codeHash: '0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248', + hashType: 'type', + }, + type: { + args: '0x6b6a9580fc2aceb920c63adea27a667acfc180f67cf875b36f31b42546ac4920', + codeHash: '0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb', + hashType: 'type', + }, + }, + ], + outputsData: ['0x00743ba40b0000000000000000000000'], + version: '0x0', + witnesses: [], + }; + expect(false).toBe(await checkCkbTxInputsCapacitySufficient(invalidCkbTx, collector)); + + const ckbTx: CKBComponents.RawTransaction = { + cellDeps: [], + headerDeps: [], + inputs: [ + { + previousOutput: { + index: '0x0', + txHash: '0xeb6ea53459efc83755e4ede6ff54b7698913379e678c6018e1eac87241f964f2', + }, + since: '0x0', + }, + ], + outputs: [ + { + capacity: '0x5e9f53e00', + lock: { + args: '0x01000000850cf65f93ed86e53044e94049ae76115ab25a4897de9247f947d390dcf4a4fc', + codeHash: '0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248', + hashType: 'type', + }, + type: { + args: '0x6b6a9580fc2aceb920c63adea27a667acfc180f67cf875b36f31b42546ac4920', + codeHash: '0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb', + hashType: 'type', + }, + }, + ], + outputsData: ['0x00743ba40b0000000000000000000000'], + version: '0x0', + witnesses: [], + }; + expect(true).toBe(await checkCkbTxInputsCapacitySufficient(ckbTx, collector)); + }); }); diff --git a/packages/ckb/src/utils/ckb-tx.ts b/packages/ckb/src/utils/ckb-tx.ts index cc19dfb3..3f333185 100644 --- a/packages/ckb/src/utils/ckb-tx.ts +++ b/packages/ckb/src/utils/ckb-tx.ts @@ -11,6 +11,8 @@ import { import { Hex, RgbppTokenInfo } from '../types'; import { PERSONAL, blake2b, hexToBytes, serializeInput, serializeScript } from '@nervosnetwork/ckb-sdk-utils'; import { encodeRgbppTokenInfo, genBtcTimeLockScript } from './rgbpp'; +import { Collector } from '../collector'; +import { NoLiveCellError } from '../error'; export const calculateTransactionFee = (txSize: number, feeRate?: bigint): bigint => { const rate = feeRate ?? BigInt(1100); @@ -139,3 +141,27 @@ export const isScriptEqual = (s1: Hex | CKBComponents.Script, s2: Hex | CKBCompo const temp2 = typeof s2 === 'string' ? remove0x(s2) : remove0x(serializeScript(s2)); return temp1 === temp2; }; + +/** + * Check whether the capacity of inputs is sufficient for outputs + * @param ckbTx CKB raw transaction + * @param collector The collector that collects CKB live cells and transactions + * @returns When the capacity of inputs is sufficient for outputs, return true, otherwise return false + */ +export const checkCkbTxInputsCapacitySufficient = async ( + ckbTx: CKBComponents.RawTransaction, + collector: Collector, +): Promise => { + let sumInputsCapacity = BigInt(0); + for await (const input of ckbTx.inputs) { + const liveCell = await collector.getLiveCell(input.previousOutput!); + if (!liveCell) { + throw new NoLiveCellError('The cell with the specific out point is dead'); + } + sumInputsCapacity += BigInt(liveCell.output.capacity); + } + const sumOutputsCapacity = ckbTx.outputs + .map((output) => BigInt(output.capacity)) + .reduce((prev, current) => prev + current, BigInt(0)); + return sumInputsCapacity > sumOutputsCapacity; +}; diff --git a/packages/ckb/src/utils/rgbpp.ts b/packages/ckb/src/utils/rgbpp.ts index 842d544b..2783eed1 100644 --- a/packages/ckb/src/utils/rgbpp.ts +++ b/packages/ckb/src/utils/rgbpp.ts @@ -255,6 +255,9 @@ export const throwErrorWhenRgbppCellsInvalid = ( } }; +/** + * Check if the tx's unoccupied capacity is enough to create a new rgbpp-cell as a UDT change cell + */ export const isRgbppCapacitySufficientForChange = ( sumUdtInputsCapacity: bigint, receiverOutputCapacity: bigint, From bf7fa04ec393a2508333017465f8a703d3339765 Mon Sep 17 00:00:00 2001 From: Shook Date: Mon, 13 May 2024 14:24:19 +0800 Subject: [PATCH 22/78] refactor: check paymaster output requirement with API from ckb lib --- packages/btc/src/api/sendRgbppUtxos.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/btc/src/api/sendRgbppUtxos.ts b/packages/btc/src/api/sendRgbppUtxos.ts index 6e40efb4..0bc23cc6 100644 --- a/packages/btc/src/api/sendRgbppUtxos.ts +++ b/packages/btc/src/api/sendRgbppUtxos.ts @@ -1,4 +1,5 @@ -import { Collector, isRgbppLockCell, isBtcTimeLockCell, calculateCommitment } from '@rgbpp-sdk/ckb'; +import { Collector, checkCkbTxInputsCapacitySufficient } from '@rgbpp-sdk/ckb'; +import { isRgbppLockCell, isBtcTimeLockCell, calculateCommitment } from '@rgbpp-sdk/ckb'; import { bitcoin } from '../bitcoin'; import { Utxo } from '../transaction/utxo'; import { DataSource } from '../query/source'; @@ -165,14 +166,16 @@ async function getMergedBtcOutputs(btcOutputs: InitOutput[], props: SendRgbppUtx const isPaymasterUnmatched = defaultPaymaster?.address !== props.paymaster?.address || defaultPaymaster?.value !== props.paymaster?.value; if (defaultPaymaster && props.paymaster && isPaymasterUnmatched) { - throw new TxBuildError(ErrorCodes.PAYMASTER_MISMATCH); + throw TxBuildError.withComment( + ErrorCodes.PAYMASTER_MISMATCH, + `expected: ${defaultPaymaster}, actual: ${props.paymaster}`, + ); } - // Add paymaster output - // TODO: can be more accurate if we compare the actual capacity of inputs & outputs + // Add paymaster output, only if paymaster address exists and needed const paymaster = defaultPaymaster ?? props.paymaster; - const needPaymasterOutput = props.ckbVirtualTx.inputs.length < props.ckbVirtualTx.outputs.length; - if (paymaster && needPaymasterOutput) { + const isCkbTxCapacitySufficient = await checkCkbTxInputsCapacitySufficient(props.ckbVirtualTx, props.ckbCollector); + if (paymaster && !isCkbTxCapacitySufficient) { merged.push({ ...paymaster, fixed: true, From 97f3ce2fe2404375d7db0873a89121f769ff753f Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Wed, 8 May 2024 15:48:27 +0800 Subject: [PATCH 23/78] refactor: Move xudt examples to signle package --- examples/rgbpp/README.md | 17 -- examples/rgbpp/xudt/0-token-info.ts | 7 - examples/rgbpp/xudt/1-issue-xudt.ts | 123 ------------ examples/rgbpp/xudt/2-transfer-xudt.ts | 163 ---------------- examples/xudt/.env.example | 11 ++ examples/xudt/1-issue-xudt.ts | 10 + examples/xudt/2-transfer-xudt.ts | 27 +++ examples/xudt/README.md | 17 ++ examples/xudt/package.json | 16 ++ examples/xudt/src/core.ts | 256 +++++++++++++++++++++++++ examples/xudt/tsconfig.json | 26 +++ package.json | 2 +- pnpm-lock.yaml | 9 + 13 files changed, 373 insertions(+), 311 deletions(-) delete mode 100644 examples/rgbpp/xudt/0-token-info.ts delete mode 100644 examples/rgbpp/xudt/1-issue-xudt.ts delete mode 100644 examples/rgbpp/xudt/2-transfer-xudt.ts create mode 100644 examples/xudt/.env.example create mode 100644 examples/xudt/1-issue-xudt.ts create mode 100644 examples/xudt/2-transfer-xudt.ts create mode 100644 examples/xudt/README.md create mode 100644 examples/xudt/package.json create mode 100644 examples/xudt/src/core.ts create mode 100644 examples/xudt/tsconfig.json diff --git a/examples/rgbpp/README.md b/examples/rgbpp/README.md index ce8d018d..5f90be8a 100644 --- a/examples/rgbpp/README.md +++ b/examples/rgbpp/README.md @@ -4,7 +4,6 @@ - Local and Queue directories: The examples for RGB++ UDT issuance, transfer, and leap - Spore directory: The examples for RGB++ spore creation, transfer and leap -- xUDT directory: The examples for xUDT issuance, mint and transfer on CKB ## What you must know about BTC transaction id @@ -29,22 +28,6 @@ But when you're searching for this transaction in [Bitcoin Core](https://bitcoin 018025fb6989eed484774170eefa2bef1074b0c24537f992a64dbc138277bc4a ``` -## xUDT on CKB Examples - -### Issue xUDT on CKB - -```shell -npx ts-node examples/rgbpp/xudt/1-issue-xudt.ts -``` - -### Mint/Transfer xUDT on CKB - -You can use this command to mint or transfer xUDT assets - -```shell -npx ts-node examples/rgbpp/xudt/2-transfer-xudt.ts -``` - ## RGB++ xUDT Examples with Queue service(Recommended) ### Leap xUDT from CKB to BTC diff --git a/examples/rgbpp/xudt/0-token-info.ts b/examples/rgbpp/xudt/0-token-info.ts deleted file mode 100644 index a2cb7a9c..00000000 --- a/examples/rgbpp/xudt/0-token-info.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { RgbppTokenInfo } from '@rgbpp-sdk/ckb'; - -export const XUDT_TOKEN_INFO: RgbppTokenInfo = { - decimal: 8, - name: 'XUDT Test Token', - symbol: 'XTT', -}; diff --git a/examples/rgbpp/xudt/1-issue-xudt.ts b/examples/rgbpp/xudt/1-issue-xudt.ts deleted file mode 100644 index a8acc356..00000000 --- a/examples/rgbpp/xudt/1-issue-xudt.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { - AddressPrefix, - addressToScript, - getTransactionSize, - privateKeyToAddress, - scriptToHash, -} from '@nervosnetwork/ckb-sdk-utils'; -import { - getSecp256k1CellDep, - Collector, - NoLiveCellError, - calculateUdtCellCapacity, - MAX_FEE, - MIN_CAPACITY, - getXudtTypeScript, - append0x, - getUniqueTypeScript, - u128ToLe, - encodeRgbppTokenInfo, - getXudtDep, - getUniqueTypeDep, - SECP256K1_WITNESS_LOCK_SIZE, - calculateTransactionFee, - generateUniqueTypeArgs, -} from '@rgbpp-sdk/ckb'; -import { calculateXudtTokenInfoCellCapacity } from '@rgbpp-sdk/ckb/src/utils'; -import { XUDT_TOKEN_INFO } from './0-token-info'; - -// CKB SECP256K1 private key -const CKB_TEST_PRIVATE_KEY = '0x0000000000000000000000000000000000000000000000000000000000000001'; - -/** - * issueXudt can be used to issue xUDT assets with unique cell as token info cell. - * @param: xudtTotalAmount The xudtTotalAmount specifies the total amount of asset issuance - */ -const issueXudt = async ({ xudtTotalAmount }: { xudtTotalAmount: bigint }) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - const issueAddress = privateKeyToAddress(CKB_TEST_PRIVATE_KEY, { - prefix: isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, - }); - console.log('ckb address: ', issueAddress); - - const issueLock = addressToScript(issueAddress); - - let emptyCells = await collector.getCells({ - lock: issueLock, - }); - if (!emptyCells || emptyCells.length === 0) { - throw new NoLiveCellError('The address has no empty cells'); - } - emptyCells = emptyCells.filter((cell) => !cell.output.type); - - const xudtCapacity = calculateUdtCellCapacity(issueLock); - const xudtInfoCapacity = calculateXudtTokenInfoCellCapacity(XUDT_TOKEN_INFO, issueLock); - - const txFee = MAX_FEE; - const { inputs, sumInputsCapacity } = collector.collectInputs(emptyCells, xudtCapacity + xudtInfoCapacity, txFee, { - minCapacity: MIN_CAPACITY, - }); - - const xudtType: CKBComponents.Script = { - ...getXudtTypeScript(isMainnet), - args: append0x(scriptToHash(issueLock)), - }; - - console.log('xUDT type script', xudtType); - - let changeCapacity = sumInputsCapacity - xudtCapacity - xudtInfoCapacity; - const outputs: CKBComponents.CellOutput[] = [ - { - lock: issueLock, - type: xudtType, - capacity: append0x(xudtCapacity.toString(16)), - }, - { - lock: issueLock, - type: { - ...getUniqueTypeScript(isMainnet), - args: generateUniqueTypeArgs(inputs[0], 1), - }, - capacity: append0x(xudtInfoCapacity.toString(16)), - }, - { - lock: issueLock, - capacity: append0x(changeCapacity.toString(16)), - }, - ]; - const totalAmount = xudtTotalAmount * BigInt(10 ** XUDT_TOKEN_INFO.decimal); - const outputsData = [append0x(u128ToLe(totalAmount)), encodeRgbppTokenInfo(XUDT_TOKEN_INFO), '0x']; - - const emptyWitness = { lock: '', inputType: '', outputType: '' }; - const witnesses = inputs.map((_, index) => (index === 0 ? emptyWitness : '0x')); - - const cellDeps = [getSecp256k1CellDep(isMainnet), getUniqueTypeDep(isMainnet), getXudtDep(isMainnet)]; - - const unsignedTx = { - version: '0x0', - cellDeps, - headerDeps: [], - inputs, - outputs, - outputsData, - witnesses, - }; - - if (txFee === MAX_FEE) { - const txSize = getTransactionSize(unsignedTx) + SECP256K1_WITNESS_LOCK_SIZE; - const estimatedTxFee = calculateTransactionFee(txSize); - changeCapacity -= estimatedTxFee; - unsignedTx.outputs[unsignedTx.outputs.length - 1].capacity = append0x(changeCapacity.toString(16)); - } - - const signedTx = collector.getCkb().signTransaction(CKB_TEST_PRIVATE_KEY)(unsignedTx); - const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); - - console.info(`xUDT asset has been issued and tx hash is ${txHash}`); -}; - -issueXudt({ xudtTotalAmount: BigInt(2100_0000) }); diff --git a/examples/rgbpp/xudt/2-transfer-xudt.ts b/examples/rgbpp/xudt/2-transfer-xudt.ts deleted file mode 100644 index 7a150aa5..00000000 --- a/examples/rgbpp/xudt/2-transfer-xudt.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { AddressPrefix, addressToScript, getTransactionSize, privateKeyToAddress } from '@nervosnetwork/ckb-sdk-utils'; -import { - getSecp256k1CellDep, - Collector, - NoLiveCellError, - calculateUdtCellCapacity, - MAX_FEE, - MIN_CAPACITY, - append0x, - u128ToLe, - getXudtDep, - getUniqueTypeDep, - SECP256K1_WITNESS_LOCK_SIZE, - calculateTransactionFee, - NoXudtLiveCellError, -} from '@rgbpp-sdk/ckb'; -import { XUDT_TOKEN_INFO } from './0-token-info'; - -// CKB SECP256K1 private key -const CKB_TEST_PRIVATE_KEY = '0x0000000000000000000000000000000000000000000000000000000000000001'; - -interface TransferParams { - xudtType: CKBComponents.Script; - receivers: { - toAddress: string; - transferAmount: bigint; - }[]; -} - -/** - * transferXudt can be used to mint xUDT assets or transfer xUDT assets. - * @param: xudtType The xUDT type script that comes from 1-issue-xudt - * @param: receivers The receiver includes toAddress and transferAmount - */ -const transferXudt = async ({ xudtType, receivers }: TransferParams) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - const fromAddress = privateKeyToAddress(CKB_TEST_PRIVATE_KEY, { - prefix: isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, - }); - console.log('ckb address: ', fromAddress); - - const fromLock = addressToScript(fromAddress); - - const xudtCells = await collector.getCells({ - lock: fromLock, - type: xudtType, - }); - if (!xudtCells || xudtCells.length === 0) { - throw new NoXudtLiveCellError('The address has no xudt cells'); - } - const sumTransferAmount = receivers - .map((receiver) => receiver.transferAmount) - .reduce((prev, current) => prev + current, BigInt(0)); - - const { - inputs: udtInputs, - sumInputsCapacity: sumXudtInputsCapacity, - sumAmount, - } = collector.collectUdtInputs({ - liveCells: xudtCells, - needAmount: sumTransferAmount, - }); - let actualInputsCapacity = sumXudtInputsCapacity; - let inputs = udtInputs; - - const xudtCapacity = calculateUdtCellCapacity(fromLock); - const sumXudtCapacity = xudtCapacity * BigInt(receivers.length); - - const outputs: CKBComponents.CellOutput[] = receivers.map((receiver) => ({ - lock: addressToScript(receiver.toAddress), - type: xudtType, - capacity: append0x(xudtCapacity.toString(16)), - })); - const outputsData = receivers.map((receiver) => append0x(u128ToLe(receiver.transferAmount))); - - const txFee = MAX_FEE; - if (sumXudtInputsCapacity < sumXudtCapacity) { - let emptyCells = await collector.getCells({ - lock: fromLock, - }); - if (!emptyCells || emptyCells.length === 0) { - throw new NoLiveCellError('The address has no empty cells'); - } - emptyCells = emptyCells.filter((cell) => !cell.output.type); - const needCapacity = sumXudtCapacity - sumXudtInputsCapacity + xudtCapacity; - const { inputs: emptyInputs, sumInputsCapacity: sumEmptyCapacity } = collector.collectInputs( - emptyCells, - needCapacity, - txFee, - { minCapacity: MIN_CAPACITY }, - ); - inputs = [...inputs, ...emptyInputs]; - actualInputsCapacity += sumEmptyCapacity; - } - - let changeCapacity = actualInputsCapacity - sumXudtCapacity; - if (sumAmount > sumTransferAmount) { - outputs.push({ - lock: fromLock, - type: xudtType, - capacity: append0x(xudtCapacity.toString(16)), - }); - outputsData.push(append0x(u128ToLe(sumAmount - sumTransferAmount))); - changeCapacity -= xudtCapacity; - } - - outputs.push({ - lock: fromLock, - type: xudtType, - capacity: append0x(changeCapacity.toString(16)), - }); - outputsData.push('0x'); - - const emptyWitness = { lock: '', inputType: '', outputType: '' }; - const witnesses = inputs.map((_, index) => (index === 0 ? emptyWitness : '0x')); - - const cellDeps = [getSecp256k1CellDep(isMainnet), getUniqueTypeDep(isMainnet), getXudtDep(isMainnet)]; - - const unsignedTx = { - version: '0x0', - cellDeps, - headerDeps: [], - inputs, - outputs, - outputsData, - witnesses, - }; - - if (txFee === MAX_FEE) { - const txSize = getTransactionSize(unsignedTx) + SECP256K1_WITNESS_LOCK_SIZE; - const estimatedTxFee = calculateTransactionFee(txSize); - changeCapacity -= estimatedTxFee; - unsignedTx.outputs[unsignedTx.outputs.length - 1].capacity = append0x(changeCapacity.toString(16)); - } - - const signedTx = collector.getCkb().signTransaction(CKB_TEST_PRIVATE_KEY)(unsignedTx); - const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); - - console.info(`xUDT asset has been minted or transferred and tx hash is ${txHash}`); -}; - -transferXudt({ - // The xudtType comes from 1-issue-xudt - xudtType: { - codeHash: '0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb', - hashType: 'type', - args: '0x562e4e8a2f64a3e9c24beb4b7dd002d0ad3b842d0cc77924328e36ad114e3ebe', - }, - receivers: [ - { - toAddress: 'ckt1qyqpyw8j7tlu3v44am8d54066zrzk4vz5lvqat8fpf', - transferAmount: BigInt(1000) * BigInt(10 ** XUDT_TOKEN_INFO.decimal), - }, - { - toAddress: 'ckt1qyqpyw8j7tlu3v44am8d54066zrzk4vz5lvqat8fpf', - transferAmount: BigInt(2000) * BigInt(10 ** XUDT_TOKEN_INFO.decimal), - }, - ], -}); diff --git a/examples/xudt/.env.example b/examples/xudt/.env.example new file mode 100644 index 00000000..097c23c4 --- /dev/null +++ b/examples/xudt/.env.example @@ -0,0 +1,11 @@ +# The secp256k1 private key whose format is 32bytes hex string with 0x prefix +CKB_SECP256K1_PRIVATE_KEY='0x-private-key' + +# Ture for CKB Mainnet and false for CKB Testnet, the default value is false +IS_MAINNET='false' + +# CKB node url which should be matched with IS_MAINNET +CKB_NODE_URL='https://testnet.ckb.dev/rpc' + +# CKB indexer url which should be matched with IS_MAINNET +CKB_INDEXER_URL='https://testnet.ckb.dev/indexer' \ No newline at end of file diff --git a/examples/xudt/1-issue-xudt.ts b/examples/xudt/1-issue-xudt.ts new file mode 100644 index 00000000..8ebb6f94 --- /dev/null +++ b/examples/xudt/1-issue-xudt.ts @@ -0,0 +1,10 @@ +import { RgbppTokenInfo } from '@rgbpp-sdk/ckb'; +import { issueXudt } from './src/core'; + +const XUDT_TOKEN_INFO: RgbppTokenInfo = { + decimal: 8, + name: 'XUDT Test Token', + symbol: 'XTT', +}; + +issueXudt({ xudtTotalAmount: BigInt(2100_0000), tokenInfo: XUDT_TOKEN_INFO }); diff --git a/examples/xudt/2-transfer-xudt.ts b/examples/xudt/2-transfer-xudt.ts new file mode 100644 index 00000000..28019144 --- /dev/null +++ b/examples/xudt/2-transfer-xudt.ts @@ -0,0 +1,27 @@ +import { RgbppTokenInfo } from '@rgbpp-sdk/ckb'; +import { transferXudt } from './src/core'; + +const XUDT_TOKEN_INFO: RgbppTokenInfo = { + decimal: 8, + name: 'XUDT Test Token', + symbol: 'XTT', +}; + +transferXudt({ + // The xudtType comes from 1-issue-xudt + xudtType: { + codeHash: '0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb', + hashType: 'type', + args: '0x562e4e8a2f64a3e9c24beb4b7dd002d0ad3b842d0cc77924328e36ad114e3ebe', + }, + receivers: [ + { + toAddress: 'ckt1qyqpyw8j7tlu3v44am8d54066zrzk4vz5lvqat8fpf', + transferAmount: BigInt(1000) * BigInt(10 ** XUDT_TOKEN_INFO.decimal), + }, + { + toAddress: 'ckt1qyqpyw8j7tlu3v44am8d54066zrzk4vz5lvqat8fpf', + transferAmount: BigInt(2000) * BigInt(10 ** XUDT_TOKEN_INFO.decimal), + }, + ], +}); diff --git a/examples/xudt/README.md b/examples/xudt/README.md new file mode 100644 index 00000000..5f671474 --- /dev/null +++ b/examples/xudt/README.md @@ -0,0 +1,17 @@ +# xUDT on CKB Examples + +The examples for xUDT issuance, mint and transfer on CKB + +### Issue xUDT on CKB + +```shell +npx ts-node examples/rgbpp/xudt/1-issue-xudt.ts +``` + +### Mint/Transfer xUDT on CKB + +You can use this command to mint or transfer xUDT assets + +```shell +npx ts-node examples/rgbpp/xudt/2-transfer-xudt.ts +``` diff --git a/examples/xudt/package.json b/examples/xudt/package.json new file mode 100644 index 00000000..ae148dc4 --- /dev/null +++ b/examples/xudt/package.json @@ -0,0 +1,16 @@ +{ + "name": "xudt-examples", + "version": "0.1.0", + "description": "Examples used for xUDT on CKB assets issuance and transfer", + "private": true, + "type": "commonjs", + "scripts": { + "format": "prettier --write '**/*.ts'", + "lint": "tsc && eslint . && prettier --check '**/*.ts'", + "lint:fix": "tsc && eslint --fix --ext .ts . && prettier --write '**/*.ts'" + }, + "dependencies": { + "@nervosnetwork/ckb-sdk-utils": "^0.109.1", + "@rgbpp-sdk/ckb": "workspace:^" + } +} diff --git a/examples/xudt/src/core.ts b/examples/xudt/src/core.ts new file mode 100644 index 00000000..09095d0d --- /dev/null +++ b/examples/xudt/src/core.ts @@ -0,0 +1,256 @@ +import { + AddressPrefix, + addressToScript, + getTransactionSize, + privateKeyToAddress, + scriptToHash, +} from '@nervosnetwork/ckb-sdk-utils'; +import { + getSecp256k1CellDep, + Collector, + RgbppTokenInfo, + NoLiveCellError, + calculateUdtCellCapacity, + MAX_FEE, + MIN_CAPACITY, + getXudtTypeScript, + append0x, + getUniqueTypeScript, + u128ToLe, + encodeRgbppTokenInfo, + getXudtDep, + getUniqueTypeDep, + SECP256K1_WITNESS_LOCK_SIZE, + calculateTransactionFee, + generateUniqueTypeArgs, + calculateXudtTokenInfoCellCapacity, + NoXudtLiveCellError, +} from '@rgbpp-sdk/ckb'; + +const collector = new Collector({ + ckbNodeUrl: process.env.CKB_NODE_URL!, + ckbIndexerUrl: process.env.CKB_INDEXER_URL!, +}); +const isMainnet = process.env.IS_MAINNET === 'true' ? true : false; +const CKB_PRIVATE_KEY = process.env.CKB_SECP256K1_PRIVATE_KEY!; + +export interface IssueResult { + txHash: string; + xudtType: CKBComponents.Script; +} + +/** + * issueXudt can be used to issue xUDT assets with unique cell as token info cell. + * @param xudtTotalAmount The xudtTotalAmount specifies the total amount of asset issuance + * @param tokenInfo The xUDT token info which includes decimal, name and symbol + */ +export const issueXudt = async ({ + xudtTotalAmount, + tokenInfo, +}: { + xudtTotalAmount: bigint; + tokenInfo: RgbppTokenInfo; +}): Promise => { + const issueAddress = privateKeyToAddress(CKB_PRIVATE_KEY, { + prefix: isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, + }); + console.log('ckb address: ', issueAddress); + + const issueLock = addressToScript(issueAddress); + + let emptyCells = await collector.getCells({ + lock: issueLock, + }); + if (!emptyCells || emptyCells.length === 0) { + throw new NoLiveCellError('The address has no empty cells'); + } + emptyCells = emptyCells.filter((cell) => !cell.output.type); + + const xudtCapacity = calculateUdtCellCapacity(issueLock); + const xudtInfoCapacity = calculateXudtTokenInfoCellCapacity(tokenInfo, issueLock); + + const txFee = MAX_FEE; + const { inputs, sumInputsCapacity } = collector.collectInputs(emptyCells, xudtCapacity + xudtInfoCapacity, txFee, { + minCapacity: MIN_CAPACITY, + }); + + const xudtType: CKBComponents.Script = { + ...getXudtTypeScript(isMainnet), + args: append0x(scriptToHash(issueLock)), + }; + + console.log('xUDT type script', xudtType); + + let changeCapacity = sumInputsCapacity - xudtCapacity - xudtInfoCapacity; + const outputs: CKBComponents.CellOutput[] = [ + { + lock: issueLock, + type: xudtType, + capacity: append0x(xudtCapacity.toString(16)), + }, + { + lock: issueLock, + type: { + ...getUniqueTypeScript(isMainnet), + args: generateUniqueTypeArgs(inputs[0], 1), + }, + capacity: append0x(xudtInfoCapacity.toString(16)), + }, + { + lock: issueLock, + capacity: append0x(changeCapacity.toString(16)), + }, + ]; + const totalAmount = xudtTotalAmount * BigInt(10 ** tokenInfo.decimal); + const outputsData = [append0x(u128ToLe(totalAmount)), encodeRgbppTokenInfo(tokenInfo), '0x']; + + const emptyWitness = { lock: '', inputType: '', outputType: '' }; + const witnesses = inputs.map((_, index) => (index === 0 ? emptyWitness : '0x')); + + const cellDeps = [getSecp256k1CellDep(isMainnet), getUniqueTypeDep(isMainnet), getXudtDep(isMainnet)]; + + const unsignedTx = { + version: '0x0', + cellDeps, + headerDeps: [], + inputs, + outputs, + outputsData, + witnesses, + }; + + if (txFee === MAX_FEE) { + const txSize = getTransactionSize(unsignedTx) + SECP256K1_WITNESS_LOCK_SIZE; + const estimatedTxFee = calculateTransactionFee(txSize); + changeCapacity -= estimatedTxFee; + unsignedTx.outputs[unsignedTx.outputs.length - 1].capacity = append0x(changeCapacity.toString(16)); + } + + const signedTx = collector.getCkb().signTransaction(CKB_PRIVATE_KEY)(unsignedTx); + const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); + + console.info(`xUDT asset on CKB has been issued and tx hash is ${txHash}`); + + return { txHash, xudtType }; +}; + +export interface TransferParams { + xudtType: CKBComponents.Script; + receivers: { + toAddress: string; + transferAmount: bigint; + }[]; +} + +/** + * transferXudt can be used to mint xUDT assets or transfer xUDT assets. + * @param xudtType The xUDT type script that comes from 1-issue-xudt + * @param receivers The receiver includes toAddress and transferAmount + */ +export const transferXudt = async ({ xudtType, receivers }: TransferParams) => { + const fromAddress = privateKeyToAddress(CKB_PRIVATE_KEY, { + prefix: isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, + }); + console.log('ckb address: ', fromAddress); + + const fromLock = addressToScript(fromAddress); + + const xudtCells = await collector.getCells({ + lock: fromLock, + type: xudtType, + }); + if (!xudtCells || xudtCells.length === 0) { + throw new NoXudtLiveCellError('The address has no xudt cells'); + } + const sumTransferAmount = receivers + .map((receiver) => receiver.transferAmount) + .reduce((prev, current) => prev + current, BigInt(0)); + + const { + inputs: udtInputs, + sumInputsCapacity: sumXudtInputsCapacity, + sumAmount, + } = collector.collectUdtInputs({ + liveCells: xudtCells, + needAmount: sumTransferAmount, + }); + let actualInputsCapacity = sumXudtInputsCapacity; + let inputs = udtInputs; + + const xudtCapacity = calculateUdtCellCapacity(fromLock); + const sumXudtCapacity = xudtCapacity * BigInt(receivers.length); + + const outputs: CKBComponents.CellOutput[] = receivers.map((receiver) => ({ + lock: addressToScript(receiver.toAddress), + type: xudtType, + capacity: append0x(xudtCapacity.toString(16)), + })); + const outputsData = receivers.map((receiver) => append0x(u128ToLe(receiver.transferAmount))); + + const txFee = MAX_FEE; + if (sumXudtInputsCapacity < sumXudtCapacity) { + let emptyCells = await collector.getCells({ + lock: fromLock, + }); + if (!emptyCells || emptyCells.length === 0) { + throw new NoLiveCellError('The address has no empty cells'); + } + emptyCells = emptyCells.filter((cell) => !cell.output.type); + const needCapacity = sumXudtCapacity - sumXudtInputsCapacity + xudtCapacity; + const { inputs: emptyInputs, sumInputsCapacity: sumEmptyCapacity } = collector.collectInputs( + emptyCells, + needCapacity, + txFee, + { minCapacity: MIN_CAPACITY }, + ); + inputs = [...inputs, ...emptyInputs]; + actualInputsCapacity += sumEmptyCapacity; + } + + let changeCapacity = actualInputsCapacity - sumXudtCapacity; + if (sumAmount > sumTransferAmount) { + outputs.push({ + lock: fromLock, + type: xudtType, + capacity: append0x(xudtCapacity.toString(16)), + }); + outputsData.push(append0x(u128ToLe(sumAmount - sumTransferAmount))); + changeCapacity -= xudtCapacity; + } + + outputs.push({ + lock: fromLock, + type: xudtType, + capacity: append0x(changeCapacity.toString(16)), + }); + outputsData.push('0x'); + + const emptyWitness = { lock: '', inputType: '', outputType: '' }; + const witnesses = inputs.map((_, index) => (index === 0 ? emptyWitness : '0x')); + + const cellDeps = [getSecp256k1CellDep(isMainnet), getUniqueTypeDep(isMainnet), getXudtDep(isMainnet)]; + + const unsignedTx = { + version: '0x0', + cellDeps, + headerDeps: [], + inputs, + outputs, + outputsData, + witnesses, + }; + + if (txFee === MAX_FEE) { + const txSize = getTransactionSize(unsignedTx) + SECP256K1_WITNESS_LOCK_SIZE; + const estimatedTxFee = calculateTransactionFee(txSize); + changeCapacity -= estimatedTxFee; + unsignedTx.outputs[unsignedTx.outputs.length - 1].capacity = append0x(changeCapacity.toString(16)); + } + + const signedTx = collector.getCkb().signTransaction(CKB_PRIVATE_KEY)(unsignedTx); + const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); + + console.info(`xUDT asset has been minted or transferred and tx hash is ${txHash}`); + + return txHash; +}; diff --git a/examples/xudt/tsconfig.json b/examples/xudt/tsconfig.json new file mode 100644 index 00000000..07484ac0 --- /dev/null +++ b/examples/xudt/tsconfig.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "target": "ES2015", + "lib": ["dom", "dom.iterable", "esnext"], + "module": "CommonJS", + "composite": false, + "resolveJsonModule": true, + "strictNullChecks": true, + "noEmit": true, + "declaration": true, + "declarationMap": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "inlineSources": false, + "isolatedModules": true, + "moduleResolution": "node", + "noUnusedLocals": false, + "noUnusedParameters": false, + "preserveWatchOutput": true, + "skipLibCheck": true, + "strict": true + }, + "include": ["src/*.ts", "*.ts"], + "exclude": ["node_modules"] +} diff --git a/package.json b/package.json index e45131ff..72764c09 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "lint:packages": "turbo run lint --filter=./{packages,examples}/*", "format": "prettier --write '{packages,apps,examples}/**/*.{js,jsx,ts,tsx}'", "clean": "turbo run clean", - "clean:packages": "turbo run clean --filter=./packags/*", + "clean:packages": "turbo run clean --filter=./packages/*", "clean:dependencies": "pnpm clean:sub-dependencies && rimraf node_modules", "clean:sub-dependencies": "rimraf packages/**/node_modules apps/**/node_modules", "release:packages": "pnpm run clean:packages && pnpm run build:packages && changeset publish" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8ceb6dc5..cb21d6ed 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -165,6 +165,15 @@ importers: specifier: ^5.4.2 version: 5.4.2 + examples/xudt: + dependencies: + '@nervosnetwork/ckb-sdk-utils': + specifier: ^0.109.1 + version: 0.109.1 + '@rgbpp-sdk/ckb': + specifier: workspace:^ + version: link:../../packages/ckb + packages/btc: dependencies: '@bitcoinerlab/secp256k1': From b684a870e6b6ea6fb25453c1c3f9d77aea03e9a2 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Wed, 8 May 2024 20:29:42 +0800 Subject: [PATCH 24/78] refactor: Create example-core package --- examples/core/.env.example | 29 ++++ examples/core/README.md | 130 ++++++++++++++++ examples/core/package.json | 29 ++++ examples/core/src/ckb-xudt/index.ts | 233 ++++++++++++++++++++++++++++ examples/core/src/index.ts | 3 + examples/core/src/rgbpp/index.ts | 1 + examples/core/src/rgbpp/xudt.ts | 163 +++++++++++++++++++ examples/core/src/utils/index.ts | 31 ++++ examples/core/tsconfig.build.json | 10 ++ examples/core/tsconfig.json | 27 ++++ 10 files changed, 656 insertions(+) create mode 100644 examples/core/.env.example create mode 100644 examples/core/README.md create mode 100644 examples/core/package.json create mode 100644 examples/core/src/ckb-xudt/index.ts create mode 100644 examples/core/src/index.ts create mode 100644 examples/core/src/rgbpp/index.ts create mode 100644 examples/core/src/rgbpp/xudt.ts create mode 100644 examples/core/src/utils/index.ts create mode 100644 examples/core/tsconfig.build.json create mode 100644 examples/core/tsconfig.json diff --git a/examples/core/.env.example b/examples/core/.env.example new file mode 100644 index 00000000..fda5ec43 --- /dev/null +++ b/examples/core/.env.example @@ -0,0 +1,29 @@ +# Ture for CKB and BTC Mainnet and false for CKB and BTC Testnet, the default value is false +IS_MAINNET='false' + + +# CKB Variables + +# The CKB secp256k1 private key whose format is 32bytes hex string with 0x prefix +CKB_SECP256K1_PRIVATE_KEY='0x-private-key' + +# CKB node url which should be matched with IS_MAINNET +CKB_NODE_URL='https://testnet.ckb.dev/rpc' + +# CKB indexer url which should be matched with IS_MAINNET +CKB_INDEXER_URL='https://testnet.ckb.dev/indexer' + + +# BTC Variables + +# The BTC private key whose format is 32bytes hex string without 0x prefix +BTC_PRIVATE_KEY='private-key' + +# The BTC assets api url which should be matched with IS_MAINNET +BTC_ASSETS_API_URL='https://btc-assets-api.testnet.mibao.pro'; + +# The BTC assets api token which should be matched with IS_MAINNET +BTC_ASSETS_TOKEN=''; + +# The BTC assets api origin which should be matched with IS_MAINNET +BTC_ASSETS_ORIGIN='https://btc-test.app'; \ No newline at end of file diff --git a/examples/core/README.md b/examples/core/README.md new file mode 100644 index 00000000..5f90be8a --- /dev/null +++ b/examples/core/README.md @@ -0,0 +1,130 @@ +# RGB++ Examples + +**All examples are just to demonstrate the use of RGB++ SDK.** + +- Local and Queue directories: The examples for RGB++ UDT issuance, transfer, and leap +- Spore directory: The examples for RGB++ spore creation, transfer and leap + +## What you must know about BTC transaction id + +**The BTC transaction id(hash) displayed on BTC explorer is different from the BTC transaction id(hash) in RGB++ lock args. They are in reverse byte order.** + +We follow the following two rules: + +- Whenever you're working with transaction/block hashes **internally** (e.g. inside raw bitcoin data), you use the **natural** byte order. +- Whenever you're **displaying or searching** for transaction/block hashes, you use the **reverse** byte order. + +For detailed rules, please refer to [Byte Order](https://learnmeabitcoin.com/technical/general/byte-order/) + +For example, the BTC transaction id(hash) of the RGB++ lock args like this: + +``` +4abc778213bc4da692f93745c2b07410ef2bfaee70417784d4ee8969fb258001 +``` + +But when you're searching for this transaction in [Bitcoin Core](https://bitcoin.org/en/bitcoin-core/) or on a block explorer, you'll see this byte order: + +``` +018025fb6989eed484774170eefa2bef1074b0c24537f992a64dbc138277bc4a +``` + +## RGB++ xUDT Examples with Queue service(Recommended) + +### Leap xUDT from CKB to BTC + +```shell +npx ts-node examples/rgbpp/queue/1-ckb-jump-btc.ts +``` + +### Transfer RGB++ xUDT on BTC + +```shell +npx ts-node examples/rgbpp/queue/2-btc-transfer.ts +``` + +### Leap RGB++ xUDT from BTC to CKB + +```shell +npx ts-node examples/rgbpp/queue/3-btc-jump-ckb.ts +``` + +### Unlock xUDT BTC time cells on CKB + +A cron job in RGB++ Queue service will construct a transaction unlocking the mature BTC time cells to the their `target_ckb_address`. + + +## RGB++ xUDT Local Examples + +### Leap RGB++ xUDT from CKB to BTC + +```shell +npx ts-node examples/rgbpp/local/1-ckb-jump-btc.ts +``` + +### Transfer RGB++ xUDT on BTC + +```shell +npx ts-node examples/rgbpp/local/2-btc-transfer.ts +``` + +### Leap RGB++ xUDT from BTC to CKB + +```shell +npx ts-node examples/rgbpp/local/3-btc-jump-ckb.ts +``` + +### Unlock xUDT BTC time cells on CKB + +**Warning: Wait at least 6 BTC confirmation blocks to unlock the BTC time cells after 4-btc-jump-ckb.ts** + +```shell +npx ts-node examples/rgbpp/local/4-spend-btc-time-cell.ts +``` + +## RGB++ Spore Examples + +**You can use RGB++ Queue service to complete spore transfer and leap, and the examples can be found in `examples/rgbpp/spore/queue`** + +### Create RGB++ Cluster Cell + +```shell +npx ts-node examples/rgbpp/spore/1-prepare-cluster.ts + +npx ts-node examples/rgbpp/spore/2-create-cluster.ts +``` + +### Create RGB++ Spores with Cluster on BTC + +```shell +npx ts-node examples/rgbpp/spore/3-create-spores.ts +``` + +### Transfer RGB++ Spore on BTC + +```shell +npx ts-node examples/rgbpp/spore/4-transfer-spore.ts +``` + +### Leap RGB++ Spore from BTC to CKB + +```shell +npx ts-node examples/rgbpp/spore/5-leap-spore-to-ckb.ts +``` + +### Unlock Spore BTC time cells on CKB + +A cron job in RGB++ Queue service will construct a transaction unlocking the mature BTC time cells to the their `target_ckb_address`. + +However, you can still manually unlock the spore btc time cell through the following command + +**Warning: Wait at least 6 BTC confirmation blocks to unlock the BTC time cells after 5-leap-spore-to-ckb.ts** + +```shell +npx ts-node examples/rgbpp/spore/6-unlock-btc-time-cell.ts +``` + +### Leap Spore from CKB to BTC + +```shell +npx ts-node examples/rgbpp/spore/7-leap-spore-to-btc.ts +``` \ No newline at end of file diff --git a/examples/core/package.json b/examples/core/package.json new file mode 100644 index 00000000..35f4384a --- /dev/null +++ b/examples/core/package.json @@ -0,0 +1,29 @@ +{ + "name": "examples-core", + "version": "0.1.0", + "description": "The core methods and utils of RGB++ and xUDT", + "scripts": { + "build": "tsc -p tsconfig.build.json", + "format": "prettier --write '**/*.ts'", + "lint": "tsc && eslint . && prettier --check '**/*.ts'", + "lint:fix": "tsc && eslint --fix --ext .ts . && prettier --write '**/*.ts'" + }, + "main": "lib", + "files": [ + "lib" + ], + "types": "./lib/index.d.ts", + "dependencies": { + "@exact-realty/multipart-parser": "^1.0.13", + "@nervosnetwork/ckb-sdk-utils": "^0.109.1", + "@rgbpp-sdk/btc": "workspace:^", + "@rgbpp-sdk/ckb": "workspace:^", + "@rgbpp-sdk/service": "workspace:^", + "@spore-sdk/core": "^0.2.0-beta.6", + "axios": "^1.6.8" + }, + "devDependencies": { + "@types/node": "^20.11.28", + "typescript": "^5.4.2" + } +} diff --git a/examples/core/src/ckb-xudt/index.ts b/examples/core/src/ckb-xudt/index.ts new file mode 100644 index 00000000..5fa40760 --- /dev/null +++ b/examples/core/src/ckb-xudt/index.ts @@ -0,0 +1,233 @@ +import { addressToScript, getTransactionSize, scriptToHash } from '@nervosnetwork/ckb-sdk-utils'; +import { + getSecp256k1CellDep, + RgbppTokenInfo, + NoLiveCellError, + calculateUdtCellCapacity, + MAX_FEE, + MIN_CAPACITY, + getXudtTypeScript, + append0x, + getUniqueTypeScript, + u128ToLe, + encodeRgbppTokenInfo, + getXudtDep, + getUniqueTypeDep, + SECP256K1_WITNESS_LOCK_SIZE, + calculateTransactionFee, + generateUniqueTypeArgs, + calculateXudtTokenInfoCellCapacity, + NoXudtLiveCellError, +} from '@rgbpp-sdk/ckb'; +import { CKB_PRIVATE_KEY, ckbAddress, collector, isMainnet } from '../utils'; + +export interface IssueResult { + txHash: string; + xudtType: CKBComponents.Script; +} + +/** + * issueXudt can be used to issue xUDT assets with unique cell as token info cell. + * @param xudtTotalAmount The xudtTotalAmount specifies the total amount of asset issuance + * @param tokenInfo The xUDT token info which includes decimal, name and symbol + */ +export const issueXudt = async ({ + xudtTotalAmount, + tokenInfo, +}: { + xudtTotalAmount: bigint; + tokenInfo: RgbppTokenInfo; +}): Promise => { + const issueLock = addressToScript(ckbAddress); + + let emptyCells = await collector.getCells({ + lock: issueLock, + }); + if (!emptyCells || emptyCells.length === 0) { + throw new NoLiveCellError('The address has no empty cells'); + } + emptyCells = emptyCells.filter((cell) => !cell.output.type); + + const xudtCapacity = calculateUdtCellCapacity(issueLock); + const xudtInfoCapacity = calculateXudtTokenInfoCellCapacity(tokenInfo, issueLock); + + const txFee = MAX_FEE; + const { inputs, sumInputsCapacity } = collector.collectInputs(emptyCells, xudtCapacity + xudtInfoCapacity, txFee, { + minCapacity: MIN_CAPACITY, + }); + + const xudtType: CKBComponents.Script = { + ...getXudtTypeScript(isMainnet), + args: append0x(scriptToHash(issueLock)), + }; + + console.log('xUDT type script', xudtType); + + let changeCapacity = sumInputsCapacity - xudtCapacity - xudtInfoCapacity; + const outputs: CKBComponents.CellOutput[] = [ + { + lock: issueLock, + type: xudtType, + capacity: append0x(xudtCapacity.toString(16)), + }, + { + lock: issueLock, + type: { + ...getUniqueTypeScript(isMainnet), + args: generateUniqueTypeArgs(inputs[0], 1), + }, + capacity: append0x(xudtInfoCapacity.toString(16)), + }, + { + lock: issueLock, + capacity: append0x(changeCapacity.toString(16)), + }, + ]; + const totalAmount = xudtTotalAmount * BigInt(10 ** tokenInfo.decimal); + const outputsData = [append0x(u128ToLe(totalAmount)), encodeRgbppTokenInfo(tokenInfo), '0x']; + + const emptyWitness = { lock: '', inputType: '', outputType: '' }; + const witnesses = inputs.map((_, index) => (index === 0 ? emptyWitness : '0x')); + + const cellDeps = [getSecp256k1CellDep(isMainnet), getUniqueTypeDep(isMainnet), getXudtDep(isMainnet)]; + + const unsignedTx = { + version: '0x0', + cellDeps, + headerDeps: [], + inputs, + outputs, + outputsData, + witnesses, + }; + + if (txFee === MAX_FEE) { + const txSize = getTransactionSize(unsignedTx) + SECP256K1_WITNESS_LOCK_SIZE; + const estimatedTxFee = calculateTransactionFee(txSize); + changeCapacity -= estimatedTxFee; + unsignedTx.outputs[unsignedTx.outputs.length - 1].capacity = append0x(changeCapacity.toString(16)); + } + + const signedTx = collector.getCkb().signTransaction(CKB_PRIVATE_KEY)(unsignedTx); + const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); + + console.info(`xUDT asset on CKB has been issued and tx hash is ${txHash}`); + + return { txHash, xudtType }; +}; + +export interface XudtTransferParams { + xudtType: CKBComponents.Script; + receivers: { + toAddress: string; + transferAmount: bigint; + }[]; +} + +/** + * transferXudt can be used to mint xUDT assets or transfer xUDT assets. + * @param xudtType The xUDT type script that comes from 1-issue-xudt + * @param receivers The receiver includes toAddress and transferAmount + */ +export const transferXudt = async ({ xudtType, receivers }: XudtTransferParams) => { + const fromLock = addressToScript(ckbAddress); + + const xudtCells = await collector.getCells({ + lock: fromLock, + type: xudtType, + }); + if (!xudtCells || xudtCells.length === 0) { + throw new NoXudtLiveCellError('The address has no xudt cells'); + } + const sumTransferAmount = receivers + .map((receiver) => receiver.transferAmount) + .reduce((prev, current) => prev + current, BigInt(0)); + + const { + inputs: udtInputs, + sumInputsCapacity: sumXudtInputsCapacity, + sumAmount, + } = collector.collectUdtInputs({ + liveCells: xudtCells, + needAmount: sumTransferAmount, + }); + let actualInputsCapacity = sumXudtInputsCapacity; + let inputs = udtInputs; + + const xudtCapacity = calculateUdtCellCapacity(fromLock); + const sumXudtCapacity = xudtCapacity * BigInt(receivers.length); + + const outputs: CKBComponents.CellOutput[] = receivers.map((receiver) => ({ + lock: addressToScript(receiver.toAddress), + type: xudtType, + capacity: append0x(xudtCapacity.toString(16)), + })); + const outputsData = receivers.map((receiver) => append0x(u128ToLe(receiver.transferAmount))); + + const txFee = MAX_FEE; + if (sumXudtInputsCapacity < sumXudtCapacity) { + let emptyCells = await collector.getCells({ + lock: fromLock, + }); + if (!emptyCells || emptyCells.length === 0) { + throw new NoLiveCellError('The address has no empty cells'); + } + emptyCells = emptyCells.filter((cell) => !cell.output.type); + const needCapacity = sumXudtCapacity - sumXudtInputsCapacity + xudtCapacity; + const { inputs: emptyInputs, sumInputsCapacity: sumEmptyCapacity } = collector.collectInputs( + emptyCells, + needCapacity, + txFee, + { minCapacity: MIN_CAPACITY }, + ); + inputs = [...inputs, ...emptyInputs]; + actualInputsCapacity += sumEmptyCapacity; + } + + let changeCapacity = actualInputsCapacity - sumXudtCapacity; + if (sumAmount > sumTransferAmount) { + outputs.push({ + lock: fromLock, + type: xudtType, + capacity: append0x(xudtCapacity.toString(16)), + }); + outputsData.push(append0x(u128ToLe(sumAmount - sumTransferAmount))); + changeCapacity -= xudtCapacity; + } + + outputs.push({ + lock: fromLock, + type: xudtType, + capacity: append0x(changeCapacity.toString(16)), + }); + outputsData.push('0x'); + + const emptyWitness = { lock: '', inputType: '', outputType: '' }; + const witnesses = inputs.map((_, index) => (index === 0 ? emptyWitness : '0x')); + + const cellDeps = [getSecp256k1CellDep(isMainnet), getUniqueTypeDep(isMainnet), getXudtDep(isMainnet)]; + + const unsignedTx = { + version: '0x0', + cellDeps, + headerDeps: [], + inputs, + outputs, + outputsData, + witnesses, + }; + + if (txFee === MAX_FEE) { + const txSize = getTransactionSize(unsignedTx) + SECP256K1_WITNESS_LOCK_SIZE; + const estimatedTxFee = calculateTransactionFee(txSize); + changeCapacity -= estimatedTxFee; + unsignedTx.outputs[unsignedTx.outputs.length - 1].capacity = append0x(changeCapacity.toString(16)); + } + + const signedTx = collector.getCkb().signTransaction(CKB_PRIVATE_KEY)(unsignedTx); + const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); + + console.info(`xUDT asset has been minted or transferred and tx hash is ${txHash}`); + + return txHash; +}; diff --git a/examples/core/src/index.ts b/examples/core/src/index.ts new file mode 100644 index 00000000..cc87c10b --- /dev/null +++ b/examples/core/src/index.ts @@ -0,0 +1,3 @@ +export * from './rgbpp'; +export * from './ckb-xudt'; +export * from './utils'; diff --git a/examples/core/src/rgbpp/index.ts b/examples/core/src/rgbpp/index.ts new file mode 100644 index 00000000..7fa4382e --- /dev/null +++ b/examples/core/src/rgbpp/index.ts @@ -0,0 +1 @@ +export * from './xudt'; diff --git a/examples/core/src/rgbpp/xudt.ts b/examples/core/src/rgbpp/xudt.ts new file mode 100644 index 00000000..3f518447 --- /dev/null +++ b/examples/core/src/rgbpp/xudt.ts @@ -0,0 +1,163 @@ +import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; +import { + genCkbJumpBtcVirtualTx, + getSecp256k1CellDep, + buildRgbppLockArgs, + getXudtTypeScript, + genBtcTransferCkbVirtualTx, + genBtcJumpCkbVirtualTx, +} from '@rgbpp-sdk/ckb'; +import { + CKB_PRIVATE_KEY, + isMainnet, + collector, + ckbAddress, + btcAddress, + btcKeyPair, + btcService, + btcDataSource, +} from '../utils'; +import { sendRgbppUtxos } from '@rgbpp-sdk/btc'; + +export interface LeapToBtcParams { + outIndex: number; + btcTxId: string; + xudtTypeArgs: string; + transferAmount: bigint; +} + +export const leapFromCkbToBtc = async ({ + outIndex, + btcTxId, + xudtTypeArgs, + transferAmount, +}: LeapToBtcParams): Promise => { + const toRgbppLockArgs = buildRgbppLockArgs(outIndex, btcTxId); + + // Warning: Please replace with your real xUDT type script here + const xudtType: CKBComponents.Script = { + ...getXudtTypeScript(isMainnet), + args: xudtTypeArgs, + }; + + const ckbRawTx = await genCkbJumpBtcVirtualTx({ + collector, + fromCkbAddress: ckbAddress, + toRgbppLockArgs, + xudtTypeBytes: serializeScript(xudtType), + transferAmount, + }); + + const emptyWitness = { lock: '', inputType: '', outputType: '' }; + const unsignedTx: CKBComponents.RawTransactionToSign = { + ...ckbRawTx, + cellDeps: [...ckbRawTx.cellDeps, getSecp256k1CellDep(false)], + witnesses: [emptyWitness, ...ckbRawTx.witnesses.slice(1)], + }; + + const signedTx = collector.getCkb().signTransaction(CKB_PRIVATE_KEY)(unsignedTx); + + const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); + console.info(`Rgbpp asset has been jumped from CKB to BTC and tx hash is ${txHash}`); + + return txHash; +}; + +export interface RgbppTransferParams { + rgbppLockArgsList: string[]; + toBtcAddress: string; + xudtTypeArgs: string; + transferAmount: bigint; +} +export const transferRgbppOnBtc = async ({ + rgbppLockArgsList, + toBtcAddress, + xudtTypeArgs, + transferAmount, +}: RgbppTransferParams): Promise => { + const xudtType: CKBComponents.Script = { + ...getXudtTypeScript(isMainnet), + args: xudtTypeArgs, + }; + + const ckbVirtualTxResult = await genBtcTransferCkbVirtualTx({ + collector, + rgbppLockArgsList, + xudtTypeBytes: serializeScript(xudtType), + transferAmount, + isMainnet, + }); + + const { commitment, ckbRawTx } = ckbVirtualTxResult; + + // Send BTC tx + const psbt = await sendRgbppUtxos({ + ckbVirtualTx: ckbRawTx, + commitment, + tos: [toBtcAddress], + ckbCollector: collector, + from: btcAddress!, + source: btcDataSource, + }); + psbt.signAllInputs(btcKeyPair); + psbt.finalizeAllInputs(); + + const btcTx = psbt.extractTransaction(); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); + + console.log('BTC TxId: ', btcTxId); + + await btcService.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); + + return btcTxId; +}; + +export interface LeapToCkbParams { + rgbppLockArgsList: string[]; + toCkbAddress: string; + xudtTypeArgs: string; + transferAmount: bigint; +} +export const leapFromBtcToCkb = async ({ + rgbppLockArgsList, + toCkbAddress, + xudtTypeArgs, + transferAmount, +}: LeapToCkbParams): Promise => { + const xudtType: CKBComponents.Script = { + ...getXudtTypeScript(isMainnet), + args: xudtTypeArgs, + }; + + const ckbVirtualTxResult = await genBtcJumpCkbVirtualTx({ + collector, + rgbppLockArgsList, + xudtTypeBytes: serializeScript(xudtType), + transferAmount, + toCkbAddress, + isMainnet, + }); + + const { commitment, ckbRawTx } = ckbVirtualTxResult; + + // Send BTC tx + const psbt = await sendRgbppUtxos({ + ckbVirtualTx: ckbRawTx, + commitment, + tos: [btcAddress!], + ckbCollector: collector, + from: btcAddress!, + source: btcDataSource, + }); + psbt.signAllInputs(btcKeyPair); + psbt.finalizeAllInputs(); + + const btcTx = psbt.extractTransaction(); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); + + console.log('BTC TxId: ', btcTxId); + + await btcService.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); + + return btcTxId; +}; diff --git a/examples/core/src/utils/index.ts b/examples/core/src/utils/index.ts new file mode 100644 index 00000000..d969214b --- /dev/null +++ b/examples/core/src/utils/index.ts @@ -0,0 +1,31 @@ +import { AddressPrefix, privateKeyToAddress } from '@nervosnetwork/ckb-sdk-utils'; +import { DataSource, ECPair, ECPairInterface, NetworkType, bitcoin } from '@rgbpp-sdk/btc'; +import { Collector } from '@rgbpp-sdk/ckb'; +import { BtcAssetsApi } from '@rgbpp-sdk/service'; + +export const isMainnet = process.env.IS_MAINNET === 'true' ? true : false; + +export const collector = new Collector({ + ckbNodeUrl: process.env.CKB_NODE_URL!, + ckbIndexerUrl: process.env.CKB_INDEXER_URL!, +}); +export const CKB_PRIVATE_KEY = process.env.CKB_SECP256K1_PRIVATE_KEY!; +export const ckbAddress = privateKeyToAddress(CKB_PRIVATE_KEY, { + prefix: isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, +}); + +export const BTC_PRIVATE_KEY = process.env.BTC_PRIVATE_KEY!; +export const BTC_ASSETS_API_URL = process.env.BTC_ASSETS_API_URL!; +export const BTC_ASSETS_TOKEN = process.env.BTC_ASSETS_TOKEN!; +export const BTC_ASSETS_ORIGIN = process.env.BTC_ASSETS_ORIGIN!; + +const network = isMainnet ? bitcoin.networks.bitcoin : bitcoin.networks.testnet; +export const btcKeyPair: ECPairInterface = ECPair.fromPrivateKey(Buffer.from(BTC_PRIVATE_KEY, 'hex'), { network }); +export const { address: btcAddress } = bitcoin.payments.p2wpkh({ + pubkey: btcKeyPair.publicKey, + network, +}); + +const networkType = isMainnet ? NetworkType.MAINNET : NetworkType.TESTNET; +export const btcService = BtcAssetsApi.fromToken(BTC_ASSETS_API_URL, BTC_ASSETS_TOKEN, BTC_ASSETS_ORIGIN); +export const btcDataSource = new DataSource(btcService, networkType); diff --git a/examples/core/tsconfig.build.json b/examples/core/tsconfig.build.json new file mode 100644 index 00000000..c5b3d86f --- /dev/null +++ b/examples/core/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "CommonJS", + "rootDir": "src", + "outDir": "lib", + "noEmit": false + }, + "include": ["src/**/*.ts", "src/*.ts"], +} diff --git a/examples/core/tsconfig.json b/examples/core/tsconfig.json new file mode 100644 index 00000000..671aefb7 --- /dev/null +++ b/examples/core/tsconfig.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "target": "ES2015", + "lib": ["dom", "dom.iterable", "esnext"], + "module": "ES2020", + "outDir": "./lib", + "composite": false, + "resolveJsonModule": true, + "strictNullChecks": true, + "noEmit": true, + "declaration": true, + "declarationMap": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "inlineSources": false, + "isolatedModules": true, + "moduleResolution": "node", + "noUnusedLocals": false, + "noUnusedParameters": false, + "preserveWatchOutput": true, + "skipLibCheck": true, + "strict": true + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "lib"] +} From 544f93958ad4a06470bffb49dd939cbc5fdc5f86 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Wed, 8 May 2024 20:30:16 +0800 Subject: [PATCH 25/78] refactor: Create xudt example package --- examples/xudt/.env.example | 11 -- examples/xudt/1-issue-xudt.ts | 2 +- examples/xudt/2-transfer-xudt.ts | 2 +- examples/xudt/package.json | 4 +- examples/xudt/src/core.ts | 256 ------------------------------- examples/xudt/tsconfig.json | 3 +- 6 files changed, 5 insertions(+), 273 deletions(-) delete mode 100644 examples/xudt/.env.example delete mode 100644 examples/xudt/src/core.ts diff --git a/examples/xudt/.env.example b/examples/xudt/.env.example deleted file mode 100644 index 097c23c4..00000000 --- a/examples/xudt/.env.example +++ /dev/null @@ -1,11 +0,0 @@ -# The secp256k1 private key whose format is 32bytes hex string with 0x prefix -CKB_SECP256K1_PRIVATE_KEY='0x-private-key' - -# Ture for CKB Mainnet and false for CKB Testnet, the default value is false -IS_MAINNET='false' - -# CKB node url which should be matched with IS_MAINNET -CKB_NODE_URL='https://testnet.ckb.dev/rpc' - -# CKB indexer url which should be matched with IS_MAINNET -CKB_INDEXER_URL='https://testnet.ckb.dev/indexer' \ No newline at end of file diff --git a/examples/xudt/1-issue-xudt.ts b/examples/xudt/1-issue-xudt.ts index 8ebb6f94..d4a16f78 100644 --- a/examples/xudt/1-issue-xudt.ts +++ b/examples/xudt/1-issue-xudt.ts @@ -1,5 +1,5 @@ import { RgbppTokenInfo } from '@rgbpp-sdk/ckb'; -import { issueXudt } from './src/core'; +import { issueXudt } from 'examples-core'; const XUDT_TOKEN_INFO: RgbppTokenInfo = { decimal: 8, diff --git a/examples/xudt/2-transfer-xudt.ts b/examples/xudt/2-transfer-xudt.ts index 28019144..1e4e09be 100644 --- a/examples/xudt/2-transfer-xudt.ts +++ b/examples/xudt/2-transfer-xudt.ts @@ -1,5 +1,5 @@ import { RgbppTokenInfo } from '@rgbpp-sdk/ckb'; -import { transferXudt } from './src/core'; +import { transferXudt } from 'examples-core'; const XUDT_TOKEN_INFO: RgbppTokenInfo = { decimal: 8, diff --git a/examples/xudt/package.json b/examples/xudt/package.json index ae148dc4..d09c40e3 100644 --- a/examples/xudt/package.json +++ b/examples/xudt/package.json @@ -10,7 +10,7 @@ "lint:fix": "tsc && eslint --fix --ext .ts . && prettier --write '**/*.ts'" }, "dependencies": { - "@nervosnetwork/ckb-sdk-utils": "^0.109.1", - "@rgbpp-sdk/ckb": "workspace:^" + "@rgbpp-sdk/ckb": "workspace:^", + "examples-core": "workspace:^" } } diff --git a/examples/xudt/src/core.ts b/examples/xudt/src/core.ts deleted file mode 100644 index 09095d0d..00000000 --- a/examples/xudt/src/core.ts +++ /dev/null @@ -1,256 +0,0 @@ -import { - AddressPrefix, - addressToScript, - getTransactionSize, - privateKeyToAddress, - scriptToHash, -} from '@nervosnetwork/ckb-sdk-utils'; -import { - getSecp256k1CellDep, - Collector, - RgbppTokenInfo, - NoLiveCellError, - calculateUdtCellCapacity, - MAX_FEE, - MIN_CAPACITY, - getXudtTypeScript, - append0x, - getUniqueTypeScript, - u128ToLe, - encodeRgbppTokenInfo, - getXudtDep, - getUniqueTypeDep, - SECP256K1_WITNESS_LOCK_SIZE, - calculateTransactionFee, - generateUniqueTypeArgs, - calculateXudtTokenInfoCellCapacity, - NoXudtLiveCellError, -} from '@rgbpp-sdk/ckb'; - -const collector = new Collector({ - ckbNodeUrl: process.env.CKB_NODE_URL!, - ckbIndexerUrl: process.env.CKB_INDEXER_URL!, -}); -const isMainnet = process.env.IS_MAINNET === 'true' ? true : false; -const CKB_PRIVATE_KEY = process.env.CKB_SECP256K1_PRIVATE_KEY!; - -export interface IssueResult { - txHash: string; - xudtType: CKBComponents.Script; -} - -/** - * issueXudt can be used to issue xUDT assets with unique cell as token info cell. - * @param xudtTotalAmount The xudtTotalAmount specifies the total amount of asset issuance - * @param tokenInfo The xUDT token info which includes decimal, name and symbol - */ -export const issueXudt = async ({ - xudtTotalAmount, - tokenInfo, -}: { - xudtTotalAmount: bigint; - tokenInfo: RgbppTokenInfo; -}): Promise => { - const issueAddress = privateKeyToAddress(CKB_PRIVATE_KEY, { - prefix: isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, - }); - console.log('ckb address: ', issueAddress); - - const issueLock = addressToScript(issueAddress); - - let emptyCells = await collector.getCells({ - lock: issueLock, - }); - if (!emptyCells || emptyCells.length === 0) { - throw new NoLiveCellError('The address has no empty cells'); - } - emptyCells = emptyCells.filter((cell) => !cell.output.type); - - const xudtCapacity = calculateUdtCellCapacity(issueLock); - const xudtInfoCapacity = calculateXudtTokenInfoCellCapacity(tokenInfo, issueLock); - - const txFee = MAX_FEE; - const { inputs, sumInputsCapacity } = collector.collectInputs(emptyCells, xudtCapacity + xudtInfoCapacity, txFee, { - minCapacity: MIN_CAPACITY, - }); - - const xudtType: CKBComponents.Script = { - ...getXudtTypeScript(isMainnet), - args: append0x(scriptToHash(issueLock)), - }; - - console.log('xUDT type script', xudtType); - - let changeCapacity = sumInputsCapacity - xudtCapacity - xudtInfoCapacity; - const outputs: CKBComponents.CellOutput[] = [ - { - lock: issueLock, - type: xudtType, - capacity: append0x(xudtCapacity.toString(16)), - }, - { - lock: issueLock, - type: { - ...getUniqueTypeScript(isMainnet), - args: generateUniqueTypeArgs(inputs[0], 1), - }, - capacity: append0x(xudtInfoCapacity.toString(16)), - }, - { - lock: issueLock, - capacity: append0x(changeCapacity.toString(16)), - }, - ]; - const totalAmount = xudtTotalAmount * BigInt(10 ** tokenInfo.decimal); - const outputsData = [append0x(u128ToLe(totalAmount)), encodeRgbppTokenInfo(tokenInfo), '0x']; - - const emptyWitness = { lock: '', inputType: '', outputType: '' }; - const witnesses = inputs.map((_, index) => (index === 0 ? emptyWitness : '0x')); - - const cellDeps = [getSecp256k1CellDep(isMainnet), getUniqueTypeDep(isMainnet), getXudtDep(isMainnet)]; - - const unsignedTx = { - version: '0x0', - cellDeps, - headerDeps: [], - inputs, - outputs, - outputsData, - witnesses, - }; - - if (txFee === MAX_FEE) { - const txSize = getTransactionSize(unsignedTx) + SECP256K1_WITNESS_LOCK_SIZE; - const estimatedTxFee = calculateTransactionFee(txSize); - changeCapacity -= estimatedTxFee; - unsignedTx.outputs[unsignedTx.outputs.length - 1].capacity = append0x(changeCapacity.toString(16)); - } - - const signedTx = collector.getCkb().signTransaction(CKB_PRIVATE_KEY)(unsignedTx); - const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); - - console.info(`xUDT asset on CKB has been issued and tx hash is ${txHash}`); - - return { txHash, xudtType }; -}; - -export interface TransferParams { - xudtType: CKBComponents.Script; - receivers: { - toAddress: string; - transferAmount: bigint; - }[]; -} - -/** - * transferXudt can be used to mint xUDT assets or transfer xUDT assets. - * @param xudtType The xUDT type script that comes from 1-issue-xudt - * @param receivers The receiver includes toAddress and transferAmount - */ -export const transferXudt = async ({ xudtType, receivers }: TransferParams) => { - const fromAddress = privateKeyToAddress(CKB_PRIVATE_KEY, { - prefix: isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, - }); - console.log('ckb address: ', fromAddress); - - const fromLock = addressToScript(fromAddress); - - const xudtCells = await collector.getCells({ - lock: fromLock, - type: xudtType, - }); - if (!xudtCells || xudtCells.length === 0) { - throw new NoXudtLiveCellError('The address has no xudt cells'); - } - const sumTransferAmount = receivers - .map((receiver) => receiver.transferAmount) - .reduce((prev, current) => prev + current, BigInt(0)); - - const { - inputs: udtInputs, - sumInputsCapacity: sumXudtInputsCapacity, - sumAmount, - } = collector.collectUdtInputs({ - liveCells: xudtCells, - needAmount: sumTransferAmount, - }); - let actualInputsCapacity = sumXudtInputsCapacity; - let inputs = udtInputs; - - const xudtCapacity = calculateUdtCellCapacity(fromLock); - const sumXudtCapacity = xudtCapacity * BigInt(receivers.length); - - const outputs: CKBComponents.CellOutput[] = receivers.map((receiver) => ({ - lock: addressToScript(receiver.toAddress), - type: xudtType, - capacity: append0x(xudtCapacity.toString(16)), - })); - const outputsData = receivers.map((receiver) => append0x(u128ToLe(receiver.transferAmount))); - - const txFee = MAX_FEE; - if (sumXudtInputsCapacity < sumXudtCapacity) { - let emptyCells = await collector.getCells({ - lock: fromLock, - }); - if (!emptyCells || emptyCells.length === 0) { - throw new NoLiveCellError('The address has no empty cells'); - } - emptyCells = emptyCells.filter((cell) => !cell.output.type); - const needCapacity = sumXudtCapacity - sumXudtInputsCapacity + xudtCapacity; - const { inputs: emptyInputs, sumInputsCapacity: sumEmptyCapacity } = collector.collectInputs( - emptyCells, - needCapacity, - txFee, - { minCapacity: MIN_CAPACITY }, - ); - inputs = [...inputs, ...emptyInputs]; - actualInputsCapacity += sumEmptyCapacity; - } - - let changeCapacity = actualInputsCapacity - sumXudtCapacity; - if (sumAmount > sumTransferAmount) { - outputs.push({ - lock: fromLock, - type: xudtType, - capacity: append0x(xudtCapacity.toString(16)), - }); - outputsData.push(append0x(u128ToLe(sumAmount - sumTransferAmount))); - changeCapacity -= xudtCapacity; - } - - outputs.push({ - lock: fromLock, - type: xudtType, - capacity: append0x(changeCapacity.toString(16)), - }); - outputsData.push('0x'); - - const emptyWitness = { lock: '', inputType: '', outputType: '' }; - const witnesses = inputs.map((_, index) => (index === 0 ? emptyWitness : '0x')); - - const cellDeps = [getSecp256k1CellDep(isMainnet), getUniqueTypeDep(isMainnet), getXudtDep(isMainnet)]; - - const unsignedTx = { - version: '0x0', - cellDeps, - headerDeps: [], - inputs, - outputs, - outputsData, - witnesses, - }; - - if (txFee === MAX_FEE) { - const txSize = getTransactionSize(unsignedTx) + SECP256K1_WITNESS_LOCK_SIZE; - const estimatedTxFee = calculateTransactionFee(txSize); - changeCapacity -= estimatedTxFee; - unsignedTx.outputs[unsignedTx.outputs.length - 1].capacity = append0x(changeCapacity.toString(16)); - } - - const signedTx = collector.getCkb().signTransaction(CKB_PRIVATE_KEY)(unsignedTx); - const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); - - console.info(`xUDT asset has been minted or transferred and tx hash is ${txHash}`); - - return txHash; -}; diff --git a/examples/xudt/tsconfig.json b/examples/xudt/tsconfig.json index 07484ac0..41f00618 100644 --- a/examples/xudt/tsconfig.json +++ b/examples/xudt/tsconfig.json @@ -21,6 +21,5 @@ "skipLibCheck": true, "strict": true }, - "include": ["src/*.ts", "*.ts"], "exclude": ["node_modules"] -} +} \ No newline at end of file From d3ec6b573b600794eadf53fa0a198aa5695dc2a0 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Wed, 8 May 2024 20:30:53 +0800 Subject: [PATCH 26/78] refactor: Use env variables for rgbpp xudt examples --- examples/rgbpp/xudt/1-ckb-jump-btc.ts | 9 ++ examples/rgbpp/xudt/2-btc-transfer.ts | 33 +++++ examples/rgbpp/xudt/3-btc-jump-ckb.ts | 34 ++++++ .../rgbpp/xudt/launch/0-rgbpp-token-info.ts | 7 ++ .../rgbpp/xudt/launch/1-prepare-launch.ts | 88 ++++++++++++++ examples/rgbpp/xudt/launch/2-launch-rgbpp.ts | 80 ++++++++++++ .../rgbpp/xudt/launch/3-distribute-rgbpp.ts | 115 ++++++++++++++++++ examples/rgbpp/xudt/local/1-ckb-jump-btc.ts | 44 +++++++ examples/rgbpp/xudt/local/2-btc-transfer.ts | 88 ++++++++++++++ examples/rgbpp/xudt/local/3-btc-jump-ckb.ts | 90 ++++++++++++++ .../rgbpp/xudt/local/4-spend-btc-time-cell.ts | 42 +++++++ 11 files changed, 630 insertions(+) create mode 100644 examples/rgbpp/xudt/1-ckb-jump-btc.ts create mode 100644 examples/rgbpp/xudt/2-btc-transfer.ts create mode 100644 examples/rgbpp/xudt/3-btc-jump-ckb.ts create mode 100644 examples/rgbpp/xudt/launch/0-rgbpp-token-info.ts create mode 100644 examples/rgbpp/xudt/launch/1-prepare-launch.ts create mode 100644 examples/rgbpp/xudt/launch/2-launch-rgbpp.ts create mode 100644 examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts create mode 100644 examples/rgbpp/xudt/local/1-ckb-jump-btc.ts create mode 100644 examples/rgbpp/xudt/local/2-btc-transfer.ts create mode 100644 examples/rgbpp/xudt/local/3-btc-jump-ckb.ts create mode 100644 examples/rgbpp/xudt/local/4-spend-btc-time-cell.ts diff --git a/examples/rgbpp/xudt/1-ckb-jump-btc.ts b/examples/rgbpp/xudt/1-ckb-jump-btc.ts new file mode 100644 index 00000000..05a626d4 --- /dev/null +++ b/examples/rgbpp/xudt/1-ckb-jump-btc.ts @@ -0,0 +1,9 @@ +import { leapFromCkbToBtc } from 'examples-core'; + +// Use your real BTC UTXO information on the BTC Testnet +leapFromCkbToBtc({ + outIndex: 1, + btcTxId: '4ff1855b64b309afa19a8b9be3d4da99dcb18b083b65d2d851662995c7d99e7a', + xudtTypeArgs: '0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b', + transferAmount: BigInt(800_0000_0000), +}); diff --git a/examples/rgbpp/xudt/2-btc-transfer.ts b/examples/rgbpp/xudt/2-btc-transfer.ts new file mode 100644 index 00000000..52f1e591 --- /dev/null +++ b/examples/rgbpp/xudt/2-btc-transfer.ts @@ -0,0 +1,33 @@ +import { buildRgbppLockArgs } from '@rgbpp-sdk/ckb'; +import { RgbppTransferParams, btcService, transferRgbppOnBtc } from 'examples-core'; + +const transfer = async (params: RgbppTransferParams) => { + const btcTxId = await transferRgbppOnBtc(params); + + try { + const interval = setInterval(async () => { + const { state, failedReason } = await btcService.getRgbppTransactionState(btcTxId); + console.log('state', state); + if (state === 'completed' || state === 'failed') { + clearInterval(interval); + if (state === 'completed') { + const { txhash: txHash } = await btcService.getRgbppTransactionHash(btcTxId); + console.info(`Rgbpp asset has been transferred on BTC and the related CKB tx hash is ${txHash}`); + } else { + console.warn(`Rgbpp CKB transaction failed and the reason is ${failedReason} `); + } + } + }, 30 * 1000); + } catch (error) { + console.error(error); + } +}; + +// Use your real BTC UTXO information on the BTC Testnet +// rgbppLockArgs: outIndexU32 + btcTxId +transfer({ + rgbppLockArgsList: [buildRgbppLockArgs(1, '64252b582aea1249ed969a20385fae48bba35bf1ab9b3df3b0fcddc754ccf592')], + toBtcAddress: 'tb1qvt7p9g6mw70sealdewtfp0sekquxuru6j3gwmt', + xudtTypeArgs: '0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b', + transferAmount: BigInt(800_0000_0000), +}); diff --git a/examples/rgbpp/xudt/3-btc-jump-ckb.ts b/examples/rgbpp/xudt/3-btc-jump-ckb.ts new file mode 100644 index 00000000..cbb917f2 --- /dev/null +++ b/examples/rgbpp/xudt/3-btc-jump-ckb.ts @@ -0,0 +1,34 @@ +import { buildRgbppLockArgs } from '@rgbpp-sdk/ckb'; +import { LeapToCkbParams, btcService, leapFromBtcToCkb } from 'examples-core'; + +const leapToCKB = async (params: LeapToCkbParams) => { + const btcTxId = await leapFromBtcToCkb(params); + + try { + const interval = setInterval(async () => { + const { state, failedReason } = await btcService.getRgbppTransactionState(btcTxId); + console.log('state', state); + if (state === 'completed' || state === 'failed') { + clearInterval(interval); + if (state === 'completed') { + const { txhash: txHash } = await btcService.getRgbppTransactionHash(btcTxId); + console.info(`Rgbpp asset has been jumped from BTC to CKB and the related CKB tx hash is ${txHash}`); + } else { + console.warn(`Rgbpp CKB transaction failed and the reason is ${failedReason} `); + } + } + }, 30 * 1000); + } catch (error) { + console.error(error); + } +}; + +// rgbppLockArgs: outIndexU32 + btcTxId +leapToCKB({ + // If the `2-btc-transfer.ts` has been executed, the BTC txId should be the new generated BTC txId by the `2-btc-transfer.ts` + // Otherwise the BTC txId should be same as the the BTC txId of the `1-ckb-jump-btc.ts` + rgbppLockArgsList: [buildRgbppLockArgs(1, '6edd4b9327506fab09fb9a0f5e5f35136a6a94bd4c9dd79af04921618fa6c800')], + toCkbAddress: 'ckt1qrfrwcdnvssswdwpn3s9v8fp87emat306ctjwsm3nmlkjg8qyza2cqgqq9kxr7vy7yknezj0vj0xptx6thk6pwyr0sxamv6q', + xudtTypeArgs: '0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b', + transferAmount: BigInt(800_0000_0000), +}); diff --git a/examples/rgbpp/xudt/launch/0-rgbpp-token-info.ts b/examples/rgbpp/xudt/launch/0-rgbpp-token-info.ts new file mode 100644 index 00000000..67a7cc39 --- /dev/null +++ b/examples/rgbpp/xudt/launch/0-rgbpp-token-info.ts @@ -0,0 +1,7 @@ +import { RgbppTokenInfo } from '@rgbpp-sdk/ckb'; + +export const RGBPP_TOKEN_INFO: RgbppTokenInfo = { + decimal: 8, + name: 'RGBPP Test Token', + symbol: 'RTT', +}; diff --git a/examples/rgbpp/xudt/launch/1-prepare-launch.ts b/examples/rgbpp/xudt/launch/1-prepare-launch.ts new file mode 100644 index 00000000..a5910b38 --- /dev/null +++ b/examples/rgbpp/xudt/launch/1-prepare-launch.ts @@ -0,0 +1,88 @@ +import { addressToScript, getTransactionSize } from '@nervosnetwork/ckb-sdk-utils'; +import { + MAX_FEE, + NoLiveCellError, + RgbppTokenInfo, + SECP256K1_WITNESS_LOCK_SIZE, + append0x, + buildRgbppLockArgs, + calculateRgbppCellCapacity, + calculateRgbppTokenInfoCellCapacity, + calculateTransactionFee, + genRgbppLockScript, + getSecp256k1CellDep, +} from '@rgbpp-sdk/ckb'; +import { RGBPP_TOKEN_INFO } from './0-rgbpp-token-info'; +import { CKB_PRIVATE_KEY, ckbAddress, collector, isMainnet } from 'examples-core'; + +const prepareLaunchCell = async ({ + outIndex, + btcTxId, + rgbppTokenInfo, +}: { + outIndex: number; + btcTxId: string; + rgbppTokenInfo: RgbppTokenInfo; +}) => { + const masterLock = addressToScript(ckbAddress); + console.log('ckb address: ', ckbAddress); + + // The capacity required to launch cells is determined by the token info cell capacity, and transaction fee. + const launchCellCapacity = + calculateRgbppCellCapacity() + calculateRgbppTokenInfoCellCapacity(rgbppTokenInfo, isMainnet); + + let emptyCells = await collector.getCells({ + lock: masterLock, + }); + if (!emptyCells || emptyCells.length === 0) { + throw new NoLiveCellError('The address has no empty cells'); + } + emptyCells = emptyCells.filter((cell) => !cell.output.type); + + const txFee = MAX_FEE; + const { inputs, sumInputsCapacity } = collector.collectInputs(emptyCells, launchCellCapacity, txFee); + + const outputs: CKBComponents.CellOutput[] = [ + { + lock: genRgbppLockScript(buildRgbppLockArgs(outIndex, btcTxId), isMainnet), + capacity: append0x(launchCellCapacity.toString(16)), + }, + ]; + let changeCapacity = sumInputsCapacity - launchCellCapacity; + outputs.push({ + lock: masterLock, + capacity: append0x(changeCapacity.toString(16)), + }); + const outputsData = ['0x', '0x']; + + const emptyWitness = { lock: '', inputType: '', outputType: '' }; + const witnesses = inputs.map((_, index) => (index === 0 ? emptyWitness : '0x')); + + const cellDeps = [getSecp256k1CellDep(isMainnet)]; + + const unsignedTx = { + version: '0x0', + cellDeps, + headerDeps: [], + inputs, + outputs, + outputsData, + witnesses, + }; + + const txSize = getTransactionSize(unsignedTx) + SECP256K1_WITNESS_LOCK_SIZE; + const estimatedTxFee = calculateTransactionFee(txSize); + changeCapacity -= estimatedTxFee; + unsignedTx.outputs[unsignedTx.outputs.length - 1].capacity = append0x(changeCapacity.toString(16)); + + const signedTx = collector.getCkb().signTransaction(CKB_PRIVATE_KEY)(unsignedTx); + const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); + + console.info(`Launch cell has been created and the tx hash ${txHash}`); +}; + +prepareLaunchCell({ + outIndex: 1, + btcTxId: '6259ea7852e294afbd2aaf9ccd5c9c1f95087b0b08ba7e47ae35ce31170732bc', + rgbppTokenInfo: RGBPP_TOKEN_INFO, +}); diff --git a/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts b/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts new file mode 100644 index 00000000..cdba02b6 --- /dev/null +++ b/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts @@ -0,0 +1,80 @@ +import { + buildRgbppLockArgs, + genRgbppLaunchCkbVirtualTx, + RgbppTokenInfo, + appendCkbTxWitnesses, + updateCkbTxWithRealBtcTxId, + sendCkbTx, +} from '@rgbpp-sdk/ckb'; +import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; +import { BtcAssetsApiError } from '@rgbpp-sdk/service'; +import { RGBPP_TOKEN_INFO } from './0-rgbpp-token-info'; +import { btcAddress, btcDataSource, btcKeyPair, btcService, collector, isMainnet } from 'examples-core'; + +interface Params { + ownerRgbppLockArgs: string; + launchAmount: bigint; + rgbppTokenInfo: RgbppTokenInfo; +} +const launchRgppAsset = async ({ ownerRgbppLockArgs, launchAmount, rgbppTokenInfo }: Params) => { + const ckbVirtualTxResult = await genRgbppLaunchCkbVirtualTx({ + collector, + ownerRgbppLockArgs, + rgbppTokenInfo, + launchAmount, + isMainnet, + }); + + const { commitment, ckbRawTx } = ckbVirtualTxResult; + + console.log('RGB++ Asset type script args: ', ckbRawTx.outputs[0].type?.args); + + // Send BTC tx + const psbt = await sendRgbppUtxos({ + ckbVirtualTx: ckbRawTx, + commitment, + tos: [btcAddress!], + ckbCollector: collector, + from: btcAddress!, + source: btcDataSource, + }); + psbt.signAllInputs(btcKeyPair); + psbt.finalizeAllInputs(); + + const btcTx = psbt.extractTransaction(); + const btcTxBytes = transactionToHex(btcTx, false); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); + + console.log('BTC TxId: ', btcTxId); + + const interval = setInterval(async () => { + try { + console.log('Waiting for BTC tx and proof to be ready'); + const rgbppApiSpvProof = await btcService.getRgbppSpvProof(btcTxId, 0); + clearInterval(interval); + // Update CKB transaction with the real BTC txId + const newCkbRawTx = updateCkbTxWithRealBtcTxId({ ckbRawTx, btcTxId, isMainnet }); + const ckbTx = await appendCkbTxWitnesses({ + ckbRawTx: newCkbRawTx, + btcTxBytes, + rgbppApiSpvProof, + }); + + const txHash = await sendCkbTx({ collector, signedTx: ckbTx }); + console.info(`RGB++ Asset has been launched and tx hash is ${txHash}`); + } catch (error) { + if (!(error instanceof BtcAssetsApiError)) { + console.error(error); + } + } + }, 30 * 1000); +}; + +// Use your real BTC UTXO information on the BTC Testnet +// rgbppLockArgs: outIndexU32 + btcTxId +launchRgppAsset({ + ownerRgbppLockArgs: buildRgbppLockArgs(1, '6259ea7852e294afbd2aaf9ccd5c9c1f95087b0b08ba7e47ae35ce31170732bc'), + rgbppTokenInfo: RGBPP_TOKEN_INFO, + // The total issuance amount of RGBPP Token, the decimal is determined by RGBPP Token info + launchAmount: BigInt(2100_0000) * BigInt(10 ** RGBPP_TOKEN_INFO.decimal), +}); diff --git a/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts b/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts new file mode 100644 index 00000000..d114ccd9 --- /dev/null +++ b/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts @@ -0,0 +1,115 @@ +import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; +import { + RgbppBtcAddressReceiver, + appendCkbTxWitnesses, + appendIssuerCellToBtcBatchTransfer, + buildRgbppLockArgs, + genBtcBatchTransferCkbVirtualTx, + getXudtTypeScript, + sendCkbTx, + updateCkbTxWithRealBtcTxId, +} from '@rgbpp-sdk/ckb'; +import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; +import { BtcAssetsApiError } from '@rgbpp-sdk/service'; +import { RGBPP_TOKEN_INFO } from './0-rgbpp-token-info'; +import { + isMainnet, + collector, + btcAddress, + btcDataSource, + btcKeyPair, + btcService, + CKB_PRIVATE_KEY, + ckbAddress, +} from 'examples-core'; + +interface Params { + rgbppLockArgsList: string[]; + receivers: RgbppBtcAddressReceiver[]; + xudtTypeArgs: string; +} +const distributeRgbppAssetOnBtc = async ({ rgbppLockArgsList, receivers, xudtTypeArgs }: Params) => { + // Warning: Please replace with your real xUDT type script here + const xudtType: CKBComponents.Script = { + ...getXudtTypeScript(isMainnet), + // The xUDT type script args is generated by 2-launch-rgbpp.ts, and it can be found from the log + args: xudtTypeArgs, + }; + + const ckbVirtualTxResult = await genBtcBatchTransferCkbVirtualTx({ + collector, + rgbppLockArgsList, + xudtTypeBytes: serializeScript(xudtType), + rgbppReceivers: receivers, + isMainnet, + }); + + const { commitment, ckbRawTx, sumInputsCapacity, rgbppChangeOutIndex } = ckbVirtualTxResult; + + // The first output utxo is OP_RETURN + // Rgbpp change utxo position depends on the number of distributions, if 50 addresses are distributed, then the change utxo position is 51 + console.log('RGB++ asset change utxo out index: ', rgbppChangeOutIndex); + + // Send BTC tx + const psbt = await sendRgbppUtxos({ + ckbVirtualTx: ckbRawTx, + commitment, + tos: receivers.map((receiver) => receiver.toBtcAddress), + ckbCollector: collector, + from: btcAddress!, + source: btcDataSource, + }); + psbt.signAllInputs(btcKeyPair); + psbt.finalizeAllInputs(); + + const btcTx = psbt.extractTransaction(); + const btcTxBytes = transactionToHex(btcTx, false); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); + + console.log('BTC TxId: ', btcTxId); + + const interval = setInterval(async () => { + try { + console.log('Waiting for BTC tx and proof to be ready'); + const rgbppApiSpvProof = await btcService.getRgbppSpvProof(btcTxId, 0); + clearInterval(interval); + // Update CKB transaction with the real BTC txId + const newCkbRawTx = updateCkbTxWithRealBtcTxId({ ckbRawTx, btcTxId, isMainnet }); + const ckbTx = await appendCkbTxWitnesses({ + ckbRawTx: newCkbRawTx, + btcTxBytes, + rgbppApiSpvProof, + }); + + const signedTx = await appendIssuerCellToBtcBatchTransfer({ + secp256k1PrivateKey: CKB_PRIVATE_KEY, + issuerAddress: ckbAddress, + ckbRawTx: ckbTx, + collector, + sumInputsCapacity, + isMainnet, + }); + + const txHash = await sendCkbTx({ collector, signedTx }); + console.info(`RGB++ Asset has been distributed and tx hash is ${txHash}`); + } catch (error) { + if (!(error instanceof BtcAssetsApiError)) { + console.error(error); + } + } + }, 20 * 1000); +}; + +// Use your real BTC UTXO information on the BTC Testnet +// rgbppLockArgs: outIndexU32 + btcTxId +distributeRgbppAssetOnBtc({ + // Warning: If rgbpp assets are distributed continuously, then the position of the current rgbpp asset utxo depends on the position of the previous change utxo distributed + rgbppLockArgsList: [buildRgbppLockArgs(2, '012bfee9c1e8a6e9e272b63ff54d5138efe910cc7aac413221cb3634ea176866')], + xudtTypeArgs: '0x4c1ecf2f14edae73b76ccf115ecfa40ba68ee315c96bd4fcfd771c2fb4c69e8f', + receivers: [ + { + toBtcAddress: 'bc1p0ey32x7dwhlx569rh0l5qaxetsfnpvezanrezahelr0t02ytyegssdel0h', + transferAmount: BigInt(1000) * BigInt(10 ** RGBPP_TOKEN_INFO.decimal), + }, + ], +}); diff --git a/examples/rgbpp/xudt/local/1-ckb-jump-btc.ts b/examples/rgbpp/xudt/local/1-ckb-jump-btc.ts new file mode 100644 index 00000000..a80e86b9 --- /dev/null +++ b/examples/rgbpp/xudt/local/1-ckb-jump-btc.ts @@ -0,0 +1,44 @@ +import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; +import { genCkbJumpBtcVirtualTx, getSecp256k1CellDep, buildRgbppLockArgs, getXudtTypeScript } from '@rgbpp-sdk/ckb'; +import { isMainnet, collector, ckbAddress, LeapToBtcParams } from 'examples-core'; + +// CKB SECP256K1 private key +const CKB_TEST_PRIVATE_KEY = '0x0000000000000000000000000000000000000000000000000000000000000001'; + +const leapToBtc = async ({ outIndex, btcTxId, xudtTypeArgs, transferAmount }: LeapToBtcParams) => { + const toRgbppLockArgs = buildRgbppLockArgs(outIndex, btcTxId); + + // Warning: Please replace with your real xUDT type script here + const xudtType: CKBComponents.Script = { + ...getXudtTypeScript(isMainnet), + args: xudtTypeArgs, + }; + + const ckbRawTx = await genCkbJumpBtcVirtualTx({ + collector, + fromCkbAddress: ckbAddress, + toRgbppLockArgs, + xudtTypeBytes: serializeScript(xudtType), + transferAmount, + }); + + const emptyWitness = { lock: '', inputType: '', outputType: '' }; + const unsignedTx: CKBComponents.RawTransactionToSign = { + ...ckbRawTx, + cellDeps: [...ckbRawTx.cellDeps, getSecp256k1CellDep(isMainnet)], + witnesses: [emptyWitness, ...ckbRawTx.witnesses.slice(1)], + }; + + const signedTx = collector.getCkb().signTransaction(CKB_TEST_PRIVATE_KEY)(unsignedTx); + + const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); + console.info(`Rgbpp asset has been jumped from CKB to BTC and tx hash is ${txHash}`); +}; + +// Use your real BTC UTXO information on the BTC Testnet +leapToBtc({ + outIndex: 1, + btcTxId: '4ff1855b64b309afa19a8b9be3d4da99dcb18b083b65d2d851662995c7d99e7a', + xudtTypeArgs: '0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b', + transferAmount: BigInt(800_0000_0000), +}); diff --git a/examples/rgbpp/xudt/local/2-btc-transfer.ts b/examples/rgbpp/xudt/local/2-btc-transfer.ts new file mode 100644 index 00000000..67a426e6 --- /dev/null +++ b/examples/rgbpp/xudt/local/2-btc-transfer.ts @@ -0,0 +1,88 @@ +import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; +import { + appendCkbTxWitnesses, + buildRgbppLockArgs, + genBtcTransferCkbVirtualTx, + sendCkbTx, + getXudtTypeScript, + updateCkbTxWithRealBtcTxId, +} from '@rgbpp-sdk/ckb'; +import { transactionToHex, sendRgbppUtxos } from '@rgbpp-sdk/btc'; +import { BtcAssetsApiError } from '@rgbpp-sdk/service'; +import { + RgbppTransferParams, + isMainnet, + collector, + btcAddress, + btcDataSource, + btcKeyPair, + btcService, +} from 'examples-core'; + +const transfer = async ({ rgbppLockArgsList, toBtcAddress, xudtTypeArgs, transferAmount }: RgbppTransferParams) => { + const xudtType: CKBComponents.Script = { + ...getXudtTypeScript(isMainnet), + args: xudtTypeArgs, + }; + + const ckbVirtualTxResult = await genBtcTransferCkbVirtualTx({ + collector, + rgbppLockArgsList, + xudtTypeBytes: serializeScript(xudtType), + transferAmount, + isMainnet, + }); + + const { commitment, ckbRawTx } = ckbVirtualTxResult; + + // Send BTC tx + const psbt = await sendRgbppUtxos({ + ckbVirtualTx: ckbRawTx, + commitment, + tos: [toBtcAddress], + ckbCollector: collector, + from: btcAddress!, + source: btcDataSource, + }); + psbt.signAllInputs(btcKeyPair); + psbt.finalizeAllInputs(); + + const btcTx = psbt.extractTransaction(); + // Remove the witness from BTC tx for RGBPP unlock + const btcTxBytes = transactionToHex(btcTx, false); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); + + console.log('BTC TxId: ', btcTxId); + + // Wait for BTC tx and proof to be ready, and then send isomorphic CKB transactions + const interval = setInterval(async () => { + try { + console.log('Waiting for BTC tx and proof to be ready'); + const rgbppApiSpvProof = await btcService.getRgbppSpvProof(btcTxId, 0); + clearInterval(interval); + // Update CKB transaction with the real BTC txId + const newCkbRawTx = updateCkbTxWithRealBtcTxId({ ckbRawTx, btcTxId, isMainnet }); + const ckbTx = await appendCkbTxWitnesses({ + ckbRawTx: newCkbRawTx, + btcTxBytes, + rgbppApiSpvProof, + }); + + const txHash = await sendCkbTx({ collector, signedTx: ckbTx }); + console.info(`RGB++ Asset has been transferred on BTC and the CKB tx hash is ${txHash}`); + } catch (error) { + if (!(error instanceof BtcAssetsApiError)) { + console.error(error); + } + } + }, 30 * 1000); +}; + +// Use your real BTC UTXO information on the BTC Testnet +// rgbppLockArgs: outIndexU32 + btcTxId +transfer({ + rgbppLockArgsList: [buildRgbppLockArgs(1, '70b250e2a3cc7a33b47f7a4e94e41e1ee2501ce73b393d824db1dd4c872c5348')], + toBtcAddress: 'tb1qvt7p9g6mw70sealdewtfp0sekquxuru6j3gwmt', + xudtTypeArgs: '0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b', + transferAmount: BigInt(800_0000_0000), +}); diff --git a/examples/rgbpp/xudt/local/3-btc-jump-ckb.ts b/examples/rgbpp/xudt/local/3-btc-jump-ckb.ts new file mode 100644 index 00000000..8dc2040a --- /dev/null +++ b/examples/rgbpp/xudt/local/3-btc-jump-ckb.ts @@ -0,0 +1,90 @@ +import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; +import { + appendCkbTxWitnesses, + genBtcJumpCkbVirtualTx, + sendCkbTx, + getXudtTypeScript, + updateCkbTxWithRealBtcTxId, + buildRgbppLockArgs, +} from '@rgbpp-sdk/ckb'; +import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; +import { BtcAssetsApiError } from '@rgbpp-sdk/service'; +import { + LeapToCkbParams, + isMainnet, + collector, + btcAddress, + btcDataSource, + btcKeyPair, + btcService, +} from 'examples-core'; + +const jumpFromBtcToCkb = async ({ rgbppLockArgsList, toCkbAddress, xudtTypeArgs, transferAmount }: LeapToCkbParams) => { + const xudtType: CKBComponents.Script = { + ...getXudtTypeScript(isMainnet), + args: xudtTypeArgs, + }; + + const ckbVirtualTxResult = await genBtcJumpCkbVirtualTx({ + collector, + rgbppLockArgsList, + xudtTypeBytes: serializeScript(xudtType), + transferAmount, + toCkbAddress, + isMainnet, + }); + + const { commitment, ckbRawTx } = ckbVirtualTxResult; + + // Send BTC tx + const psbt = await sendRgbppUtxos({ + ckbVirtualTx: ckbRawTx, + commitment, + tos: [btcAddress!], + ckbCollector: collector, + from: btcAddress!, + source: btcDataSource, + }); + psbt.signAllInputs(btcKeyPair); + psbt.finalizeAllInputs(); + + const btcTx = psbt.extractTransaction(); + // Remove the witness from BTC tx for RGBPP unlock + const btcTxBytes = transactionToHex(btcTx, false); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); + + console.log('BTC Tx bytes: ', btcTxBytes); + console.log('BTC TxId: ', btcTxId); + console.log('ckbRawTx', JSON.stringify(ckbRawTx)); + + // Wait for BTC tx and proof to be ready, and then send isomorphic CKB transactions + const interval = setInterval(async () => { + try { + console.log('Waiting for BTC tx and proof to be ready'); + const rgbppApiSpvProof = await btcService.getRgbppSpvProof(btcTxId, 0); + clearInterval(interval); + // Update CKB transaction with the real BTC txId + const newCkbRawTx = updateCkbTxWithRealBtcTxId({ ckbRawTx, btcTxId, isMainnet }); + const ckbTx = await appendCkbTxWitnesses({ + ckbRawTx: newCkbRawTx, + btcTxBytes, + rgbppApiSpvProof, + }); + + const txHash = await sendCkbTx({ collector, signedTx: ckbTx }); + console.info(`RGB++ Asset has been leaped from BTC to CKB and the CKB tx hash is ${txHash}`); + } catch (error) { + if (!(error instanceof BtcAssetsApiError)) { + console.error(error); + } + } + }, 30 * 1000); +}; + +// rgbppLockArgs: outIndexU32 + btcTxId +jumpFromBtcToCkb({ + rgbppLockArgsList: [buildRgbppLockArgs(1, '24e622419156dd3a277a90bcbb40c7117462a18d5329dd1ada320ca8bdfba715')], + toCkbAddress: 'ckt1qrfrwcdnvssswdwpn3s9v8fp87emat306ctjwsm3nmlkjg8qyza2cqgqq9kxr7vy7yknezj0vj0xptx6thk6pwyr0sxamv6q', + xudtTypeArgs: '0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b', + transferAmount: BigInt(800_0000_0000), +}); diff --git a/examples/rgbpp/xudt/local/4-spend-btc-time-cell.ts b/examples/rgbpp/xudt/local/4-spend-btc-time-cell.ts new file mode 100644 index 00000000..242f3a74 --- /dev/null +++ b/examples/rgbpp/xudt/local/4-spend-btc-time-cell.ts @@ -0,0 +1,42 @@ +import { sendCkbTx, buildBtcTimeCellsSpentTx, getBtcTimeLockScript, signBtcTimeCellSpentTx } from '@rgbpp-sdk/ckb'; +import { CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from 'examples-core'; + +// Warning: Wait at least 6 BTC confirmation blocks to spend the BTC time cells after 4-btc-jump-ckb.ts +const spendBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: string }) => { + const btcTimeCells = await collector.getCells({ + lock: { + ...getBtcTimeLockScript(false), + args: btcTimeCellArgs, + }, + isDataMustBeEmpty: false, + }); + + if (!btcTimeCells || btcTimeCells.length === 0) { + throw new Error('No btc time cell found'); + } + + const ckbRawTx: CKBComponents.RawTransaction = await buildBtcTimeCellsSpentTx({ + btcTimeCells, + btcAssetsApi: btcService, + isMainnet, + }); + + const signedTx = await signBtcTimeCellSpentTx({ + secp256k1PrivateKey: CKB_PRIVATE_KEY, + collector, + masterCkbAddress: ckbAddress, + ckbRawTx, + isMainnet, + }); + + console.log(JSON.stringify(signedTx)); + + const txHash = await sendCkbTx({ collector, signedTx }); + console.info(`BTC time cell has been spent and tx hash is ${txHash}`); +}; + +// The btcTimeCellArgs is from the outputs[0].lock.args(BTC Time lock args) of the 4-btc-jump-ckb.ts CKB transaction +spendBtcTimeCell({ + btcTimeCellArgs: + '0x7f000000100000005b0000005f0000004b000000100000003000000031000000d23761b364210735c19c60561d213fb3beae2fd6172743719eff6920e020baac011600000000016c61f984f12d3c8a4f649e60acda5deda0b8837c060000001c95b9d726e4ab337d6a4572680598947954d7b6ff4f1e767e605eeeec49e7ed', +}); From 65a92fd0587e350a04b0c1fdf865a42986f54ff3 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Wed, 8 May 2024 20:31:40 +0800 Subject: [PATCH 27/78] refactor: Use env veriables for rgbpp spore examples --- examples/rgbpp/local/1-ckb-jump-btc.ts | 57 -------- examples/rgbpp/local/2-btc-transfer.ts | 114 --------------- examples/rgbpp/local/3-btc-jump-ckb.ts | 117 --------------- examples/rgbpp/local/4-spend-btc-time-cell.ts | 70 --------- examples/rgbpp/local/batch/1-ckb-jump-btc.ts | 63 -------- .../rgbpp/local/launch/0-rgbpp-token-info.ts | 7 - .../rgbpp/local/launch/1-prepare-launch.ts | 99 ------------- examples/rgbpp/local/launch/2-launch-rgbpp.ts | 108 -------------- .../rgbpp/local/launch/3-distribute-rgbpp.ts | 138 ------------------ examples/rgbpp/local/transfer-btc.ts | 47 ------ examples/rgbpp/package.json | 4 +- examples/rgbpp/queue/1-ckb-jump-btc.ts | 57 -------- examples/rgbpp/queue/2-btc-transfer.ts | 100 ------------- examples/rgbpp/queue/3-btc-jump-ckb.ts | 101 ------------- .../queue/no-merge-outputs/2-btc-transfer.ts | 103 ------------- examples/rgbpp/spore/1-prepare-cluster.ts | 21 +-- examples/rgbpp/spore/2-create-cluster.ts | 42 +----- examples/rgbpp/spore/3-create-spores.ts | 69 +++------ examples/rgbpp/spore/4-transfer-spore.ts | 106 ++++---------- examples/rgbpp/spore/5-leap-spore-to-ckb.ts | 103 ++++--------- .../rgbpp/spore/6-unlock-btc-time-cell.ts | 39 +---- examples/rgbpp/spore/7-leap-spore-to-btc.ts | 36 ++--- .../rgbpp/spore/local/4-transfer-spore.ts | 98 +++++++++++++ .../rgbpp/spore/local/5-leap-spore-to-ckb.ts | 98 +++++++++++++ .../rgbpp/spore/queue/4-transfer-spore.ts | 102 ------------- .../rgbpp/spore/queue/5-leap-spore-to-ckb.ts | 109 -------------- examples/rgbpp/tsconfig.json | 2 +- 27 files changed, 308 insertions(+), 1702 deletions(-) delete mode 100644 examples/rgbpp/local/1-ckb-jump-btc.ts delete mode 100644 examples/rgbpp/local/2-btc-transfer.ts delete mode 100644 examples/rgbpp/local/3-btc-jump-ckb.ts delete mode 100644 examples/rgbpp/local/4-spend-btc-time-cell.ts delete mode 100644 examples/rgbpp/local/batch/1-ckb-jump-btc.ts delete mode 100644 examples/rgbpp/local/launch/0-rgbpp-token-info.ts delete mode 100644 examples/rgbpp/local/launch/1-prepare-launch.ts delete mode 100644 examples/rgbpp/local/launch/2-launch-rgbpp.ts delete mode 100644 examples/rgbpp/local/launch/3-distribute-rgbpp.ts delete mode 100644 examples/rgbpp/local/transfer-btc.ts delete mode 100644 examples/rgbpp/queue/1-ckb-jump-btc.ts delete mode 100644 examples/rgbpp/queue/2-btc-transfer.ts delete mode 100644 examples/rgbpp/queue/3-btc-jump-ckb.ts delete mode 100644 examples/rgbpp/queue/no-merge-outputs/2-btc-transfer.ts create mode 100644 examples/rgbpp/spore/local/4-transfer-spore.ts create mode 100644 examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts delete mode 100644 examples/rgbpp/spore/queue/4-transfer-spore.ts delete mode 100644 examples/rgbpp/spore/queue/5-leap-spore-to-ckb.ts diff --git a/examples/rgbpp/local/1-ckb-jump-btc.ts b/examples/rgbpp/local/1-ckb-jump-btc.ts deleted file mode 100644 index 9255c91d..00000000 --- a/examples/rgbpp/local/1-ckb-jump-btc.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { AddressPrefix, privateKeyToAddress, serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { - genCkbJumpBtcVirtualTx, - Collector, - getSecp256k1CellDep, - buildRgbppLockArgs, - getXudtTypeScript, -} from '@rgbpp-sdk/ckb'; - -// CKB SECP256K1 private key -const CKB_TEST_PRIVATE_KEY = '0x0000000000000000000000000000000000000000000000000000000000000001'; - -const jumpFromCkbToBtc = async ({ outIndex, btcTxId }: { outIndex: number; btcTxId: string }) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - const address = privateKeyToAddress(CKB_TEST_PRIVATE_KEY, { - prefix: isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, - }); - console.log('ckb address: ', address); - - const toRgbppLockArgs = buildRgbppLockArgs(outIndex, btcTxId); - - // Warning: Please replace with your real xUDT type script here - const xudtType: CKBComponents.Script = { - ...getXudtTypeScript(isMainnet), - args: '0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b', - }; - - const ckbRawTx = await genCkbJumpBtcVirtualTx({ - collector, - fromCkbAddress: address, - toRgbppLockArgs, - xudtTypeBytes: serializeScript(xudtType), - transferAmount: BigInt(800_0000_0000), - }); - - const emptyWitness = { lock: '', inputType: '', outputType: '' }; - const unsignedTx: CKBComponents.RawTransactionToSign = { - ...ckbRawTx, - cellDeps: [...ckbRawTx.cellDeps, getSecp256k1CellDep(isMainnet)], - witnesses: [emptyWitness, ...ckbRawTx.witnesses.slice(1)], - }; - - const signedTx = collector.getCkb().signTransaction(CKB_TEST_PRIVATE_KEY)(unsignedTx); - - const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); - console.info(`Rgbpp asset has been jumped from CKB to BTC and tx hash is ${txHash}`); -}; - -// Use your real BTC UTXO information on the BTC Testnet -jumpFromCkbToBtc({ - outIndex: 1, - btcTxId: '4ff1855b64b309afa19a8b9be3d4da99dcb18b083b65d2d851662995c7d99e7a', -}); diff --git a/examples/rgbpp/local/2-btc-transfer.ts b/examples/rgbpp/local/2-btc-transfer.ts deleted file mode 100644 index 05bddec6..00000000 --- a/examples/rgbpp/local/2-btc-transfer.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { - Collector, - appendCkbTxWitnesses, - buildRgbppLockArgs, - genBtcTransferCkbVirtualTx, - sendCkbTx, - getXudtTypeScript, - updateCkbTxWithRealBtcTxId, -} from '@rgbpp-sdk/ckb'; -import { transactionToHex, sendRgbppUtxos, DataSource, ECPair, bitcoin, NetworkType } from '@rgbpp-sdk/btc'; -import { BtcAssetsApi, BtcAssetsApiError } from '@rgbpp-sdk/service'; - -// BTC SECP256K1 private key -const BTC_TEST_PRIVATE_KEY = '0000000000000000000000000000000000000000000000000000000000000001'; -// API docs: https://btc-assets-api.testnet.mibao.pro/docs -const BTC_ASSETS_API_URL = 'https://btc-assets-api.testnet.mibao.pro'; -// https://btc-assets-api.testnet.mibao.pro/docs/static/index.html#/Token/post_token_generate -const BTC_ASSETS_TOKEN = ''; - -const BTC_ASSETS_ORIGIN = 'https://btc-test.app'; - -interface Params { - rgbppLockArgsList: string[]; - toBtcAddress: string; - transferAmount: bigint; -} -const transferRgbppOnBtc = async ({ rgbppLockArgsList, toBtcAddress, transferAmount }: Params) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - - const network = isMainnet ? bitcoin.networks.bitcoin : bitcoin.networks.testnet; - const keyPair = ECPair.fromPrivateKey(Buffer.from(BTC_TEST_PRIVATE_KEY, 'hex'), { network }); - const { address: btcAddress } = bitcoin.payments.p2wpkh({ - pubkey: keyPair.publicKey, - network, - }); - - console.log('btc address: ', btcAddress); - - const networkType = isMainnet ? NetworkType.MAINNET : NetworkType.TESTNET; - const service = BtcAssetsApi.fromToken(BTC_ASSETS_API_URL, BTC_ASSETS_TOKEN, BTC_ASSETS_ORIGIN); - const source = new DataSource(service, networkType); - - // Warning: Please replace with your real xUDT type script here - const xudtType: CKBComponents.Script = { - ...getXudtTypeScript(isMainnet), - args: '0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b', - }; - - const ckbVirtualTxResult = await genBtcTransferCkbVirtualTx({ - collector, - rgbppLockArgsList, - xudtTypeBytes: serializeScript(xudtType), - transferAmount, - isMainnet, - }); - - const { commitment, ckbRawTx } = ckbVirtualTxResult; - - // Send BTC tx - const psbt = await sendRgbppUtxos({ - ckbVirtualTx: ckbRawTx, - commitment, - tos: [toBtcAddress], - ckbCollector: collector, - from: btcAddress!, - source, - }); - psbt.signAllInputs(keyPair); - psbt.finalizeAllInputs(); - - const btcTx = psbt.extractTransaction(); - // Remove the witness from BTC tx for RGBPP unlock - const btcTxBytes = transactionToHex(btcTx, false); - const { txid: btcTxId } = await service.sendBtcTransaction(btcTx.toHex()); - - console.log('BTC TxId: ', btcTxId); - - // Wait for BTC tx and proof to be ready, and then send isomorphic CKB transactions - const interval = setInterval(async () => { - try { - console.log('Waiting for BTC tx and proof to be ready'); - const rgbppApiSpvProof = await service.getRgbppSpvProof(btcTxId, 0); - clearInterval(interval); - // Update CKB transaction with the real BTC txId - const newCkbRawTx = updateCkbTxWithRealBtcTxId({ ckbRawTx, btcTxId, isMainnet }); - const ckbTx = await appendCkbTxWitnesses({ - ckbRawTx: newCkbRawTx, - btcTxBytes, - rgbppApiSpvProof, - }); - - const txHash = await sendCkbTx({ collector, signedTx: ckbTx }); - console.info(`RGB++ Asset has been transferred on BTC and the CKB tx hash is ${txHash}`); - } catch (error) { - if (!(error instanceof BtcAssetsApiError)) { - console.error(error); - } - } - }, 30 * 1000); -}; - -// Use your real BTC UTXO information on the BTC Testnet -// rgbppLockArgs: outIndexU32 + btcTxId -transferRgbppOnBtc({ - rgbppLockArgsList: [buildRgbppLockArgs(1, '70b250e2a3cc7a33b47f7a4e94e41e1ee2501ce73b393d824db1dd4c872c5348')], - toBtcAddress: 'tb1qvt7p9g6mw70sealdewtfp0sekquxuru6j3gwmt', - // To simplify, keep the transferAmount the same as 2-ckb-jump-btc - transferAmount: BigInt(800_0000_0000), -}); diff --git a/examples/rgbpp/local/3-btc-jump-ckb.ts b/examples/rgbpp/local/3-btc-jump-ckb.ts deleted file mode 100644 index 818df2eb..00000000 --- a/examples/rgbpp/local/3-btc-jump-ckb.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { - Collector, - appendCkbTxWitnesses, - genBtcJumpCkbVirtualTx, - sendCkbTx, - getXudtTypeScript, - updateCkbTxWithRealBtcTxId, - buildRgbppLockArgs, -} from '@rgbpp-sdk/ckb'; -import { sendRgbppUtxos, DataSource, NetworkType, bitcoin, ECPair, transactionToHex } from '@rgbpp-sdk/btc'; -import { BtcAssetsApi, BtcAssetsApiError } from '@rgbpp-sdk/service'; - -// BTC SECP256K1 private key -const BTC_TEST_PRIVATE_KEY = '0000000000000000000000000000000000000000000000000000000000000001'; -// API docs: https://btc-assets-api.testnet.mibao.pro/docs -const BTC_ASSETS_API_URL = 'https://btc-assets-api.testnet.mibao.pro'; -// https://btc-assets-api.testnet.mibao.pro/docs/static/index.html#/Token/post_token_generate -const BTC_ASSETS_TOKEN = ''; - -const BTC_ASSETS_ORIGIN = 'https://btc-test.app'; - -interface Params { - rgbppLockArgsList: string[]; - toCkbAddress: string; - transferAmount: bigint; -} -const jumpFromBtcToCkb = async ({ rgbppLockArgsList, toCkbAddress, transferAmount }: Params) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - - const network = isMainnet ? bitcoin.networks.bitcoin : bitcoin.networks.testnet; - const keyPair = ECPair.fromPrivateKey(Buffer.from(BTC_TEST_PRIVATE_KEY, 'hex'), { network }); - const { address: btcAddress } = bitcoin.payments.p2wpkh({ - pubkey: keyPair.publicKey, - network, - }); - console.log('btc address: ', btcAddress); - - const networkType = isMainnet ? NetworkType.MAINNET : NetworkType.TESTNET; - const service = BtcAssetsApi.fromToken(BTC_ASSETS_API_URL, BTC_ASSETS_TOKEN, BTC_ASSETS_ORIGIN); - const source = new DataSource(service, networkType); - - // Warning: Please replace with your real xUDT type script here - const xudtType: CKBComponents.Script = { - ...getXudtTypeScript(isMainnet), - args: '0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b', - }; - - const ckbVirtualTxResult = await genBtcJumpCkbVirtualTx({ - collector, - rgbppLockArgsList, - xudtTypeBytes: serializeScript(xudtType), - transferAmount, - toCkbAddress, - isMainnet, - }); - - const { commitment, ckbRawTx } = ckbVirtualTxResult; - - // Send BTC tx - const psbt = await sendRgbppUtxos({ - ckbVirtualTx: ckbRawTx, - commitment, - tos: [btcAddress!], - ckbCollector: collector, - from: btcAddress!, - source, - }); - psbt.signAllInputs(keyPair); - psbt.finalizeAllInputs(); - - const btcTx = psbt.extractTransaction(); - // Remove the witness from BTC tx for RGBPP unlock - const btcTxBytes = transactionToHex(btcTx, false); - const { txid: btcTxId } = await service.sendBtcTransaction(btcTx.toHex()); - - console.log('BTC Tx bytes: ', btcTxBytes); - console.log('BTC TxId: ', btcTxId); - console.log('ckbRawTx', JSON.stringify(ckbRawTx)); - - // Wait for BTC tx and proof to be ready, and then send isomorphic CKB transactions - const interval = setInterval(async () => { - try { - console.log('Waiting for BTC tx and proof to be ready'); - const rgbppApiSpvProof = await service.getRgbppSpvProof(btcTxId, 0); - clearInterval(interval); - // Update CKB transaction with the real BTC txId - const newCkbRawTx = updateCkbTxWithRealBtcTxId({ ckbRawTx, btcTxId, isMainnet }); - const ckbTx = await appendCkbTxWitnesses({ - ckbRawTx: newCkbRawTx, - btcTxBytes, - rgbppApiSpvProof, - }); - - const txHash = await sendCkbTx({ collector, signedTx: ckbTx }); - console.info(`RGB++ Asset has been leaped from BTC to CKB and the CKB tx hash is ${txHash}`); - } catch (error) { - if (!(error instanceof BtcAssetsApiError)) { - console.error(error); - } - } - }, 30 * 1000); -}; - -// rgbppLockArgs: outIndexU32 + btcTxId -jumpFromBtcToCkb({ - // If the `3-btc-transfer.ts` has been executed, the BTC txId should be the new generated BTC txId by the `3-btc-transfer.ts` - // Otherwise the BTC txId should be same as the the BTC txId of the `2-ckb-jump-btc.ts` - rgbppLockArgsList: [buildRgbppLockArgs(1, '24e622419156dd3a277a90bcbb40c7117462a18d5329dd1ada320ca8bdfba715')], - toCkbAddress: 'ckt1qrfrwcdnvssswdwpn3s9v8fp87emat306ctjwsm3nmlkjg8qyza2cqgqq9kxr7vy7yknezj0vj0xptx6thk6pwyr0sxamv6q', - // To simplify, keep the transferAmount the same as 2-ckb-jump-btc - transferAmount: BigInt(800_0000_0000), -}); diff --git a/examples/rgbpp/local/4-spend-btc-time-cell.ts b/examples/rgbpp/local/4-spend-btc-time-cell.ts deleted file mode 100644 index 45921412..00000000 --- a/examples/rgbpp/local/4-spend-btc-time-cell.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { AddressPrefix, privateKeyToAddress } from '@nervosnetwork/ckb-sdk-utils'; -import { - Collector, - sendCkbTx, - buildBtcTimeCellsSpentTx, - getBtcTimeLockScript, - signBtcTimeCellSpentTx, -} from '@rgbpp-sdk/ckb'; -import { BtcAssetsApi } from '@rgbpp-sdk/service'; - -// CKB SECP256K1 private key -const CKB_TEST_PRIVATE_KEY = '0x0000000000000000000000000000000000000000000000000000000000000001'; -// API docs: https://btc-assets-api.testnet.mibao.pro/docs -const BTC_ASSETS_API_URL = 'https://btc-assets-api.testnet.mibao.pro'; -// https://btc-assets-api.testnet.mibao.pro/docs/static/index.html#/Token/post_token_generate -const BTC_ASSETS_TOKEN = ''; - -const BTC_ASSETS_ORIGIN = 'https://btc-test.app'; - -// Warning: Wait at least 6 BTC confirmation blocks to spend the BTC time cells after 4-btc-jump-ckb.ts -const spendBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: string }) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - const address = privateKeyToAddress(CKB_TEST_PRIVATE_KEY, { - prefix: isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, - }); - console.log('ckb address: ', address); - - const btcTimeCells = await collector.getCells({ - lock: { - ...getBtcTimeLockScript(false), - args: btcTimeCellArgs, - }, - isDataMustBeEmpty: false, - }); - - if (!btcTimeCells || btcTimeCells.length === 0) { - throw new Error('No btc time cell found'); - } - - const btcAssetsApi = BtcAssetsApi.fromToken(BTC_ASSETS_API_URL, BTC_ASSETS_TOKEN, BTC_ASSETS_ORIGIN); - - const ckbRawTx: CKBComponents.RawTransaction = await buildBtcTimeCellsSpentTx({ - btcTimeCells, - btcAssetsApi, - isMainnet, - }); - - const signedTx = await signBtcTimeCellSpentTx({ - secp256k1PrivateKey: CKB_TEST_PRIVATE_KEY, - collector, - masterCkbAddress: address, - ckbRawTx, - isMainnet, - }); - - console.log(JSON.stringify(signedTx)); - - const txHash = await sendCkbTx({ collector, signedTx }); - console.info(`BTC time cell has been spent and tx hash is ${txHash}`); -}; - -// The btcTimeCellArgs is from the outputs[0].lock.args(BTC Time lock args) of the 4-btc-jump-ckb.ts CKB transaction -spendBtcTimeCell({ - btcTimeCellArgs: - '0x7f000000100000005b0000005f0000004b000000100000003000000031000000d23761b364210735c19c60561d213fb3beae2fd6172743719eff6920e020baac011600000000016c61f984f12d3c8a4f649e60acda5deda0b8837c060000001c95b9d726e4ab337d6a4572680598947954d7b6ff4f1e767e605eeeec49e7ed', -}); diff --git a/examples/rgbpp/local/batch/1-ckb-jump-btc.ts b/examples/rgbpp/local/batch/1-ckb-jump-btc.ts deleted file mode 100644 index a6565d5b..00000000 --- a/examples/rgbpp/local/batch/1-ckb-jump-btc.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { AddressPrefix, privateKeyToAddress, serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { - Collector, - getSecp256k1CellDep, - buildRgbppLockArgs, - genCkbBatchJumpBtcVirtualTx, - RgbppLockArgsReceiver, - getXudtTypeScript, -} from '@rgbpp-sdk/ckb'; - -// CKB SECP256K1 private key -const CKB_TEST_PRIVATE_KEY = '0x0000000000000000000000000000000000000000000000000000000000000001'; - -const batchJumpFromCkbToBtc = async (rgbppReceivers: RgbppLockArgsReceiver[]) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - const address = privateKeyToAddress(CKB_TEST_PRIVATE_KEY, { - prefix: isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, - }); - console.log('ckb address: ', address); - - const xudtType: CKBComponents.Script = { - ...getXudtTypeScript(isMainnet), - args: '0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b', - }; - - const ckbRawTx = await genCkbBatchJumpBtcVirtualTx({ - collector, - fromCkbAddress: address, - xudtTypeBytes: serializeScript(xudtType), - rgbppReceivers, - }); - - const emptyWitness = { lock: '', inputType: '', outputType: '' }; - const unsignedTx: CKBComponents.RawTransactionToSign = { - ...ckbRawTx, - cellDeps: [...ckbRawTx.cellDeps, getSecp256k1CellDep(false)], - witnesses: [emptyWitness, ...ckbRawTx.witnesses.slice(1)], - }; - - const signedTx = collector.getCkb().signTransaction(CKB_TEST_PRIVATE_KEY)(unsignedTx); - - const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); - console.info(`Rgbpp asset has been jumped from CKB to BTC and tx hash is ${txHash}`); -}; - -// Use your real BTC UTXO information on the BTC Testnet -const rgbppReceivers: RgbppLockArgsReceiver[] = [ - { - // outIndex and btcTxId - toRgbppLockArgs: buildRgbppLockArgs(1, 'bf991a2d6d08efffa089076d59b02bc78479b73c6300e640c148ec660bba0305'), - transferAmount: BigInt(800_0000_0000), - }, - { - // outIndex and btcTxId - toRgbppLockArgs: buildRgbppLockArgs(1, 'bf991a2d6d08efffa089076d59b02bc78479b73c6300e640c148ec660bba0305'), - transferAmount: BigInt(800_0000_0000), - }, -]; -batchJumpFromCkbToBtc(rgbppReceivers); diff --git a/examples/rgbpp/local/launch/0-rgbpp-token-info.ts b/examples/rgbpp/local/launch/0-rgbpp-token-info.ts deleted file mode 100644 index 67a7cc39..00000000 --- a/examples/rgbpp/local/launch/0-rgbpp-token-info.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { RgbppTokenInfo } from '@rgbpp-sdk/ckb'; - -export const RGBPP_TOKEN_INFO: RgbppTokenInfo = { - decimal: 8, - name: 'RGBPP Test Token', - symbol: 'RTT', -}; diff --git a/examples/rgbpp/local/launch/1-prepare-launch.ts b/examples/rgbpp/local/launch/1-prepare-launch.ts deleted file mode 100644 index 7867a194..00000000 --- a/examples/rgbpp/local/launch/1-prepare-launch.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { AddressPrefix, addressToScript, getTransactionSize, privateKeyToAddress } from '@nervosnetwork/ckb-sdk-utils'; -import { - Collector, - MAX_FEE, - NoLiveCellError, - RgbppTokenInfo, - SECP256K1_WITNESS_LOCK_SIZE, - append0x, - buildRgbppLockArgs, - calculateRgbppCellCapacity, - calculateRgbppTokenInfoCellCapacity, - calculateTransactionFee, - genRgbppLockScript, - getSecp256k1CellDep, -} from '@rgbpp-sdk/ckb'; -import { RGBPP_TOKEN_INFO } from './0-rgbpp-token-info'; - -// CKB SECP256K1 private key -const CKB_TEST_PRIVATE_KEY = '0x0000000000000000000000000000000000000000000000000000000000000001'; - -const prepareLaunchCell = async ({ - outIndex, - btcTxId, - rgbppTokenInfo, -}: { - outIndex: number; - btcTxId: string; - rgbppTokenInfo: RgbppTokenInfo; -}) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - const address = privateKeyToAddress(CKB_TEST_PRIVATE_KEY, { - prefix: isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, - }); - const masterLock = addressToScript(address); - console.log('ckb address: ', address); - - // The capacity required to launch cells is determined by the token info cell capacity, and transaction fee. - const launchCellCapacity = - calculateRgbppCellCapacity() + calculateRgbppTokenInfoCellCapacity(rgbppTokenInfo, isMainnet); - - let emptyCells = await collector.getCells({ - lock: masterLock, - }); - if (!emptyCells || emptyCells.length === 0) { - throw new NoLiveCellError('The address has no empty cells'); - } - emptyCells = emptyCells.filter((cell) => !cell.output.type); - - const txFee = MAX_FEE; - const { inputs, sumInputsCapacity } = collector.collectInputs(emptyCells, launchCellCapacity, txFee); - - const outputs: CKBComponents.CellOutput[] = [ - { - lock: genRgbppLockScript(buildRgbppLockArgs(outIndex, btcTxId), isMainnet), - capacity: append0x(launchCellCapacity.toString(16)), - }, - ]; - let changeCapacity = sumInputsCapacity - launchCellCapacity; - outputs.push({ - lock: masterLock, - capacity: append0x(changeCapacity.toString(16)), - }); - const outputsData = ['0x', '0x']; - - const emptyWitness = { lock: '', inputType: '', outputType: '' }; - const witnesses = inputs.map((_, index) => (index === 0 ? emptyWitness : '0x')); - - const cellDeps = [getSecp256k1CellDep(isMainnet)]; - - const unsignedTx = { - version: '0x0', - cellDeps, - headerDeps: [], - inputs, - outputs, - outputsData, - witnesses, - }; - - const txSize = getTransactionSize(unsignedTx) + SECP256K1_WITNESS_LOCK_SIZE; - const estimatedTxFee = calculateTransactionFee(txSize); - changeCapacity -= estimatedTxFee; - unsignedTx.outputs[unsignedTx.outputs.length - 1].capacity = append0x(changeCapacity.toString(16)); - - const signedTx = collector.getCkb().signTransaction(CKB_TEST_PRIVATE_KEY)(unsignedTx); - const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); - - console.info(`Launch cell has been created and the tx hash ${txHash}`); -}; - -prepareLaunchCell({ - outIndex: 1, - btcTxId: '6259ea7852e294afbd2aaf9ccd5c9c1f95087b0b08ba7e47ae35ce31170732bc', - rgbppTokenInfo: RGBPP_TOKEN_INFO, -}); diff --git a/examples/rgbpp/local/launch/2-launch-rgbpp.ts b/examples/rgbpp/local/launch/2-launch-rgbpp.ts deleted file mode 100644 index be5db676..00000000 --- a/examples/rgbpp/local/launch/2-launch-rgbpp.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { - Collector, - buildRgbppLockArgs, - genRgbppLaunchCkbVirtualTx, - RgbppTokenInfo, - appendCkbTxWitnesses, - updateCkbTxWithRealBtcTxId, - sendCkbTx, -} from '@rgbpp-sdk/ckb'; -import { DataSource, ECPair, bitcoin, NetworkType, sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; -import { BtcAssetsApi, BtcAssetsApiError } from '@rgbpp-sdk/service'; -import { RGBPP_TOKEN_INFO } from './0-rgbpp-token-info'; - -// BTC SECP256K1 private key -const BTC_TEST_PRIVATE_KEY = '0000000000000000000000000000000000000000000000000000000000000001'; -// API docs: https://btc-assets-api.testnet.mibao.pro/docs -const BTC_ASSETS_API_URL = 'https://btc-assets-api.testnet.mibao.pro'; -// https://btc-assets-api.testnet.mibao.pro/docs/static/index.html#/Token/post_token_generate -const BTC_ASSETS_TOKEN = ''; - -const BTC_ASSETS_ORIGIN = 'https://btc-test.app'; - -interface Params { - ownerRgbppLockArgs: string; - launchAmount: bigint; - rgbppTokenInfo: RgbppTokenInfo; -} -const launchRgppAsset = async ({ ownerRgbppLockArgs, launchAmount, rgbppTokenInfo }: Params) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - - const network = isMainnet ? bitcoin.networks.bitcoin : bitcoin.networks.testnet; - const keyPair = ECPair.fromPrivateKey(Buffer.from(BTC_TEST_PRIVATE_KEY, 'hex'), { network }); - const { address: btcAddress } = bitcoin.payments.p2wpkh({ - pubkey: keyPair.publicKey, - network, - }); - - console.log('btc address: ', btcAddress); - - const networkType = isMainnet ? NetworkType.MAINNET : NetworkType.TESTNET; - const service = BtcAssetsApi.fromToken(BTC_ASSETS_API_URL, BTC_ASSETS_TOKEN, BTC_ASSETS_ORIGIN); - const source = new DataSource(service, networkType); - - const ckbVirtualTxResult = await genRgbppLaunchCkbVirtualTx({ - collector, - ownerRgbppLockArgs, - rgbppTokenInfo, - launchAmount, - isMainnet, - }); - - const { commitment, ckbRawTx } = ckbVirtualTxResult; - - console.log('RGB++ Asset type script args: ', ckbRawTx.outputs[0].type?.args); - - // Send BTC tx - const psbt = await sendRgbppUtxos({ - ckbVirtualTx: ckbRawTx, - commitment, - tos: [btcAddress!], - ckbCollector: collector, - from: btcAddress!, - source, - }); - psbt.signAllInputs(keyPair); - psbt.finalizeAllInputs(); - - const btcTx = psbt.extractTransaction(); - const btcTxBytes = transactionToHex(btcTx, false); - const { txid: btcTxId } = await service.sendBtcTransaction(btcTx.toHex()); - - console.log('BTC TxId: ', btcTxId); - - const interval = setInterval(async () => { - try { - console.log('Waiting for BTC tx and proof to be ready'); - const rgbppApiSpvProof = await service.getRgbppSpvProof(btcTxId, 0); - clearInterval(interval); - // Update CKB transaction with the real BTC txId - const newCkbRawTx = updateCkbTxWithRealBtcTxId({ ckbRawTx, btcTxId, isMainnet }); - const ckbTx = await appendCkbTxWitnesses({ - ckbRawTx: newCkbRawTx, - btcTxBytes, - rgbppApiSpvProof, - }); - - const txHash = await sendCkbTx({ collector, signedTx: ckbTx }); - console.info(`RGB++ Asset has been launched and tx hash is ${txHash}`); - } catch (error) { - if (!(error instanceof BtcAssetsApiError)) { - console.error(error); - } - } - }, 30 * 1000); -}; - -// Use your real BTC UTXO information on the BTC Testnet -// rgbppLockArgs: outIndexU32 + btcTxId -launchRgppAsset({ - ownerRgbppLockArgs: buildRgbppLockArgs(1, '6259ea7852e294afbd2aaf9ccd5c9c1f95087b0b08ba7e47ae35ce31170732bc'), - rgbppTokenInfo: RGBPP_TOKEN_INFO, - // The total issuance amount of RGBPP Token, the decimal is determined by RGBPP Token info - launchAmount: BigInt(2100_0000) * BigInt(10 ** RGBPP_TOKEN_INFO.decimal), -}); diff --git a/examples/rgbpp/local/launch/3-distribute-rgbpp.ts b/examples/rgbpp/local/launch/3-distribute-rgbpp.ts deleted file mode 100644 index b1cb880e..00000000 --- a/examples/rgbpp/local/launch/3-distribute-rgbpp.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { AddressPrefix, privateKeyToAddress, serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { - Collector, - RgbppBtcAddressReceiver, - appendCkbTxWitnesses, - appendIssuerCellToBtcBatchTransfer, - buildRgbppLockArgs, - genBtcBatchTransferCkbVirtualTx, - getXudtTypeScript, - sendCkbTx, - updateCkbTxWithRealBtcTxId, -} from '@rgbpp-sdk/ckb'; -import { sendRgbppUtxos, DataSource, ECPair, bitcoin, NetworkType, transactionToHex } from '@rgbpp-sdk/btc'; -import { BtcAssetsApi, BtcAssetsApiError } from '@rgbpp-sdk/service'; -import { RGBPP_TOKEN_INFO } from './0-rgbpp-token-info'; - -// CKB SECP256K1 private key -const CKB_TEST_PRIVATE_KEY = '0x0000000000000000000000000000000000000000000000000000000000000001'; -// BTC SECP256K1 private key -const BTC_TEST_PRIVATE_KEY = '0000000000000000000000000000000000000000000000000000000000000001'; -// API docs: https://btc-assets-api.testnet.mibao.pro/docs -const BTC_ASSETS_API_URL = 'https://btc-assets-api.testnet.mibao.pro'; -// https://btc-assets-api.testnet.mibao.pro/docs/static/index.html#/Token/post_token_generate -const BTC_ASSETS_TOKEN = ''; - -const BTC_ASSETS_ORIGIN = 'https://btc-test.app'; - -interface Params { - rgbppLockArgsList: string[]; - receivers: RgbppBtcAddressReceiver[]; -} -const distributeRgbppAssetOnBtc = async ({ rgbppLockArgsList, receivers }: Params) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - const ckbAddress = privateKeyToAddress(CKB_TEST_PRIVATE_KEY, { - prefix: isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, - }); - console.log('ckb address: ', ckbAddress); - - const network = isMainnet ? bitcoin.networks.bitcoin : bitcoin.networks.testnet; - const keyPair = ECPair.fromPrivateKey(Buffer.from(BTC_TEST_PRIVATE_KEY, 'hex'), { network }); - const { address: btcAddress } = bitcoin.payments.p2wpkh({ - pubkey: keyPair.publicKey, - network, - }); - - console.log('btc address: ', btcAddress); - - const networkType = isMainnet ? NetworkType.MAINNET : NetworkType.TESTNET; - const service = BtcAssetsApi.fromToken(BTC_ASSETS_API_URL, BTC_ASSETS_TOKEN, BTC_ASSETS_ORIGIN); - const source = new DataSource(service, networkType); - - // Warning: Please replace with your real xUDT type script here - const xudtType: CKBComponents.Script = { - ...getXudtTypeScript(isMainnet), - // The xUDT type script args is generated by 2-launch-rgbpp.ts, and it can be found from the log - args: '0x4c1ecf2f14edae73b76ccf115ecfa40ba68ee315c96bd4fcfd771c2fb4c69e8f', - }; - - const ckbVirtualTxResult = await genBtcBatchTransferCkbVirtualTx({ - collector, - rgbppLockArgsList, - xudtTypeBytes: serializeScript(xudtType), - rgbppReceivers: receivers, - isMainnet, - }); - - const { commitment, ckbRawTx, sumInputsCapacity, rgbppChangeOutIndex } = ckbVirtualTxResult; - - // The first output utxo is OP_RETURN - // Rgbpp change utxo position depends on the number of distributions, if 50 addresses are distributed, then the change utxo position is 51 - console.log('RGB++ asset change utxo out index: ', rgbppChangeOutIndex); - - // Send BTC tx - const psbt = await sendRgbppUtxos({ - ckbVirtualTx: ckbRawTx, - commitment, - tos: receivers.map((receiver) => receiver.toBtcAddress), - ckbCollector: collector, - from: btcAddress!, - source, - }); - psbt.signAllInputs(keyPair); - psbt.finalizeAllInputs(); - - const btcTx = psbt.extractTransaction(); - const btcTxBytes = transactionToHex(btcTx, false); - const { txid: btcTxId } = await service.sendBtcTransaction(btcTx.toHex()); - - console.log('BTC TxId: ', btcTxId); - - const interval = setInterval(async () => { - try { - console.log('Waiting for BTC tx and proof to be ready'); - const rgbppApiSpvProof = await service.getRgbppSpvProof(btcTxId, 0); - clearInterval(interval); - // Update CKB transaction with the real BTC txId - const newCkbRawTx = updateCkbTxWithRealBtcTxId({ ckbRawTx, btcTxId, isMainnet }); - const ckbTx = await appendCkbTxWitnesses({ - ckbRawTx: newCkbRawTx, - btcTxBytes, - rgbppApiSpvProof, - }); - - const signedTx = await appendIssuerCellToBtcBatchTransfer({ - secp256k1PrivateKey: CKB_TEST_PRIVATE_KEY, - issuerAddress: ckbAddress, - ckbRawTx: ckbTx, - collector, - sumInputsCapacity, - isMainnet, - }); - - const txHash = await sendCkbTx({ collector, signedTx }); - console.info(`RGB++ Asset has been distributed and tx hash is ${txHash}`); - } catch (error) { - if (!(error instanceof BtcAssetsApiError)) { - console.error(error); - } - } - }, 20 * 1000); -}; - -// Use your real BTC UTXO information on the BTC Testnet -// rgbppLockArgs: outIndexU32 + btcTxId -distributeRgbppAssetOnBtc({ - // Warning: If rgbpp assets are distributed continuously, then the position of the current rgbpp asset utxo depends on the position of the previous change utxo distributed - rgbppLockArgsList: [buildRgbppLockArgs(2, '012bfee9c1e8a6e9e272b63ff54d5138efe910cc7aac413221cb3634ea176866')], - receivers: [ - { - toBtcAddress: 'bc1p0ey32x7dwhlx569rh0l5qaxetsfnpvezanrezahelr0t02ytyegssdel0h', - transferAmount: BigInt(1000) * BigInt(10 ** RGBPP_TOKEN_INFO.decimal), - }, - ], -}); diff --git a/examples/rgbpp/local/transfer-btc.ts b/examples/rgbpp/local/transfer-btc.ts deleted file mode 100644 index be40aa1a..00000000 --- a/examples/rgbpp/local/transfer-btc.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { sendBtc, DataSource, NetworkType, bitcoin, ECPair } from '@rgbpp-sdk/btc'; -import { BtcAssetsApi } from '@rgbpp-sdk/service'; - -// BTC SECP256K1 private key -const BTC_TEST_PRIVATE_KEY = '0000000000000000000000000000000000000000000000000000000000000001'; -// https://btc-assets-api-develop.vercel.app/docs/static/index.html -const BTC_ASSETS_API_URL = 'https://btc-assets-api.testnet.mibao.pro'; -// https://btc-assets-api.testnet.mibao.pro/docs/static/index.html#/Token/post_token_generate -const BTC_ASSETS_TOKEN = ''; - -// This example shows how to transfer BTC on testnet -const transferBtc = async () => { - const network = bitcoin.networks.testnet; - const keyPair = ECPair.fromPrivateKey(Buffer.from(BTC_TEST_PRIVATE_KEY, 'hex'), { network }); - const { address: btcAddress } = bitcoin.payments.p2wpkh({ - pubkey: keyPair.publicKey, - network, - }); - console.log('btc address: ', btcAddress); - - const networkType = NetworkType.TESTNET; - const service = BtcAssetsApi.fromToken(BTC_ASSETS_API_URL, BTC_ASSETS_TOKEN, 'https://btc-test.app'); - const source = new DataSource(service, networkType); - - const psbt = await sendBtc({ - from: btcAddress!, // your P2WPKH address - tos: [ - { - address: btcAddress!, // destination btc address - value: 100000, // transfer satoshi amount - }, - ], - feeRate: 1, // optional, default to 1 sat/vbyte - source, - }); - - // Sign & finalize inputs - psbt.signAllInputs(keyPair); - psbt.finalizeAllInputs(); - - // Broadcast transaction - const tx = psbt.extractTransaction(); - const { txid: txId } = await service.sendBtcTransaction(tx.toHex()); - console.log('txId:', txId); -}; - -transferBtc(); diff --git a/examples/rgbpp/package.json b/examples/rgbpp/package.json index 7ab70fc4..e5f88eb3 100644 --- a/examples/rgbpp/package.json +++ b/examples/rgbpp/package.json @@ -1,7 +1,7 @@ { "name": "rgbpp-examples", "version": "0.1.0", - "description": "Examples used for RGBPP assets issuance, transfer, and jumping between BTC and CKB", + "description": "Examples used for RGBPP assets issuance, transfer, and leaping between BTC and CKB", "private": true, "type": "module", "scripts": { @@ -16,7 +16,7 @@ "@rgbpp-sdk/ckb": "workspace:^", "@rgbpp-sdk/service": "workspace:^", "@spore-sdk/core": "^0.2.0-beta.6", - "axios": "^1.6.8" + "examples-core": "workspace:^" }, "devDependencies": { "@types/node": "^20.11.28", diff --git a/examples/rgbpp/queue/1-ckb-jump-btc.ts b/examples/rgbpp/queue/1-ckb-jump-btc.ts deleted file mode 100644 index ef408c20..00000000 --- a/examples/rgbpp/queue/1-ckb-jump-btc.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { AddressPrefix, privateKeyToAddress, serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { - genCkbJumpBtcVirtualTx, - Collector, - getSecp256k1CellDep, - buildRgbppLockArgs, - getXudtTypeScript, -} from '@rgbpp-sdk/ckb'; - -// CKB SECP256K1 private key -const CKB_TEST_PRIVATE_KEY = '0x0000000000000000000000000000000000000000000000000000000000000001'; - -const jumpFromCkbToBtc = async ({ outIndex, btcTxId }: { outIndex: number; btcTxId: string }) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - const address = privateKeyToAddress(CKB_TEST_PRIVATE_KEY, { - prefix: isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, - }); - console.log('ckb address: ', address); - - const toRgbppLockArgs = buildRgbppLockArgs(outIndex, btcTxId); - - // Warning: Please replace with your real xUDT type script here - const xudtType: CKBComponents.Script = { - ...getXudtTypeScript(isMainnet), - args: '0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b', - }; - - const ckbRawTx = await genCkbJumpBtcVirtualTx({ - collector, - fromCkbAddress: address, - toRgbppLockArgs, - xudtTypeBytes: serializeScript(xudtType), - transferAmount: BigInt(800_0000_0000), - }); - - const emptyWitness = { lock: '', inputType: '', outputType: '' }; - const unsignedTx: CKBComponents.RawTransactionToSign = { - ...ckbRawTx, - cellDeps: [...ckbRawTx.cellDeps, getSecp256k1CellDep(false)], - witnesses: [emptyWitness, ...ckbRawTx.witnesses.slice(1)], - }; - - const signedTx = collector.getCkb().signTransaction(CKB_TEST_PRIVATE_KEY)(unsignedTx); - - const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); - console.info(`Rgbpp asset has been jumped from CKB to BTC and tx hash is ${txHash}`); -}; - -// Use your real BTC UTXO information on the BTC Testnet -jumpFromCkbToBtc({ - outIndex: 1, - btcTxId: '4ff1855b64b309afa19a8b9be3d4da99dcb18b083b65d2d851662995c7d99e7a', -}); diff --git a/examples/rgbpp/queue/2-btc-transfer.ts b/examples/rgbpp/queue/2-btc-transfer.ts deleted file mode 100644 index 86de53e1..00000000 --- a/examples/rgbpp/queue/2-btc-transfer.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { Collector, buildRgbppLockArgs, genBtcTransferCkbVirtualTx, getXudtTypeScript } from '@rgbpp-sdk/ckb'; -import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { sendRgbppUtxos, DataSource, ECPair, bitcoin, NetworkType } from '@rgbpp-sdk/btc'; -import { BtcAssetsApi } from '@rgbpp-sdk/service'; - -// BTC SECP256K1 private key -const BTC_TEST_PRIVATE_KEY = '0000000000000000000000000000000000000000000000000000000000000001'; -// API docs: https://btc-assets-api.testnet.mibao.pro/docs -const BTC_ASSETS_API_URL = 'https://btc-assets-api.testnet.mibao.pro'; -// https://btc-assets-api.testnet.mibao.pro/docs/static/index.html#/Token/post_token_generate -const BTC_ASSETS_TOKEN = ''; - -const BTC_ASSETS_ORIGIN = 'https://btc-test.app'; - -interface Params { - rgbppLockArgsList: string[]; - toBtcAddress: string; - transferAmount: bigint; -} -const transferRgbppOnBtc = async ({ rgbppLockArgsList, toBtcAddress, transferAmount }: Params) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - - const network = isMainnet ? bitcoin.networks.bitcoin : bitcoin.networks.testnet; - const keyPair = ECPair.fromPrivateKey(Buffer.from(BTC_TEST_PRIVATE_KEY, 'hex'), { network }); - const { address: btcAddress } = bitcoin.payments.p2wpkh({ - pubkey: keyPair.publicKey, - network, - }); - - console.log('btc address: ', btcAddress); - - const networkType = isMainnet ? NetworkType.MAINNET : NetworkType.TESTNET; - const service = BtcAssetsApi.fromToken(BTC_ASSETS_API_URL, BTC_ASSETS_TOKEN, BTC_ASSETS_ORIGIN); - const source = new DataSource(service, networkType); - - // Warning: Please replace with your real xUDT type script here - const xudtType: CKBComponents.Script = { - ...getXudtTypeScript(isMainnet), - args: '0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b', - }; - - const ckbVirtualTxResult = await genBtcTransferCkbVirtualTx({ - collector, - rgbppLockArgsList, - xudtTypeBytes: serializeScript(xudtType), - transferAmount, - isMainnet, - }); - - const { commitment, ckbRawTx } = ckbVirtualTxResult; - - // Send BTC tx - const psbt = await sendRgbppUtxos({ - ckbVirtualTx: ckbRawTx, - commitment, - tos: [toBtcAddress], - ckbCollector: collector, - from: btcAddress!, - source, - }); - psbt.signAllInputs(keyPair); - psbt.finalizeAllInputs(); - - const btcTx = psbt.extractTransaction(); - const { txid: btcTxId } = await service.sendBtcTransaction(btcTx.toHex()); - - console.log('BTC TxId: ', btcTxId); - - try { - await service.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); - const interval = setInterval(async () => { - const { state, failedReason } = await service.getRgbppTransactionState(btcTxId); - console.log('state', state); - if (state === 'completed' || state === 'failed') { - clearInterval(interval); - if (state === 'completed') { - const { txhash: txHash } = await service.getRgbppTransactionHash(btcTxId); - console.info(`Rgbpp asset has been transferred on BTC and the related CKB tx hash is ${txHash}`); - } else { - console.warn(`Rgbpp CKB transaction failed and the reason is ${failedReason} `); - } - } - }, 30 * 1000); - } catch (error) { - console.error(error); - } -}; - -// Use your real BTC UTXO information on the BTC Testnet -// rgbppLockArgs: outIndexU32 + btcTxId -transferRgbppOnBtc({ - rgbppLockArgsList: [buildRgbppLockArgs(1, '64252b582aea1249ed969a20385fae48bba35bf1ab9b3df3b0fcddc754ccf592')], - toBtcAddress: 'tb1qvt7p9g6mw70sealdewtfp0sekquxuru6j3gwmt', - // To simplify, keep the transferAmount the same as 2-ckb-jump-btc - transferAmount: BigInt(800_0000_0000), -}); diff --git a/examples/rgbpp/queue/3-btc-jump-ckb.ts b/examples/rgbpp/queue/3-btc-jump-ckb.ts deleted file mode 100644 index 3e400c0f..00000000 --- a/examples/rgbpp/queue/3-btc-jump-ckb.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { sendRgbppUtxos, DataSource, NetworkType, bitcoin, ECPair } from '@rgbpp-sdk/btc'; -import { Collector, genBtcJumpCkbVirtualTx, buildRgbppLockArgs, getXudtTypeScript } from '@rgbpp-sdk/ckb'; -import { BtcAssetsApi } from '@rgbpp-sdk/service'; - -// BTC SECP256K1 private key -const BTC_TEST_PRIVATE_KEY = '0000000000000000000000000000000000000000000000000000000000000001'; -// API docs: https://btc-assets-api.testnet.mibao.pro/docs -const BTC_ASSETS_API_URL = 'https://btc-assets-api.testnet.mibao.pro'; -// https://btc-assets-api.testnet.mibao.pro/docs/static/index.html#/Token/post_token_generate -const BTC_ASSETS_TOKEN = ''; - -const BTC_ASSETS_ORIGIN = 'https://btc-test.app'; - -interface Params { - rgbppLockArgsList: string[]; - toCkbAddress: string; - transferAmount: bigint; -} -const jumpFromBtcToCkb = async ({ rgbppLockArgsList, toCkbAddress, transferAmount }: Params) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - - const network = isMainnet ? bitcoin.networks.bitcoin : bitcoin.networks.testnet; - const keyPair = ECPair.fromPrivateKey(Buffer.from(BTC_TEST_PRIVATE_KEY, 'hex'), { network }); - const { address: btcAddress } = bitcoin.payments.p2wpkh({ - pubkey: keyPair.publicKey, - network, - }); - console.log('btc address: ', btcAddress); - - const networkType = isMainnet ? NetworkType.MAINNET : NetworkType.TESTNET; - const service = BtcAssetsApi.fromToken(BTC_ASSETS_API_URL, BTC_ASSETS_TOKEN, BTC_ASSETS_ORIGIN); - const source = new DataSource(service, networkType); - - // Warning: Please replace with your real xUDT type script here - const xudtType: CKBComponents.Script = { - ...getXudtTypeScript(isMainnet), - args: '0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b', - }; - - const ckbVirtualTxResult = await genBtcJumpCkbVirtualTx({ - collector, - rgbppLockArgsList, - xudtTypeBytes: serializeScript(xudtType), - transferAmount, - toCkbAddress, - isMainnet, - }); - - const { commitment, ckbRawTx } = ckbVirtualTxResult; - - // Send BTC tx - const psbt = await sendRgbppUtxos({ - ckbVirtualTx: ckbRawTx, - commitment, - tos: [btcAddress!], - ckbCollector: collector, - from: btcAddress!, - source, - }); - psbt.signAllInputs(keyPair); - psbt.finalizeAllInputs(); - - const btcTx = psbt.extractTransaction(); - const { txid: btcTxId } = await service.sendBtcTransaction(btcTx.toHex()); - - console.log('BTC TxId: ', btcTxId); - - try { - await service.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); - const interval = setInterval(async () => { - const { state, failedReason } = await service.getRgbppTransactionState(btcTxId); - console.log('state', state); - if (state === 'completed' || state === 'failed') { - clearInterval(interval); - if (state === 'completed') { - const { txhash: txHash } = await service.getRgbppTransactionHash(btcTxId); - console.info(`Rgbpp asset has been jumped from BTC to CKB and the related CKB tx hash is ${txHash}`); - } else { - console.warn(`Rgbpp CKB transaction failed and the reason is ${failedReason} `); - } - } - }, 30 * 1000); - } catch (error) { - console.error(error); - } -}; - -// rgbppLockArgs: outIndexU32 + btcTxId -jumpFromBtcToCkb({ - // If the `3-btc-transfer.ts` has been executed, the BTC txId should be the new generated BTC txId by the `3-btc-transfer.ts` - // Otherwise the BTC txId should be same as the the BTC txId of the `2-ckb-jump-btc.ts` - rgbppLockArgsList: [buildRgbppLockArgs(1, '6edd4b9327506fab09fb9a0f5e5f35136a6a94bd4c9dd79af04921618fa6c800')], - toCkbAddress: 'ckt1qrfrwcdnvssswdwpn3s9v8fp87emat306ctjwsm3nmlkjg8qyza2cqgqq9kxr7vy7yknezj0vj0xptx6thk6pwyr0sxamv6q', - // To simplify, keep the transferAmount the same as 2-ckb-jump-btc - transferAmount: BigInt(800_0000_0000), -}); diff --git a/examples/rgbpp/queue/no-merge-outputs/2-btc-transfer.ts b/examples/rgbpp/queue/no-merge-outputs/2-btc-transfer.ts deleted file mode 100644 index a07c48d6..00000000 --- a/examples/rgbpp/queue/no-merge-outputs/2-btc-transfer.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { Collector, buildRgbppLockArgs, genBtcTransferCkbVirtualTx, getXudtTypeScript } from '@rgbpp-sdk/ckb'; -import { sendRgbppUtxos, DataSource, ECPair, bitcoin, NetworkType } from '@rgbpp-sdk/btc'; -import { BtcAssetsApi } from '@rgbpp-sdk/service'; - -// BTC SECP256K1 private key -const BTC_TEST_PRIVATE_KEY = '0000000000000000000000000000000000000000000000000000000000000001'; -// API docs: https://btc-assets-api.testnet.mibao.pro/docs -const BTC_ASSETS_API_URL = 'https://btc-assets-api.testnet.mibao.pro'; -// https://btc-assets-api.testnet.mibao.pro/docs/static/index.html#/Token/post_token_generate -const BTC_ASSETS_TOKEN = ''; - -const BTC_ASSETS_ORIGIN = 'https://btc-test.app'; - -interface Params { - rgbppLockArgsList: string[]; - toBtcAddress: string; - transferAmount: bigint; -} -const transferRgbppOnBtc = async ({ rgbppLockArgsList, toBtcAddress, transferAmount }: Params) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - - const network = isMainnet ? bitcoin.networks.bitcoin : bitcoin.networks.testnet; - const keyPair = ECPair.fromPrivateKey(Buffer.from(BTC_TEST_PRIVATE_KEY, 'hex'), { network }); - const { address: btcAddress } = bitcoin.payments.p2wpkh({ - pubkey: keyPair.publicKey, - network, - }); - - console.log('btc address: ', btcAddress); - - const networkType = isMainnet ? NetworkType.MAINNET : NetworkType.TESTNET; - const service = BtcAssetsApi.fromToken(BTC_ASSETS_API_URL, BTC_ASSETS_TOKEN, BTC_ASSETS_ORIGIN); - const source = new DataSource(service, networkType); - - const xudtType: CKBComponents.Script = { - ...getXudtTypeScript(isMainnet), - args: '0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b', - }; - - const ckbVirtualTxResult = await genBtcTransferCkbVirtualTx({ - collector, - rgbppLockArgsList, - xudtTypeBytes: serializeScript(xudtType), - transferAmount, - isMainnet, - noMergeOutputCells: true, - }); - - const { commitment, ckbRawTx } = ckbVirtualTxResult; - - // Send BTC tx - const psbt = await sendRgbppUtxos({ - ckbVirtualTx: ckbRawTx, - commitment, - tos: [toBtcAddress], - ckbCollector: collector, - from: btcAddress!, - source, - }); - psbt.signAllInputs(keyPair); - psbt.finalizeAllInputs(); - - const btcTx = psbt.extractTransaction(); - const { txid: btcTxId } = await service.sendBtcTransaction(btcTx.toHex()); - - console.log('BTC TxId: ', btcTxId); - - try { - await service.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); - const interval = setInterval(async () => { - const { state, failedReason } = await service.getRgbppTransactionState(btcTxId); - console.log('state', state); - if (state === 'completed' || state === 'failed') { - clearInterval(interval); - if (state === 'completed') { - const { txhash: txHash } = await service.getRgbppTransactionHash(btcTxId); - console.info(`Rgbpp asset has been transferred on BTC and the related CKB tx hash is ${txHash}`); - } else { - console.warn(`Rgbpp CKB transaction failed and the reason is ${failedReason} `); - } - } - }, 30 * 1000); - } catch (error) { - console.error(error); - } -}; - -// Use your real BTC UTXO information on the BTC Testnet -// rgbppLockArgs: outIndexU32 + btcTxId -transferRgbppOnBtc({ - rgbppLockArgsList: [ - buildRgbppLockArgs(0, '4ff1855b64b309afa19a8b9be3d4da99dcb18b083b65d2d851662995c7d99e7a'), - buildRgbppLockArgs(1, '4ff1855b64b309afa19a8b9be3d4da99dcb18b083b65d2d851662995c7d99e7a'), - ], - toBtcAddress: 'tb1qvt7p9g6mw70sealdewtfp0sekquxuru6j3gwmt', - // the transferAmount will be ignored - transferAmount: BigInt(0), -}); diff --git a/examples/rgbpp/spore/1-prepare-cluster.ts b/examples/rgbpp/spore/1-prepare-cluster.ts index 2319f273..ef80fc3c 100644 --- a/examples/rgbpp/spore/1-prepare-cluster.ts +++ b/examples/rgbpp/spore/1-prepare-cluster.ts @@ -1,6 +1,5 @@ -import { AddressPrefix, addressToScript, getTransactionSize, privateKeyToAddress } from '@nervosnetwork/ckb-sdk-utils'; +import { addressToScript, getTransactionSize } from '@nervosnetwork/ckb-sdk-utils'; import { - Collector, MAX_FEE, NoLiveCellError, SECP256K1_WITNESS_LOCK_SIZE, @@ -11,22 +10,12 @@ import { genRgbppLockScript, getSecp256k1CellDep, } from '@rgbpp-sdk/ckb'; +import { ckbAddress, isMainnet, collector, CKB_PRIVATE_KEY } from 'examples-core'; import { CLUSTER_DATA } from './0-cluster-info'; -// CKB SECP256K1 private key -const CKB_TEST_PRIVATE_KEY = '0x0000000000000000000000000000000000000000000000000000000000000001'; - const prepareClusterCell = async ({ outIndex, btcTxId }: { outIndex: number; btcTxId: string }) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - const address = privateKeyToAddress(CKB_TEST_PRIVATE_KEY, { - prefix: isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, - }); - const masterLock = addressToScript(address); - console.log('ckb address: ', address); + const masterLock = addressToScript(ckbAddress); + console.log('ckb address: ', ckbAddress); // The capacity required to launch cells is determined by the token info cell capacity, and transaction fee. const clusterCellCapacity = calculateRgbppClusterCellCapacity(CLUSTER_DATA); @@ -75,7 +64,7 @@ const prepareClusterCell = async ({ outIndex, btcTxId }: { outIndex: number; btc changeCapacity -= estimatedTxFee; unsignedTx.outputs[unsignedTx.outputs.length - 1].capacity = append0x(changeCapacity.toString(16)); - const signedTx = collector.getCkb().signTransaction(CKB_TEST_PRIVATE_KEY)(unsignedTx); + const signedTx = collector.getCkb().signTransaction(CKB_PRIVATE_KEY)(unsignedTx); const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); console.info(`Cluster cell has been prepared and the tx hash ${txHash}`); diff --git a/examples/rgbpp/spore/2-create-cluster.ts b/examples/rgbpp/spore/2-create-cluster.ts index a1269e27..e824bf33 100644 --- a/examples/rgbpp/spore/2-create-cluster.ts +++ b/examples/rgbpp/spore/2-create-cluster.ts @@ -1,5 +1,4 @@ import { - Collector, buildRgbppLockArgs, appendCkbTxWitnesses, updateCkbTxWithRealBtcTxId, @@ -7,39 +6,12 @@ import { genCreateClusterCkbVirtualTx, generateClusterCreateCoBuild, } from '@rgbpp-sdk/ckb'; -import { DataSource, ECPair, bitcoin, NetworkType, sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; -import { BtcAssetsApi, BtcAssetsApiError } from '@rgbpp-sdk/service'; +import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; +import { BtcAssetsApiError } from '@rgbpp-sdk/service'; +import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from 'examples-core'; import { CLUSTER_DATA } from './0-cluster-info'; -// BTC SECP256K1 private key -const BTC_TEST_PRIVATE_KEY = '0000000000000000000000000000000000000000000000000000000000000001'; -// API docs: https://btc-assets-api.testnet.mibao.pro/docs -const BTC_ASSETS_API_URL = 'https://btc-assets-api.testnet.mibao.pro'; -// https://btc-assets-api.testnet.mibao.pro/docs/static/index.html#/Token/post_token_generate -const BTC_ASSETS_TOKEN = ''; - -const BTC_ASSETS_ORIGIN = 'https://btc-test.app'; - const createCluster = async ({ ownerRgbppLockArgs }: { ownerRgbppLockArgs: string }) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - - const network = isMainnet ? bitcoin.networks.bitcoin : bitcoin.networks.testnet; - const keyPair = ECPair.fromPrivateKey(Buffer.from(BTC_TEST_PRIVATE_KEY, 'hex'), { network }); - const { address: btcAddress } = bitcoin.payments.p2wpkh({ - pubkey: keyPair.publicKey, - network, - }); - - console.log('btc address: ', btcAddress); - - const networkType = isMainnet ? NetworkType.MAINNET : NetworkType.TESTNET; - const service = BtcAssetsApi.fromToken(BTC_ASSETS_API_URL, BTC_ASSETS_TOKEN, BTC_ASSETS_ORIGIN); - const source = new DataSource(service, networkType); - const ckbVirtualTxResult = await genCreateClusterCkbVirtualTx({ collector, rgbppLockArgs: ownerRgbppLockArgs, @@ -59,22 +31,22 @@ const createCluster = async ({ ownerRgbppLockArgs }: { ownerRgbppLockArgs: strin tos: [btcAddress!], ckbCollector: collector, from: btcAddress!, - source, + source: btcDataSource, feeRate: 30, }); - psbt.signAllInputs(keyPair); + psbt.signAllInputs(btcKeyPair); psbt.finalizeAllInputs(); const btcTx = psbt.extractTransaction(); const btcTxBytes = transactionToHex(btcTx, false); - const { txid: btcTxId } = await service.sendBtcTransaction(btcTx.toHex()); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); console.log('BTC TxId: ', btcTxId); const interval = setInterval(async () => { try { console.log('Waiting for BTC tx and proof to be ready'); - const rgbppApiSpvProof = await service.getRgbppSpvProof(btcTxId, 0); + const rgbppApiSpvProof = await btcService.getRgbppSpvProof(btcTxId, 0); clearInterval(interval); // Update CKB transaction with the real BTC txId const newCkbRawTx = updateCkbTxWithRealBtcTxId({ ckbRawTx, btcTxId, isMainnet }); diff --git a/examples/rgbpp/spore/3-create-spores.ts b/examples/rgbpp/spore/3-create-spores.ts index 38493df2..50e1f61a 100644 --- a/examples/rgbpp/spore/3-create-spores.ts +++ b/examples/rgbpp/spore/3-create-spores.ts @@ -1,5 +1,4 @@ import { - Collector, buildRgbppLockArgs, appendCkbTxWitnesses, updateCkbTxWithRealBtcTxId, @@ -9,29 +8,19 @@ import { appendIssuerCellToSporesCreate, generateSporeCreateCoBuild, } from '@rgbpp-sdk/ckb'; -import { - DataSource, - ECPair, - bitcoin, - NetworkType, - sendRgbppUtxos, - transactionToHex, - utf8ToBuffer, -} from '@rgbpp-sdk/btc'; -import { BtcAssetsApi, BtcAssetsApiError } from '@rgbpp-sdk/service'; +import { sendRgbppUtxos, transactionToHex, utf8ToBuffer } from '@rgbpp-sdk/btc'; +import { BtcAssetsApiError } from '@rgbpp-sdk/service'; import { RawSporeData } from '@spore-sdk/core'; -import { AddressPrefix, privateKeyToAddress } from '@nervosnetwork/ckb-sdk-utils'; - -// CKB SECP256K1 private key -const CKB_TEST_PRIVATE_KEY = '0x0000000000000000000000000000000000000000000000000000000000000001'; -// BTC SECP256K1 private key -const BTC_TEST_PRIVATE_KEY = '0000000000000000000000000000000000000000000000000000000000000001'; -// API docs: https://btc-assets-api.testnet.mibao.pro/docs -const BTC_ASSETS_API_URL = 'https://btc-assets-api.testnet.mibao.pro'; -// https://btc-assets-api.testnet.mibao.pro/docs/static/index.html#/Token/post_token_generate -const BTC_ASSETS_TOKEN = ''; - -const BTC_ASSETS_ORIGIN = 'https://btc-test.app'; +import { + isMainnet, + collector, + btcAddress, + btcDataSource, + btcKeyPair, + btcService, + CKB_PRIVATE_KEY, + ckbAddress, +} from 'examples-core'; interface Params { clusterRgbppLockArgs: Hex; @@ -42,30 +31,6 @@ interface Params { } const createSpores = async ({ clusterRgbppLockArgs, receivers }: Params) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - - const ckbAddress = privateKeyToAddress(CKB_TEST_PRIVATE_KEY, { - prefix: isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, - }); - console.log('ckb address: ', ckbAddress); - - const network = isMainnet ? bitcoin.networks.bitcoin : bitcoin.networks.testnet; - const keyPair = ECPair.fromPrivateKey(Buffer.from(BTC_TEST_PRIVATE_KEY, 'hex'), { network }); - const { address: btcAddress } = bitcoin.payments.p2wpkh({ - pubkey: keyPair.publicKey, - network, - }); - - console.log('btc address: ', btcAddress); - - const networkType = isMainnet ? NetworkType.MAINNET : NetworkType.TESTNET; - const service = BtcAssetsApi.fromToken(BTC_ASSETS_API_URL, BTC_ASSETS_TOKEN, BTC_ASSETS_ORIGIN); - const source = new DataSource(service, networkType); - const ckbVirtualTxResult = await genCreateSporeCkbVirtualTx({ collector, sporeDataList: receivers.map((receiver) => receiver.sporeData), @@ -85,22 +50,22 @@ const createSpores = async ({ clusterRgbppLockArgs, receivers }: Params) => { tos: btcTos, ckbCollector: collector, from: btcAddress!, - source, + source: btcDataSource, feeRate: 120, }); - psbt.signAllInputs(keyPair); + psbt.signAllInputs(btcKeyPair); psbt.finalizeAllInputs(); const btcTx = psbt.extractTransaction(); const btcTxBytes = transactionToHex(btcTx, false); - const { txid: btcTxId } = await service.sendBtcTransaction(btcTx.toHex()); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); console.log('BTC TxId: ', btcTxId); const interval = setInterval(async () => { try { console.log('Waiting for BTC tx and proof to be ready'); - const rgbppApiSpvProof = await service.getRgbppSpvProof(btcTxId, 0); + const rgbppApiSpvProof = await btcService.getRgbppSpvProof(btcTxId, 0); clearInterval(interval); // Update CKB transaction with the real BTC txId const newCkbRawTx = updateCkbTxWithRealBtcTxId({ ckbRawTx, btcTxId, isMainnet }); @@ -128,7 +93,7 @@ const createSpores = async ({ clusterRgbppLockArgs, receivers }: Params) => { // console.log('ckbTx: ', JSON.stringify(ckbTx)); const signedTx = await appendIssuerCellToSporesCreate({ - secp256k1PrivateKey: CKB_TEST_PRIVATE_KEY, + secp256k1PrivateKey: CKB_PRIVATE_KEY, issuerAddress: ckbAddress, ckbRawTx: ckbTx, collector, diff --git a/examples/rgbpp/spore/4-transfer-spore.ts b/examples/rgbpp/spore/4-transfer-spore.ts index 9aeff02d..2976456b 100644 --- a/examples/rgbpp/spore/4-transfer-spore.ts +++ b/examples/rgbpp/spore/4-transfer-spore.ts @@ -1,57 +1,21 @@ -import { - Collector, - buildRgbppLockArgs, - appendCkbTxWitnesses, - updateCkbTxWithRealBtcTxId, - sendCkbTx, - getSporeTypeScript, - Hex, - generateSporeTransferCoBuild, - genTransferSporeCkbVirtualTx, -} from '@rgbpp-sdk/ckb'; -import { DataSource, ECPair, bitcoin, NetworkType, sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; -import { BtcAssetsApi, BtcAssetsApiError } from '@rgbpp-sdk/service'; +import { buildRgbppLockArgs, getSporeTypeScript, Hex, genTransferSporeCkbVirtualTx } from '@rgbpp-sdk/ckb'; +import { sendRgbppUtxos } from '@rgbpp-sdk/btc'; import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; - -// BTC SECP256K1 private key -const BTC_TEST_PRIVATE_KEY = '0000000000000000000000000000000000000000000000000000000000000001'; -// API docs: https://btc-assets-api.testnet.mibao.pro/docs -const BTC_ASSETS_API_URL = 'https://btc-assets-api.testnet.mibao.pro'; -// https://btc-assets-api.testnet.mibao.pro/docs/static/index.html#/Token/post_token_generate -const BTC_ASSETS_TOKEN = ''; - -const BTC_ASSETS_ORIGIN = 'https://btc-test.app'; +import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from 'examples-core'; const transferSpore = async ({ sporeRgbppLockArgs, toBtcAddress, + sporeTypeArgs, }: { sporeRgbppLockArgs: Hex; toBtcAddress: string; + sporeTypeArgs: Hex; }) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - - const network = isMainnet ? bitcoin.networks.bitcoin : bitcoin.networks.testnet; - const keyPair = ECPair.fromPrivateKey(Buffer.from(BTC_TEST_PRIVATE_KEY, 'hex'), { network }); - const { address: btcAddress } = bitcoin.payments.p2wpkh({ - pubkey: keyPair.publicKey, - network, - }); - - console.log('btc address: ', btcAddress); - - const networkType = isMainnet ? NetworkType.MAINNET : NetworkType.TESTNET; - const service = BtcAssetsApi.fromToken(BTC_ASSETS_API_URL, BTC_ASSETS_TOKEN, BTC_ASSETS_ORIGIN); - const source = new DataSource(service, networkType); - - // The spore type script is from 3-create-spore.ts, you can find it from the ckb tx spore output cells + // The spore type script is from 3-create-spore.ts, you can find it from the ckb tx spore output cell const sporeTypeBytes = serializeScript({ ...getSporeTypeScript(isMainnet), - args: '0x205fe15af04e59d3ff1ff8e0b0a1e3bc201af406a38964760c24848ed6029b6b', + args: sporeTypeArgs, }); const ckbVirtualTxResult = await genTransferSporeCkbVirtualTx({ @@ -59,10 +23,9 @@ const transferSpore = async ({ sporeRgbppLockArgs, sporeTypeBytes, isMainnet, - ckbFeeRate: BigInt(5000), }); - const { commitment, ckbRawTx, sporeCell } = ckbVirtualTxResult; + const { commitment, ckbRawTx } = ckbVirtualTxResult; // console.log(JSON.stringify(ckbRawTx)) @@ -73,51 +36,42 @@ const transferSpore = async ({ tos: [toBtcAddress], ckbCollector: collector, from: btcAddress!, - source, + source: btcDataSource, feeRate: 30, }); - psbt.signAllInputs(keyPair); + psbt.signAllInputs(btcKeyPair); psbt.finalizeAllInputs(); const btcTx = psbt.extractTransaction(); - const btcTxBytes = transactionToHex(btcTx, false); - const { txid: btcTxId } = await service.sendBtcTransaction(btcTx.toHex()); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); console.log('BTC TxId: ', btcTxId); - const interval = setInterval(async () => { - try { - console.log('Waiting for BTC tx and proof to be ready'); - const rgbppApiSpvProof = await service.getRgbppSpvProof(btcTxId, 0); - clearInterval(interval); - // Update CKB transaction with the real BTC txId - const newCkbRawTx = updateCkbTxWithRealBtcTxId({ ckbRawTx, btcTxId, isMainnet }); - - const ckbTx = await appendCkbTxWitnesses({ - ckbRawTx: newCkbRawTx, - btcTxBytes, - rgbppApiSpvProof, - }); - - // Replace cobuild witness with the final rgbpp lock script - ckbTx.witnesses[ckbTx.witnesses.length - 1] = generateSporeTransferCoBuild([sporeCell], ckbTx.outputs); - - // console.log('ckbTx: ', JSON.stringify(ckbTx)); - - const txHash = await sendCkbTx({ collector, signedTx: ckbTx }); - console.info(`RGB++ Spore has been transferred and tx hash is ${txHash}`); - } catch (error) { - if (!(error instanceof BtcAssetsApiError)) { - console.error(error); + try { + await btcService.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); + const interval = setInterval(async () => { + const { state, failedReason } = await btcService.getRgbppTransactionState(btcTxId); + console.log('state', state); + if (state === 'completed' || state === 'failed') { + clearInterval(interval); + if (state === 'completed') { + const { txhash: txHash } = await btcService.getRgbppTransactionHash(btcTxId); + console.info(`Rgbpp spore has been transferred on BTC and the related CKB tx hash is ${txHash}`); + } else { + console.warn(`Rgbpp CKB transaction failed and the reason is ${failedReason} `); + } } - } - }, 30 * 1000); + }, 30 * 1000); + } catch (error) { + console.error(error); + } }; // Use your real BTC UTXO information on the BTC Testnet // rgbppLockArgs: outIndexU32 + btcTxId transferSpore({ // The spore rgbpp lock args is from 3-create-spore.ts - sporeRgbppLockArgs: buildRgbppLockArgs(1, 'f203c8c13eacdbd126f85d286a963c85f233f8145363b1d997c4d552afb990e1'), + sporeRgbppLockArgs: buildRgbppLockArgs(2, 'd5868dbde4be5e49876b496449df10150c356843afb6f94b08f8d81f394bb350'), toBtcAddress: 'tb1qhp9fh9qsfeyh0yhewgu27ndqhs5qlrqwau28m7', + sporeTypeArgs: '0x42898ea77062256f46e8f1b861d526ae47810ecc51ab50477945d5fa90452706', }); diff --git a/examples/rgbpp/spore/5-leap-spore-to-ckb.ts b/examples/rgbpp/spore/5-leap-spore-to-ckb.ts index dfb445d2..909076a5 100644 --- a/examples/rgbpp/spore/5-leap-spore-to-ckb.ts +++ b/examples/rgbpp/spore/5-leap-spore-to-ckb.ts @@ -1,57 +1,21 @@ -import { - Collector, - buildRgbppLockArgs, - appendCkbTxWitnesses, - updateCkbTxWithRealBtcTxId, - sendCkbTx, - getSporeTypeScript, - Hex, - generateSporeTransferCoBuild, - genLeapSporeFromBtcToCkbVirtualTx, -} from '@rgbpp-sdk/ckb'; -import { DataSource, ECPair, bitcoin, NetworkType, sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; -import { BtcAssetsApi, BtcAssetsApiError } from '@rgbpp-sdk/service'; +import { buildRgbppLockArgs, getSporeTypeScript, Hex, genLeapSporeFromBtcToCkbVirtualTx } from '@rgbpp-sdk/ckb'; +import { sendRgbppUtxos } from '@rgbpp-sdk/btc'; import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; - -// BTC SECP256K1 private key -const BTC_TEST_PRIVATE_KEY = '0000000000000000000000000000000000000000000000000000000000000001'; -// API docs: https://btc-assets-api.testnet.mibao.pro/docs -const BTC_ASSETS_API_URL = 'https://btc-assets-api.testnet.mibao.pro'; -// https://btc-assets-api.testnet.mibao.pro/docs/static/index.html#/Token/post_token_generate -const BTC_ASSETS_TOKEN = ''; - -const BTC_ASSETS_ORIGIN = 'https://btc-test.app'; +import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from 'examples-core'; const transferSpore = async ({ sporeRgbppLockArgs, toCkbAddress, + sporeTypeArgs, }: { sporeRgbppLockArgs: Hex; toCkbAddress: string; + sporeTypeArgs: Hex; }) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - - const network = isMainnet ? bitcoin.networks.bitcoin : bitcoin.networks.testnet; - const keyPair = ECPair.fromPrivateKey(Buffer.from(BTC_TEST_PRIVATE_KEY, 'hex'), { network }); - const { address: btcAddress } = bitcoin.payments.p2wpkh({ - pubkey: keyPair.publicKey, - network, - }); - - console.log('btc address: ', btcAddress); - - const networkType = isMainnet ? NetworkType.MAINNET : NetworkType.TESTNET; - const service = BtcAssetsApi.fromToken(BTC_ASSETS_API_URL, BTC_ASSETS_TOKEN, BTC_ASSETS_ORIGIN); - const source = new DataSource(service, networkType); - // The spore type script is from 3-create-spore.ts, you can find it from the ckb tx spore output cells const sporeTypeBytes = serializeScript({ ...getSporeTypeScript(isMainnet), - args: '0x42898ea77062256f46e8f1b861d526ae47810ecc51ab50477945d5fa90452706', + args: sporeTypeArgs, }); const ckbVirtualTxResult = await genLeapSporeFromBtcToCkbVirtualTx({ @@ -62,7 +26,7 @@ const transferSpore = async ({ isMainnet, }); - const { commitment, ckbRawTx, sporeCell } = ckbVirtualTxResult; + const { commitment, ckbRawTx } = ckbVirtualTxResult; // console.log(JSON.stringify(ckbRawTx)) @@ -73,45 +37,35 @@ const transferSpore = async ({ tos: [btcAddress!], ckbCollector: collector, from: btcAddress!, - source, - feeRate: 120, + source: btcDataSource, + feeRate: 30, }); - psbt.signAllInputs(keyPair); + psbt.signAllInputs(btcKeyPair); psbt.finalizeAllInputs(); const btcTx = psbt.extractTransaction(); - const btcTxBytes = transactionToHex(btcTx, false); - const { txid: btcTxId } = await service.sendBtcTransaction(btcTx.toHex()); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); console.log('BTC TxId: ', btcTxId); - const interval = setInterval(async () => { - try { - console.log('Waiting for BTC tx and proof to be ready'); - const rgbppApiSpvProof = await service.getRgbppSpvProof(btcTxId, 0); - clearInterval(interval); - // Update CKB transaction with the real BTC txId - const newCkbRawTx = updateCkbTxWithRealBtcTxId({ ckbRawTx, btcTxId, isMainnet }); - - const ckbTx = await appendCkbTxWitnesses({ - ckbRawTx: newCkbRawTx, - btcTxBytes, - rgbppApiSpvProof, - }); - - // Replace cobuild witness with the final rgbpp lock script - ckbTx.witnesses[ckbTx.witnesses.length - 1] = generateSporeTransferCoBuild([sporeCell], ckbTx.outputs); - - // console.log('ckbTx: ', JSON.stringify(ckbTx)); - - const txHash = await sendCkbTx({ collector, signedTx: ckbTx }); - console.info(`RGB++ Spore has been leaped from BTC to CKB and tx hash is ${txHash}`); - } catch (error) { - if (!(error instanceof BtcAssetsApiError)) { - console.error(error); + try { + await btcService.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); + const interval = setInterval(async () => { + const { state, failedReason } = await btcService.getRgbppTransactionState(btcTxId); + console.log('state', state); + if (state === 'completed' || state === 'failed') { + clearInterval(interval); + if (state === 'completed') { + const { txhash: txHash } = await btcService.getRgbppTransactionHash(btcTxId); + console.info(`Rgbpp spore has been leaped from BTC to CKB and the related CKB tx hash is ${txHash}`); + } else { + console.warn(`Rgbpp CKB transaction failed and the reason is ${failedReason} `); + } } - } - }, 30 * 1000); + }, 30 * 1000); + } catch (error) { + console.error(error); + } }; // Use your real BTC UTXO information on the BTC Testnet @@ -120,4 +74,5 @@ transferSpore({ // The spore rgbpp lock args is from 3-create-spore.ts sporeRgbppLockArgs: buildRgbppLockArgs(3, 'd8a31796fbd42c546f6b22014b9b82b16586ce1df81b0e7ca9a552cdc492a0af'), toCkbAddress: 'ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq0e4xk4rmg5jdkn8aams492a7jlg73ue0gc0ddfj', + sporeTypeArgs: '0x42898ea77062256f46e8f1b861d526ae47810ecc51ab50477945d5fa90452706', }); diff --git a/examples/rgbpp/spore/6-unlock-btc-time-cell.ts b/examples/rgbpp/spore/6-unlock-btc-time-cell.ts index 2d333e96..c610600f 100644 --- a/examples/rgbpp/spore/6-unlock-btc-time-cell.ts +++ b/examples/rgbpp/spore/6-unlock-btc-time-cell.ts @@ -1,35 +1,8 @@ -import { AddressPrefix, privateKeyToAddress } from '@nervosnetwork/ckb-sdk-utils'; -import { - Collector, - sendCkbTx, - getBtcTimeLockScript, - buildSporeBtcTimeCellsSpentTx, - signBtcTimeCellSpentTx, -} from '@rgbpp-sdk/ckb'; -import { BtcAssetsApi } from '@rgbpp-sdk/service'; - -// CKB SECP256K1 private key -const CKB_TEST_PRIVATE_KEY = '0x0000000000000000000000000000000000000000000000000000000000000001'; -// API docs: https://btc-assets-api.testnet.mibao.pro/docs -const BTC_ASSETS_API_URL = 'https://btc-assets-api.testnet.mibao.pro'; -// https://btc-assets-api.testnet.mibao.pro/docs/static/index.html#/Token/post_token_generate -const BTC_ASSETS_TOKEN = ''; - -const BTC_ASSETS_ORIGIN = 'https://btc-test.app'; +import { sendCkbTx, getBtcTimeLockScript, buildSporeBtcTimeCellsSpentTx, signBtcTimeCellSpentTx } from '@rgbpp-sdk/ckb'; +import { CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from 'examples-core'; // Warning: Wait at least 6 BTC confirmation blocks to spend the BTC time cells after 4-btc-jump-ckb.ts const unlockSporeBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: string }) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - - const address = privateKeyToAddress(CKB_TEST_PRIVATE_KEY, { - prefix: isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, - }); - console.log('ckb address: ', address); - const btcTimeCells = await collector.getCells({ lock: { ...getBtcTimeLockScript(false), @@ -42,18 +15,16 @@ const unlockSporeBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: st throw new Error('No btc time cells found'); } - const btcAssetsApi = BtcAssetsApi.fromToken(BTC_ASSETS_API_URL, BTC_ASSETS_TOKEN, BTC_ASSETS_ORIGIN); - const ckbRawTx: CKBComponents.RawTransaction = await buildSporeBtcTimeCellsSpentTx({ btcTimeCells, - btcAssetsApi, + btcAssetsApi: btcService, isMainnet, }); const signedTx = await signBtcTimeCellSpentTx({ - secp256k1PrivateKey: CKB_TEST_PRIVATE_KEY, + secp256k1PrivateKey: CKB_PRIVATE_KEY, collector, - masterCkbAddress: address, + masterCkbAddress: ckbAddress, ckbRawTx, isMainnet, }); diff --git a/examples/rgbpp/spore/7-leap-spore-to-btc.ts b/examples/rgbpp/spore/7-leap-spore-to-btc.ts index ae73382a..77d3d081 100644 --- a/examples/rgbpp/spore/7-leap-spore-to-btc.ts +++ b/examples/rgbpp/spore/7-leap-spore-to-btc.ts @@ -1,36 +1,31 @@ -import { AddressPrefix, privateKeyToAddress, serializeScript } from '@nervosnetwork/ckb-sdk-utils'; +import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; import { - Collector, getSecp256k1CellDep, buildRgbppLockArgs, getSporeTypeScript, genLeapSporeFromCkbToBtcRawTx, } from '@rgbpp-sdk/ckb'; - -// CKB SECP256K1 private key -const CKB_TEST_PRIVATE_KEY = '0x0000000000000000000000000000000000000000000000000000000000000001'; - -const leapSporeFromCkbToBtc = async ({ outIndex, btcTxId }: { outIndex: number; btcTxId: string }) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - const address = privateKeyToAddress(CKB_TEST_PRIVATE_KEY, { - prefix: isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, - }); - console.log('ckb address: ', address); - +import { isMainnet, collector, ckbAddress, CKB_PRIVATE_KEY } from 'examples-core'; + +const leapSporeFromCkbToBtc = async ({ + outIndex, + btcTxId, + sporeTypeArgs, +}: { + outIndex: number; + btcTxId: string; + sporeTypeArgs: string; +}) => { const toRgbppLockArgs = buildRgbppLockArgs(outIndex, btcTxId); const sporeType: CKBComponents.Script = { ...getSporeTypeScript(isMainnet), - args: '0x42898ea77062256f46e8f1b861d526ae47810ecc51ab50477945d5fa90452706', + args: sporeTypeArgs, }; const ckbRawTx = await genLeapSporeFromCkbToBtcRawTx({ collector, - fromCkbAddress: address, + fromCkbAddress: ckbAddress, toRgbppLockArgs, sporeTypeBytes: serializeScript(sporeType), isMainnet, @@ -43,7 +38,7 @@ const leapSporeFromCkbToBtc = async ({ outIndex, btcTxId }: { outIndex: number; witnesses: [emptyWitness, ...ckbRawTx.witnesses.slice(1)], }; - const signedTx = collector.getCkb().signTransaction(CKB_TEST_PRIVATE_KEY)(unsignedTx); + const signedTx = collector.getCkb().signTransaction(CKB_PRIVATE_KEY)(unsignedTx); const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); console.info(`RGB++ Spore has been jumped from CKB to BTC and tx hash is ${txHash}`); @@ -53,4 +48,5 @@ const leapSporeFromCkbToBtc = async ({ outIndex, btcTxId }: { outIndex: number; leapSporeFromCkbToBtc({ outIndex: 1, btcTxId: '448897515cf07b4ca0cd38af9806399ede55775b4c760b274ed2322121ed185f', + sporeTypeArgs: '0x42898ea77062256f46e8f1b861d526ae47810ecc51ab50477945d5fa90452706', }); diff --git a/examples/rgbpp/spore/local/4-transfer-spore.ts b/examples/rgbpp/spore/local/4-transfer-spore.ts new file mode 100644 index 00000000..0662d0bd --- /dev/null +++ b/examples/rgbpp/spore/local/4-transfer-spore.ts @@ -0,0 +1,98 @@ +import { + buildRgbppLockArgs, + appendCkbTxWitnesses, + updateCkbTxWithRealBtcTxId, + sendCkbTx, + getSporeTypeScript, + Hex, + generateSporeTransferCoBuild, + genTransferSporeCkbVirtualTx, +} from '@rgbpp-sdk/ckb'; +import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; +import { BtcAssetsApiError } from '@rgbpp-sdk/service'; +import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; +import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from 'examples-core'; + +const transferSpore = async ({ + sporeRgbppLockArgs, + toBtcAddress, + sporeTypeArgs, +}: { + sporeRgbppLockArgs: Hex; + toBtcAddress: string; + sporeTypeArgs: string; +}) => { + // The spore type script is from 3-create-spore.ts, you can find it from the ckb tx spore output cells + const sporeTypeBytes = serializeScript({ + ...getSporeTypeScript(isMainnet), + args: sporeTypeArgs, + }); + + const ckbVirtualTxResult = await genTransferSporeCkbVirtualTx({ + collector, + sporeRgbppLockArgs, + sporeTypeBytes, + isMainnet, + ckbFeeRate: BigInt(5000), + }); + + const { commitment, ckbRawTx, sporeCell } = ckbVirtualTxResult; + + // console.log(JSON.stringify(ckbRawTx)) + + // Send BTC tx + const psbt = await sendRgbppUtxos({ + ckbVirtualTx: ckbRawTx, + commitment, + tos: [toBtcAddress], + ckbCollector: collector, + from: btcAddress!, + source: btcDataSource, + feeRate: 30, + }); + psbt.signAllInputs(btcKeyPair); + psbt.finalizeAllInputs(); + + const btcTx = psbt.extractTransaction(); + const btcTxBytes = transactionToHex(btcTx, false); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); + + console.log('BTC TxId: ', btcTxId); + + const interval = setInterval(async () => { + try { + console.log('Waiting for BTC tx and proof to be ready'); + const rgbppApiSpvProof = await btcService.getRgbppSpvProof(btcTxId, 0); + clearInterval(interval); + // Update CKB transaction with the real BTC txId + const newCkbRawTx = updateCkbTxWithRealBtcTxId({ ckbRawTx, btcTxId, isMainnet }); + + const ckbTx = await appendCkbTxWitnesses({ + ckbRawTx: newCkbRawTx, + btcTxBytes, + rgbppApiSpvProof, + }); + + // Replace cobuild witness with the final rgbpp lock script + ckbTx.witnesses[ckbTx.witnesses.length - 1] = generateSporeTransferCoBuild([sporeCell], ckbTx.outputs); + + // console.log('ckbTx: ', JSON.stringify(ckbTx)); + + const txHash = await sendCkbTx({ collector, signedTx: ckbTx }); + console.info(`RGB++ Spore has been transferred and tx hash is ${txHash}`); + } catch (error) { + if (!(error instanceof BtcAssetsApiError)) { + console.error(error); + } + } + }, 30 * 1000); +}; + +// Use your real BTC UTXO information on the BTC Testnet +// rgbppLockArgs: outIndexU32 + btcTxId +transferSpore({ + // The spore rgbpp lock args is from 3-create-spore.ts + sporeRgbppLockArgs: buildRgbppLockArgs(1, 'f203c8c13eacdbd126f85d286a963c85f233f8145363b1d997c4d552afb990e1'), + toBtcAddress: 'tb1qhp9fh9qsfeyh0yhewgu27ndqhs5qlrqwau28m7', + sporeTypeArgs: '0x42898ea77062256f46e8f1b861d526ae47810ecc51ab50477945d5fa90452706', +}); diff --git a/examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts b/examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts new file mode 100644 index 00000000..21e7c6ae --- /dev/null +++ b/examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts @@ -0,0 +1,98 @@ +import { + buildRgbppLockArgs, + appendCkbTxWitnesses, + updateCkbTxWithRealBtcTxId, + sendCkbTx, + getSporeTypeScript, + Hex, + generateSporeTransferCoBuild, + genLeapSporeFromBtcToCkbVirtualTx, +} from '@rgbpp-sdk/ckb'; +import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; +import { BtcAssetsApiError } from '@rgbpp-sdk/service'; +import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; +import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from 'examples-core'; + +const transferSpore = async ({ + sporeRgbppLockArgs, + toCkbAddress, + sporeTypeArgs, +}: { + sporeRgbppLockArgs: Hex; + toCkbAddress: string; + sporeTypeArgs: Hex; +}) => { + // The spore type script is from 3-create-spore.ts, you can find it from the ckb tx spore output cells + const sporeTypeBytes = serializeScript({ + ...getSporeTypeScript(isMainnet), + args: sporeTypeArgs, + }); + + const ckbVirtualTxResult = await genLeapSporeFromBtcToCkbVirtualTx({ + collector, + sporeRgbppLockArgs, + sporeTypeBytes, + toCkbAddress, + isMainnet, + }); + + const { commitment, ckbRawTx, sporeCell } = ckbVirtualTxResult; + + // console.log(JSON.stringify(ckbRawTx)) + + // Send BTC tx + const psbt = await sendRgbppUtxos({ + ckbVirtualTx: ckbRawTx, + commitment, + tos: [btcAddress!], + ckbCollector: collector, + from: btcAddress!, + source: btcDataSource, + feeRate: 120, + }); + psbt.signAllInputs(btcKeyPair); + psbt.finalizeAllInputs(); + + const btcTx = psbt.extractTransaction(); + const btcTxBytes = transactionToHex(btcTx, false); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); + + console.log('BTC TxId: ', btcTxId); + + const interval = setInterval(async () => { + try { + console.log('Waiting for BTC tx and proof to be ready'); + const rgbppApiSpvProof = await btcService.getRgbppSpvProof(btcTxId, 0); + clearInterval(interval); + // Update CKB transaction with the real BTC txId + const newCkbRawTx = updateCkbTxWithRealBtcTxId({ ckbRawTx, btcTxId, isMainnet }); + + const ckbTx = await appendCkbTxWitnesses({ + ckbRawTx: newCkbRawTx, + btcTxBytes, + rgbppApiSpvProof, + }); + + // Replace cobuild witness with the final rgbpp lock script + ckbTx.witnesses[ckbTx.witnesses.length - 1] = generateSporeTransferCoBuild([sporeCell], ckbTx.outputs); + + // console.log('ckbTx: ', JSON.stringify(ckbTx)); + + const txHash = await sendCkbTx({ collector, signedTx: ckbTx }); + console.info(`RGB++ Spore has been leaped from BTC to CKB and tx hash is ${txHash}`); + } catch (error) { + if (!(error instanceof BtcAssetsApiError)) { + console.error(error); + } + } + }, 30 * 1000); +}; + +// Use your real BTC UTXO information on the BTC Testnet +// rgbppLockArgs: outIndexU32 + btcTxId +transferSpore({ + // The spore rgbpp lock args is from 3-create-spore.ts + sporeRgbppLockArgs: buildRgbppLockArgs(3, 'd8a31796fbd42c546f6b22014b9b82b16586ce1df81b0e7ca9a552cdc492a0af'), + toCkbAddress: 'ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq0e4xk4rmg5jdkn8aams492a7jlg73ue0gc0ddfj', + sporeTypeArgs: '0x42898ea77062256f46e8f1b861d526ae47810ecc51ab50477945d5fa90452706', +}); diff --git a/examples/rgbpp/spore/queue/4-transfer-spore.ts b/examples/rgbpp/spore/queue/4-transfer-spore.ts deleted file mode 100644 index 24b7b39f..00000000 --- a/examples/rgbpp/spore/queue/4-transfer-spore.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { Collector, buildRgbppLockArgs, getSporeTypeScript, Hex, genTransferSporeCkbVirtualTx } from '@rgbpp-sdk/ckb'; -import { DataSource, ECPair, bitcoin, NetworkType, sendRgbppUtxos } from '@rgbpp-sdk/btc'; -import { BtcAssetsApi } from '@rgbpp-sdk/service'; -import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; - -// BTC SECP256K1 private key -const BTC_TEST_PRIVATE_KEY = '0000000000000000000000000000000000000000000000000000000000000001'; -// API docs: https://btc-assets-api.testnet.mibao.pro/docs -const BTC_ASSETS_API_URL = 'https://btc-assets-api.testnet.mibao.pro'; -// https://btc-assets-api.testnet.mibao.pro/docs/static/index.html#/Token/post_token_generate -const BTC_ASSETS_TOKEN = ''; - -const BTC_ASSETS_ORIGIN = 'https://btc-test.app'; - -const transferSpore = async ({ - sporeRgbppLockArgs, - toBtcAddress, -}: { - sporeRgbppLockArgs: Hex; - toBtcAddress: string; -}) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - - const network = isMainnet ? bitcoin.networks.bitcoin : bitcoin.networks.testnet; - const keyPair = ECPair.fromPrivateKey(Buffer.from(BTC_TEST_PRIVATE_KEY, 'hex'), { network }); - const { address: btcAddress } = bitcoin.payments.p2wpkh({ - pubkey: keyPair.publicKey, - network, - }); - - console.log('btc address: ', btcAddress); - - const networkType = isMainnet ? NetworkType.MAINNET : NetworkType.TESTNET; - const service = BtcAssetsApi.fromToken(BTC_ASSETS_API_URL, BTC_ASSETS_TOKEN, BTC_ASSETS_ORIGIN); - const source = new DataSource(service, networkType); - - // The spore type script is from 3-create-spore.ts, you can find it from the ckb tx spore output cell - const sporeTypeBytes = serializeScript({ - ...getSporeTypeScript(isMainnet), - args: '0x205fe15af04e59d3ff1ff8e0b0a1e3bc201af406a38964760c24848ed6029b6b', - }); - - const ckbVirtualTxResult = await genTransferSporeCkbVirtualTx({ - collector, - sporeRgbppLockArgs, - sporeTypeBytes, - isMainnet, - }); - - const { commitment, ckbRawTx } = ckbVirtualTxResult; - - // console.log(JSON.stringify(ckbRawTx)) - - // Send BTC tx - const psbt = await sendRgbppUtxos({ - ckbVirtualTx: ckbRawTx, - commitment, - tos: [toBtcAddress], - ckbCollector: collector, - from: btcAddress!, - source, - feeRate: 30, - }); - psbt.signAllInputs(keyPair); - psbt.finalizeAllInputs(); - - const btcTx = psbt.extractTransaction(); - const { txid: btcTxId } = await service.sendBtcTransaction(btcTx.toHex()); - - console.log('BTC TxId: ', btcTxId); - - try { - await service.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); - const interval = setInterval(async () => { - const { state, failedReason } = await service.getRgbppTransactionState(btcTxId); - console.log('state', state); - if (state === 'completed' || state === 'failed') { - clearInterval(interval); - if (state === 'completed') { - const { txhash: txHash } = await service.getRgbppTransactionHash(btcTxId); - console.info(`Rgbpp spore has been transferred on BTC and the related CKB tx hash is ${txHash}`); - } else { - console.warn(`Rgbpp CKB transaction failed and the reason is ${failedReason} `); - } - } - }, 30 * 1000); - } catch (error) { - console.error(error); - } -}; - -// Use your real BTC UTXO information on the BTC Testnet -// rgbppLockArgs: outIndexU32 + btcTxId -transferSpore({ - // The spore rgbpp lock args is from 3-create-spore.ts - sporeRgbppLockArgs: buildRgbppLockArgs(2, 'd5868dbde4be5e49876b496449df10150c356843afb6f94b08f8d81f394bb350'), - toBtcAddress: 'tb1qhp9fh9qsfeyh0yhewgu27ndqhs5qlrqwau28m7', -}); diff --git a/examples/rgbpp/spore/queue/5-leap-spore-to-ckb.ts b/examples/rgbpp/spore/queue/5-leap-spore-to-ckb.ts deleted file mode 100644 index 9ce5497c..00000000 --- a/examples/rgbpp/spore/queue/5-leap-spore-to-ckb.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { - Collector, - buildRgbppLockArgs, - getSporeTypeScript, - Hex, - genLeapSporeFromBtcToCkbVirtualTx, -} from '@rgbpp-sdk/ckb'; -import { DataSource, ECPair, bitcoin, NetworkType, sendRgbppUtxos } from '@rgbpp-sdk/btc'; -import { BtcAssetsApi } from '@rgbpp-sdk/service'; -import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; - -// BTC SECP256K1 private key -const BTC_TEST_PRIVATE_KEY = '0000000000000000000000000000000000000000000000000000000000000001'; -// API docs: https://btc-assets-api.testnet.mibao.pro/docs -const BTC_ASSETS_API_URL = 'https://btc-assets-api.testnet.mibao.pro'; -// https://btc-assets-api.testnet.mibao.pro/docs/static/index.html#/Token/post_token_generate -const BTC_ASSETS_TOKEN = ''; - -const BTC_ASSETS_ORIGIN = 'https://btc-test.app'; - -const transferSpore = async ({ - sporeRgbppLockArgs, - toCkbAddress, -}: { - sporeRgbppLockArgs: Hex; - toCkbAddress: string; -}) => { - const collector = new Collector({ - ckbNodeUrl: 'https://testnet.ckb.dev/rpc', - ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', - }); - const isMainnet = false; - - const network = isMainnet ? bitcoin.networks.bitcoin : bitcoin.networks.testnet; - const keyPair = ECPair.fromPrivateKey(Buffer.from(BTC_TEST_PRIVATE_KEY, 'hex'), { network }); - const { address: btcAddress } = bitcoin.payments.p2wpkh({ - pubkey: keyPair.publicKey, - network, - }); - - console.log('btc address: ', btcAddress); - - const networkType = isMainnet ? NetworkType.MAINNET : NetworkType.TESTNET; - const service = BtcAssetsApi.fromToken(BTC_ASSETS_API_URL, BTC_ASSETS_TOKEN, BTC_ASSETS_ORIGIN); - const source = new DataSource(service, networkType); - - // The spore type script is from 3-create-spore.ts, you can find it from the ckb tx spore output cells - const sporeTypeBytes = serializeScript({ - ...getSporeTypeScript(isMainnet), - args: '0x42898ea77062256f46e8f1b861d526ae47810ecc51ab50477945d5fa90452706', - }); - - const ckbVirtualTxResult = await genLeapSporeFromBtcToCkbVirtualTx({ - collector, - sporeRgbppLockArgs, - sporeTypeBytes, - toCkbAddress, - isMainnet, - }); - - const { commitment, ckbRawTx } = ckbVirtualTxResult; - - // console.log(JSON.stringify(ckbRawTx)) - - // Send BTC tx - const psbt = await sendRgbppUtxos({ - ckbVirtualTx: ckbRawTx, - commitment, - tos: [btcAddress!], - ckbCollector: collector, - from: btcAddress!, - source, - feeRate: 30, - }); - psbt.signAllInputs(keyPair); - psbt.finalizeAllInputs(); - - const btcTx = psbt.extractTransaction(); - const { txid: btcTxId } = await service.sendBtcTransaction(btcTx.toHex()); - - console.log('BTC TxId: ', btcTxId); - - try { - await service.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); - const interval = setInterval(async () => { - const { state, failedReason } = await service.getRgbppTransactionState(btcTxId); - console.log('state', state); - if (state === 'completed' || state === 'failed') { - clearInterval(interval); - if (state === 'completed') { - const { txhash: txHash } = await service.getRgbppTransactionHash(btcTxId); - console.info(`Rgbpp spore has been leaped from BTC to CKB and the related CKB tx hash is ${txHash}`); - } else { - console.warn(`Rgbpp CKB transaction failed and the reason is ${failedReason} `); - } - } - }, 30 * 1000); - } catch (error) { - console.error(error); - } -}; - -// Use your real BTC UTXO information on the BTC Testnet -// rgbppLockArgs: outIndexU32 + btcTxId -transferSpore({ - // The spore rgbpp lock args is from 3-create-spore.ts - sporeRgbppLockArgs: buildRgbppLockArgs(3, 'd8a31796fbd42c546f6b22014b9b82b16586ce1df81b0e7ca9a552cdc492a0af'), - toCkbAddress: 'ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq0e4xk4rmg5jdkn8aams492a7jlg73ue0gc0ddfj', -}); diff --git a/examples/rgbpp/tsconfig.json b/examples/rgbpp/tsconfig.json index 3ac8b03f..0f0b1f2b 100644 --- a/examples/rgbpp/tsconfig.json +++ b/examples/rgbpp/tsconfig.json @@ -21,6 +21,6 @@ "skipLibCheck": true, "strict": true }, - "include": ["local/**/*.ts", "queue/**/*.ts"], + "include": ["queue/**/*.ts", "xudt/**/*.ts", "core/*.ts"], "exclude": ["node_modules"] } From fc19f96947026cadf05b0aa342b3ecd7319870e5 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Wed, 8 May 2024 20:32:29 +0800 Subject: [PATCH 28/78] refactor: Update btc package export --- .gitignore | 2 ++ packages/btc/src/bitcoin.ts | 3 ++- pnpm-lock.yaml | 39 +++++++++++++++++++++++++++++++++---- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index dfd9f2f7..f3c703cd 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ .env.development.local .env.production.local .env.test.local +.env **/.npmrc # logs @@ -40,3 +41,4 @@ yarn-error.log* devbox.json devbox.lock .envrc + diff --git a/packages/btc/src/bitcoin.ts b/packages/btc/src/bitcoin.ts index c18fc83c..7673eeac 100644 --- a/packages/btc/src/bitcoin.ts +++ b/packages/btc/src/bitcoin.ts @@ -1,4 +1,4 @@ -import ECPairFactory from 'ecpair'; +import ECPairFactory, { ECPairInterface } from 'ecpair'; import ecc from '@bitcoinerlab/secp256k1'; import * as bitcoin from 'bitcoinjs-lib'; import { isTaprootInput } from 'bitcoinjs-lib/src/psbt/bip371'; @@ -7,4 +7,5 @@ bitcoin.initEccLib(ecc); const ECPair = ECPairFactory(ecc); +export type { ECPairInterface }; export { ecc, ECPair, bitcoin, isTaprootInput }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cb21d6ed..1fe96902 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -134,7 +134,7 @@ importers: specifier: ^0.21.0 version: 0.21.0(vite@5.2.11) - examples/rgbpp: + examples/core: dependencies: '@exact-realty/multipart-parser': specifier: ^1.0.13 @@ -160,19 +160,50 @@ importers: devDependencies: '@types/node': specifier: ^20.11.28 - version: 20.11.28 + version: 20.12.2 typescript: specifier: ^5.4.2 - version: 5.4.2 + version: 5.4.3 - examples/xudt: + examples/rgbpp: dependencies: + '@exact-realty/multipart-parser': + specifier: ^1.0.13 + version: 1.0.13 '@nervosnetwork/ckb-sdk-utils': specifier: ^0.109.1 version: 0.109.1 + '@rgbpp-sdk/btc': + specifier: workspace:^ + version: link:../../packages/btc '@rgbpp-sdk/ckb': specifier: workspace:^ version: link:../../packages/ckb + '@rgbpp-sdk/service': + specifier: workspace:^ + version: link:../../packages/service + '@spore-sdk/core': + specifier: ^0.2.0-beta.6 + version: 0.2.0-beta.6(@ckb-lumos/lumos@0.22.0-next.5)(lodash@4.17.21) + examples-core: + specifier: workspace:^ + version: link:../core + devDependencies: + '@types/node': + specifier: ^20.11.28 + version: 20.11.28 + typescript: + specifier: ^5.4.2 + version: 5.4.2 + + examples/xudt: + dependencies: + '@rgbpp-sdk/ckb': + specifier: workspace:^ + version: link:../../packages/ckb + examples-core: + specifier: workspace:^ + version: link:../core packages/btc: dependencies: From 1d33bae4add8a7f6b6dddd21f2f22e68777ef4e6 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Wed, 8 May 2024 21:00:15 +0800 Subject: [PATCH 29/78] refactor: Move spore transfer and leap to examples-core --- examples/core/src/rgbpp/index.ts | 1 + examples/core/src/rgbpp/spore.ts | 105 ++++++++++++++++++ examples/rgbpp/spore/4-transfer-spore.ts | 53 +-------- examples/rgbpp/spore/5-leap-spore-to-ckb.ts | 56 +--------- .../spore/{ => launch}/0-cluster-info.ts | 0 .../spore/{ => launch}/1-prepare-cluster.ts | 0 .../spore/{ => launch}/2-create-cluster.ts | 0 .../spore/{ => launch}/3-create-spores.ts | 0 examples/rgbpp/tsconfig.json | 2 +- .../{1-ckb-jump-btc.ts => 1-ckb-leap-btc.ts} | 0 .../{3-btc-jump-ckb.ts => 3-btc-leap-ckb.ts} | 0 ...time-cell.ts => 4-unlock-btc-time-cell.ts} | 4 +- examples/rgbpp/xudt/local/1-ckb-jump-btc.ts | 44 -------- .../{3-btc-jump-ckb.ts => 3-btc-leap-ckb.ts} | 4 +- 14 files changed, 120 insertions(+), 149 deletions(-) create mode 100644 examples/core/src/rgbpp/spore.ts rename examples/rgbpp/spore/{ => launch}/0-cluster-info.ts (100%) rename examples/rgbpp/spore/{ => launch}/1-prepare-cluster.ts (100%) rename examples/rgbpp/spore/{ => launch}/2-create-cluster.ts (100%) rename examples/rgbpp/spore/{ => launch}/3-create-spores.ts (100%) rename examples/rgbpp/xudt/{1-ckb-jump-btc.ts => 1-ckb-leap-btc.ts} (100%) rename examples/rgbpp/xudt/{3-btc-jump-ckb.ts => 3-btc-leap-ckb.ts} (100%) rename examples/rgbpp/xudt/{local/4-spend-btc-time-cell.ts => 4-unlock-btc-time-cell.ts} (93%) delete mode 100644 examples/rgbpp/xudt/local/1-ckb-jump-btc.ts rename examples/rgbpp/xudt/local/{3-btc-jump-ckb.ts => 3-btc-leap-ckb.ts} (97%) diff --git a/examples/core/src/rgbpp/index.ts b/examples/core/src/rgbpp/index.ts index 7fa4382e..03e3f45e 100644 --- a/examples/core/src/rgbpp/index.ts +++ b/examples/core/src/rgbpp/index.ts @@ -1 +1,2 @@ export * from './xudt'; +export * from './spore'; diff --git a/examples/core/src/rgbpp/spore.ts b/examples/core/src/rgbpp/spore.ts new file mode 100644 index 00000000..095deffe --- /dev/null +++ b/examples/core/src/rgbpp/spore.ts @@ -0,0 +1,105 @@ +import { + getSporeTypeScript, + Hex, + genTransferSporeCkbVirtualTx, + genLeapSporeFromBtcToCkbVirtualTx, +} from '@rgbpp-sdk/ckb'; +import { sendRgbppUtxos } from '@rgbpp-sdk/btc'; +import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; +import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../utils'; + +export interface SporeTransferParams { + sporeRgbppLockArgs: Hex; + toBtcAddress: string; + sporeTypeArgs: Hex; +} + +export const transferSporeOnBtc = async ({ + sporeRgbppLockArgs, + toBtcAddress, + sporeTypeArgs, +}: SporeTransferParams): Promise => { + const sporeTypeBytes = serializeScript({ + ...getSporeTypeScript(isMainnet), + args: sporeTypeArgs, + }); + + const ckbVirtualTxResult = await genTransferSporeCkbVirtualTx({ + collector, + sporeRgbppLockArgs, + sporeTypeBytes, + isMainnet, + }); + + const { commitment, ckbRawTx } = ckbVirtualTxResult; + + // Send BTC tx + const psbt = await sendRgbppUtxos({ + ckbVirtualTx: ckbRawTx, + commitment, + tos: [toBtcAddress], + ckbCollector: collector, + from: btcAddress!, + source: btcDataSource, + feeRate: 30, + }); + psbt.signAllInputs(btcKeyPair); + psbt.finalizeAllInputs(); + + const btcTx = psbt.extractTransaction(); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); + + console.log('BTC TxId: ', btcTxId); + + await btcService.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); + + return btcTxId; +}; + +export interface SporeLeapParams { + sporeRgbppLockArgs: Hex; + toCkbAddress: string; + sporeTypeArgs: Hex; +} +export const leapSporeToCkb = async ({ + sporeRgbppLockArgs, + toCkbAddress, + sporeTypeArgs, +}: SporeLeapParams): Promise => { + const sporeTypeBytes = serializeScript({ + ...getSporeTypeScript(isMainnet), + args: sporeTypeArgs, + }); + + const ckbVirtualTxResult = await genLeapSporeFromBtcToCkbVirtualTx({ + collector, + sporeRgbppLockArgs, + sporeTypeBytes, + toCkbAddress, + isMainnet, + }); + + const { commitment, ckbRawTx } = ckbVirtualTxResult; + + // Send BTC tx + const psbt = await sendRgbppUtxos({ + ckbVirtualTx: ckbRawTx, + commitment, + tos: [btcAddress!], + ckbCollector: collector, + from: btcAddress!, + source: btcDataSource, + feeRate: 30, + }); + psbt.signAllInputs(btcKeyPair); + psbt.finalizeAllInputs(); + + const btcTx = psbt.extractTransaction(); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); + + console.log('BTC TxId: ', btcTxId); + + await btcService.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); + + return btcTxId; +}; diff --git a/examples/rgbpp/spore/4-transfer-spore.ts b/examples/rgbpp/spore/4-transfer-spore.ts index 2976456b..2b6cc2c2 100644 --- a/examples/rgbpp/spore/4-transfer-spore.ts +++ b/examples/rgbpp/spore/4-transfer-spore.ts @@ -1,54 +1,9 @@ -import { buildRgbppLockArgs, getSporeTypeScript, Hex, genTransferSporeCkbVirtualTx } from '@rgbpp-sdk/ckb'; -import { sendRgbppUtxos } from '@rgbpp-sdk/btc'; -import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from 'examples-core'; - -const transferSpore = async ({ - sporeRgbppLockArgs, - toBtcAddress, - sporeTypeArgs, -}: { - sporeRgbppLockArgs: Hex; - toBtcAddress: string; - sporeTypeArgs: Hex; -}) => { - // The spore type script is from 3-create-spore.ts, you can find it from the ckb tx spore output cell - const sporeTypeBytes = serializeScript({ - ...getSporeTypeScript(isMainnet), - args: sporeTypeArgs, - }); - - const ckbVirtualTxResult = await genTransferSporeCkbVirtualTx({ - collector, - sporeRgbppLockArgs, - sporeTypeBytes, - isMainnet, - }); - - const { commitment, ckbRawTx } = ckbVirtualTxResult; - - // console.log(JSON.stringify(ckbRawTx)) - - // Send BTC tx - const psbt = await sendRgbppUtxos({ - ckbVirtualTx: ckbRawTx, - commitment, - tos: [toBtcAddress], - ckbCollector: collector, - from: btcAddress!, - source: btcDataSource, - feeRate: 30, - }); - psbt.signAllInputs(btcKeyPair); - psbt.finalizeAllInputs(); - - const btcTx = psbt.extractTransaction(); - const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); - - console.log('BTC TxId: ', btcTxId); +import { buildRgbppLockArgs } from '@rgbpp-sdk/ckb'; +import { SporeTransferParams, transferSporeOnBtc, btcService } from 'examples-core'; +const transferSpore = async (params: SporeTransferParams) => { + const btcTxId = await transferSporeOnBtc(params); try { - await btcService.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); const interval = setInterval(async () => { const { state, failedReason } = await btcService.getRgbppTransactionState(btcTxId); console.log('state', state); diff --git a/examples/rgbpp/spore/5-leap-spore-to-ckb.ts b/examples/rgbpp/spore/5-leap-spore-to-ckb.ts index 909076a5..10239eaf 100644 --- a/examples/rgbpp/spore/5-leap-spore-to-ckb.ts +++ b/examples/rgbpp/spore/5-leap-spore-to-ckb.ts @@ -1,55 +1,9 @@ -import { buildRgbppLockArgs, getSporeTypeScript, Hex, genLeapSporeFromBtcToCkbVirtualTx } from '@rgbpp-sdk/ckb'; -import { sendRgbppUtxos } from '@rgbpp-sdk/btc'; -import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from 'examples-core'; - -const transferSpore = async ({ - sporeRgbppLockArgs, - toCkbAddress, - sporeTypeArgs, -}: { - sporeRgbppLockArgs: Hex; - toCkbAddress: string; - sporeTypeArgs: Hex; -}) => { - // The spore type script is from 3-create-spore.ts, you can find it from the ckb tx spore output cells - const sporeTypeBytes = serializeScript({ - ...getSporeTypeScript(isMainnet), - args: sporeTypeArgs, - }); - - const ckbVirtualTxResult = await genLeapSporeFromBtcToCkbVirtualTx({ - collector, - sporeRgbppLockArgs, - sporeTypeBytes, - toCkbAddress, - isMainnet, - }); - - const { commitment, ckbRawTx } = ckbVirtualTxResult; - - // console.log(JSON.stringify(ckbRawTx)) - - // Send BTC tx - const psbt = await sendRgbppUtxos({ - ckbVirtualTx: ckbRawTx, - commitment, - tos: [btcAddress!], - ckbCollector: collector, - from: btcAddress!, - source: btcDataSource, - feeRate: 30, - }); - psbt.signAllInputs(btcKeyPair); - psbt.finalizeAllInputs(); - - const btcTx = psbt.extractTransaction(); - const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); - - console.log('BTC TxId: ', btcTxId); +import { buildRgbppLockArgs } from '@rgbpp-sdk/ckb'; +import { leapSporeToCkb, btcService, SporeLeapParams } from 'examples-core'; +const leapSpore = async (params: SporeLeapParams) => { + const btcTxId = await leapSporeToCkb(params); try { - await btcService.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); const interval = setInterval(async () => { const { state, failedReason } = await btcService.getRgbppTransactionState(btcTxId); console.log('state', state); @@ -70,7 +24,7 @@ const transferSpore = async ({ // Use your real BTC UTXO information on the BTC Testnet // rgbppLockArgs: outIndexU32 + btcTxId -transferSpore({ +leapSpore({ // The spore rgbpp lock args is from 3-create-spore.ts sporeRgbppLockArgs: buildRgbppLockArgs(3, 'd8a31796fbd42c546f6b22014b9b82b16586ce1df81b0e7ca9a552cdc492a0af'), toCkbAddress: 'ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq0e4xk4rmg5jdkn8aams492a7jlg73ue0gc0ddfj', diff --git a/examples/rgbpp/spore/0-cluster-info.ts b/examples/rgbpp/spore/launch/0-cluster-info.ts similarity index 100% rename from examples/rgbpp/spore/0-cluster-info.ts rename to examples/rgbpp/spore/launch/0-cluster-info.ts diff --git a/examples/rgbpp/spore/1-prepare-cluster.ts b/examples/rgbpp/spore/launch/1-prepare-cluster.ts similarity index 100% rename from examples/rgbpp/spore/1-prepare-cluster.ts rename to examples/rgbpp/spore/launch/1-prepare-cluster.ts diff --git a/examples/rgbpp/spore/2-create-cluster.ts b/examples/rgbpp/spore/launch/2-create-cluster.ts similarity index 100% rename from examples/rgbpp/spore/2-create-cluster.ts rename to examples/rgbpp/spore/launch/2-create-cluster.ts diff --git a/examples/rgbpp/spore/3-create-spores.ts b/examples/rgbpp/spore/launch/3-create-spores.ts similarity index 100% rename from examples/rgbpp/spore/3-create-spores.ts rename to examples/rgbpp/spore/launch/3-create-spores.ts diff --git a/examples/rgbpp/tsconfig.json b/examples/rgbpp/tsconfig.json index 0f0b1f2b..a610e3f5 100644 --- a/examples/rgbpp/tsconfig.json +++ b/examples/rgbpp/tsconfig.json @@ -21,6 +21,6 @@ "skipLibCheck": true, "strict": true }, - "include": ["queue/**/*.ts", "xudt/**/*.ts", "core/*.ts"], + "include": ["queue/**/*.ts", "xudt/**/*.ts"], "exclude": ["node_modules"] } diff --git a/examples/rgbpp/xudt/1-ckb-jump-btc.ts b/examples/rgbpp/xudt/1-ckb-leap-btc.ts similarity index 100% rename from examples/rgbpp/xudt/1-ckb-jump-btc.ts rename to examples/rgbpp/xudt/1-ckb-leap-btc.ts diff --git a/examples/rgbpp/xudt/3-btc-jump-ckb.ts b/examples/rgbpp/xudt/3-btc-leap-ckb.ts similarity index 100% rename from examples/rgbpp/xudt/3-btc-jump-ckb.ts rename to examples/rgbpp/xudt/3-btc-leap-ckb.ts diff --git a/examples/rgbpp/xudt/local/4-spend-btc-time-cell.ts b/examples/rgbpp/xudt/4-unlock-btc-time-cell.ts similarity index 93% rename from examples/rgbpp/xudt/local/4-spend-btc-time-cell.ts rename to examples/rgbpp/xudt/4-unlock-btc-time-cell.ts index 242f3a74..5220339f 100644 --- a/examples/rgbpp/xudt/local/4-spend-btc-time-cell.ts +++ b/examples/rgbpp/xudt/4-unlock-btc-time-cell.ts @@ -2,7 +2,7 @@ import { sendCkbTx, buildBtcTimeCellsSpentTx, getBtcTimeLockScript, signBtcTimeC import { CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from 'examples-core'; // Warning: Wait at least 6 BTC confirmation blocks to spend the BTC time cells after 4-btc-jump-ckb.ts -const spendBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: string }) => { +const unlockBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: string }) => { const btcTimeCells = await collector.getCells({ lock: { ...getBtcTimeLockScript(false), @@ -36,7 +36,7 @@ const spendBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: string } }; // The btcTimeCellArgs is from the outputs[0].lock.args(BTC Time lock args) of the 4-btc-jump-ckb.ts CKB transaction -spendBtcTimeCell({ +unlockBtcTimeCell({ btcTimeCellArgs: '0x7f000000100000005b0000005f0000004b000000100000003000000031000000d23761b364210735c19c60561d213fb3beae2fd6172743719eff6920e020baac011600000000016c61f984f12d3c8a4f649e60acda5deda0b8837c060000001c95b9d726e4ab337d6a4572680598947954d7b6ff4f1e767e605eeeec49e7ed', }); diff --git a/examples/rgbpp/xudt/local/1-ckb-jump-btc.ts b/examples/rgbpp/xudt/local/1-ckb-jump-btc.ts deleted file mode 100644 index a80e86b9..00000000 --- a/examples/rgbpp/xudt/local/1-ckb-jump-btc.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { genCkbJumpBtcVirtualTx, getSecp256k1CellDep, buildRgbppLockArgs, getXudtTypeScript } from '@rgbpp-sdk/ckb'; -import { isMainnet, collector, ckbAddress, LeapToBtcParams } from 'examples-core'; - -// CKB SECP256K1 private key -const CKB_TEST_PRIVATE_KEY = '0x0000000000000000000000000000000000000000000000000000000000000001'; - -const leapToBtc = async ({ outIndex, btcTxId, xudtTypeArgs, transferAmount }: LeapToBtcParams) => { - const toRgbppLockArgs = buildRgbppLockArgs(outIndex, btcTxId); - - // Warning: Please replace with your real xUDT type script here - const xudtType: CKBComponents.Script = { - ...getXudtTypeScript(isMainnet), - args: xudtTypeArgs, - }; - - const ckbRawTx = await genCkbJumpBtcVirtualTx({ - collector, - fromCkbAddress: ckbAddress, - toRgbppLockArgs, - xudtTypeBytes: serializeScript(xudtType), - transferAmount, - }); - - const emptyWitness = { lock: '', inputType: '', outputType: '' }; - const unsignedTx: CKBComponents.RawTransactionToSign = { - ...ckbRawTx, - cellDeps: [...ckbRawTx.cellDeps, getSecp256k1CellDep(isMainnet)], - witnesses: [emptyWitness, ...ckbRawTx.witnesses.slice(1)], - }; - - const signedTx = collector.getCkb().signTransaction(CKB_TEST_PRIVATE_KEY)(unsignedTx); - - const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); - console.info(`Rgbpp asset has been jumped from CKB to BTC and tx hash is ${txHash}`); -}; - -// Use your real BTC UTXO information on the BTC Testnet -leapToBtc({ - outIndex: 1, - btcTxId: '4ff1855b64b309afa19a8b9be3d4da99dcb18b083b65d2d851662995c7d99e7a', - xudtTypeArgs: '0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b', - transferAmount: BigInt(800_0000_0000), -}); diff --git a/examples/rgbpp/xudt/local/3-btc-jump-ckb.ts b/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts similarity index 97% rename from examples/rgbpp/xudt/local/3-btc-jump-ckb.ts rename to examples/rgbpp/xudt/local/3-btc-leap-ckb.ts index 8dc2040a..f88048d6 100644 --- a/examples/rgbpp/xudt/local/3-btc-jump-ckb.ts +++ b/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts @@ -19,7 +19,7 @@ import { btcService, } from 'examples-core'; -const jumpFromBtcToCkb = async ({ rgbppLockArgsList, toCkbAddress, xudtTypeArgs, transferAmount }: LeapToCkbParams) => { +const leapFromBtcToCkb = async ({ rgbppLockArgsList, toCkbAddress, xudtTypeArgs, transferAmount }: LeapToCkbParams) => { const xudtType: CKBComponents.Script = { ...getXudtTypeScript(isMainnet), args: xudtTypeArgs, @@ -82,7 +82,7 @@ const jumpFromBtcToCkb = async ({ rgbppLockArgsList, toCkbAddress, xudtTypeArgs, }; // rgbppLockArgs: outIndexU32 + btcTxId -jumpFromBtcToCkb({ +leapFromBtcToCkb({ rgbppLockArgsList: [buildRgbppLockArgs(1, '24e622419156dd3a277a90bcbb40c7117462a18d5329dd1ada320ca8bdfba715')], toCkbAddress: 'ckt1qrfrwcdnvssswdwpn3s9v8fp87emat306ctjwsm3nmlkjg8qyza2cqgqq9kxr7vy7yknezj0vj0xptx6thk6pwyr0sxamv6q', xudtTypeArgs: '0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b', From 03fafb25b88bda2cd1bcee2ba43022013762a163 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Wed, 8 May 2024 23:31:19 +0800 Subject: [PATCH 30/78] refactor: Update examples packages --- examples/core/README.md | 130 ------------------ examples/core/package.json | 29 ---- examples/core/src/index.ts | 3 - examples/core/tsconfig.json | 27 ---- examples/{core => rgbpp}/.env.example | 0 .../src/utils/index.ts => rgbpp/core/env.ts} | 5 + .../{core/src/rgbpp => rgbpp/core}/index.ts | 3 +- .../{core/src/rgbpp => rgbpp/core}/spore.ts | 2 +- .../{core/src/rgbpp => rgbpp/core}/xudt.ts | 2 +- examples/rgbpp/package.json | 7 +- examples/rgbpp/spore/4-transfer-spore.ts | 2 +- examples/rgbpp/spore/5-leap-spore-to-ckb.ts | 2 +- .../rgbpp/spore/6-unlock-btc-time-cell.ts | 2 +- examples/rgbpp/spore/7-leap-spore-to-btc.ts | 2 +- .../rgbpp/spore/launch/1-prepare-cluster.ts | 2 +- .../rgbpp/spore/launch/2-create-cluster.ts | 2 +- .../rgbpp/spore/launch/3-create-spores.ts | 2 +- examples/{core => rgbpp}/tsconfig.build.json | 2 +- examples/rgbpp/xudt/1-ckb-leap-btc.ts | 2 +- examples/rgbpp/xudt/2-btc-transfer.ts | 2 +- examples/rgbpp/xudt/3-btc-leap-ckb.ts | 2 +- examples/rgbpp/xudt/4-unlock-btc-time-cell.ts | 2 +- .../rgbpp/xudt/launch/1-prepare-launch.ts | 2 +- examples/rgbpp/xudt/launch/2-launch-rgbpp.ts | 2 +- .../rgbpp/xudt/launch/3-distribute-rgbpp.ts | 2 +- examples/rgbpp/xudt/local/2-btc-transfer.ts | 2 +- examples/rgbpp/xudt/local/3-btc-leap-ckb.ts | 10 +- examples/xudt/.env.example | 29 ++++ examples/xudt/1-issue-xudt.ts | 2 +- examples/xudt/2-transfer-xudt.ts | 2 +- examples/xudt/core/env.ts | 18 +++ .../ckb-xudt/index.ts => xudt/core/xudt.ts} | 2 +- examples/xudt/package.json | 9 +- examples/xudt/tsconfig.build.json | 10 ++ pnpm-lock.yaml | 65 ++++----- 35 files changed, 125 insertions(+), 262 deletions(-) delete mode 100644 examples/core/README.md delete mode 100644 examples/core/package.json delete mode 100644 examples/core/src/index.ts delete mode 100644 examples/core/tsconfig.json rename examples/{core => rgbpp}/.env.example (100%) rename examples/{core/src/utils/index.ts => rgbpp/core/env.ts} (92%) rename examples/{core/src/rgbpp => rgbpp/core}/index.ts (68%) rename examples/{core/src/rgbpp => rgbpp/core}/spore.ts (98%) rename examples/{core/src/rgbpp => rgbpp/core}/xudt.ts (99%) rename examples/{core => rgbpp}/tsconfig.build.json (78%) create mode 100644 examples/xudt/.env.example create mode 100644 examples/xudt/core/env.ts rename examples/{core/src/ckb-xudt/index.ts => xudt/core/xudt.ts} (99%) create mode 100644 examples/xudt/tsconfig.build.json diff --git a/examples/core/README.md b/examples/core/README.md deleted file mode 100644 index 5f90be8a..00000000 --- a/examples/core/README.md +++ /dev/null @@ -1,130 +0,0 @@ -# RGB++ Examples - -**All examples are just to demonstrate the use of RGB++ SDK.** - -- Local and Queue directories: The examples for RGB++ UDT issuance, transfer, and leap -- Spore directory: The examples for RGB++ spore creation, transfer and leap - -## What you must know about BTC transaction id - -**The BTC transaction id(hash) displayed on BTC explorer is different from the BTC transaction id(hash) in RGB++ lock args. They are in reverse byte order.** - -We follow the following two rules: - -- Whenever you're working with transaction/block hashes **internally** (e.g. inside raw bitcoin data), you use the **natural** byte order. -- Whenever you're **displaying or searching** for transaction/block hashes, you use the **reverse** byte order. - -For detailed rules, please refer to [Byte Order](https://learnmeabitcoin.com/technical/general/byte-order/) - -For example, the BTC transaction id(hash) of the RGB++ lock args like this: - -``` -4abc778213bc4da692f93745c2b07410ef2bfaee70417784d4ee8969fb258001 -``` - -But when you're searching for this transaction in [Bitcoin Core](https://bitcoin.org/en/bitcoin-core/) or on a block explorer, you'll see this byte order: - -``` -018025fb6989eed484774170eefa2bef1074b0c24537f992a64dbc138277bc4a -``` - -## RGB++ xUDT Examples with Queue service(Recommended) - -### Leap xUDT from CKB to BTC - -```shell -npx ts-node examples/rgbpp/queue/1-ckb-jump-btc.ts -``` - -### Transfer RGB++ xUDT on BTC - -```shell -npx ts-node examples/rgbpp/queue/2-btc-transfer.ts -``` - -### Leap RGB++ xUDT from BTC to CKB - -```shell -npx ts-node examples/rgbpp/queue/3-btc-jump-ckb.ts -``` - -### Unlock xUDT BTC time cells on CKB - -A cron job in RGB++ Queue service will construct a transaction unlocking the mature BTC time cells to the their `target_ckb_address`. - - -## RGB++ xUDT Local Examples - -### Leap RGB++ xUDT from CKB to BTC - -```shell -npx ts-node examples/rgbpp/local/1-ckb-jump-btc.ts -``` - -### Transfer RGB++ xUDT on BTC - -```shell -npx ts-node examples/rgbpp/local/2-btc-transfer.ts -``` - -### Leap RGB++ xUDT from BTC to CKB - -```shell -npx ts-node examples/rgbpp/local/3-btc-jump-ckb.ts -``` - -### Unlock xUDT BTC time cells on CKB - -**Warning: Wait at least 6 BTC confirmation blocks to unlock the BTC time cells after 4-btc-jump-ckb.ts** - -```shell -npx ts-node examples/rgbpp/local/4-spend-btc-time-cell.ts -``` - -## RGB++ Spore Examples - -**You can use RGB++ Queue service to complete spore transfer and leap, and the examples can be found in `examples/rgbpp/spore/queue`** - -### Create RGB++ Cluster Cell - -```shell -npx ts-node examples/rgbpp/spore/1-prepare-cluster.ts - -npx ts-node examples/rgbpp/spore/2-create-cluster.ts -``` - -### Create RGB++ Spores with Cluster on BTC - -```shell -npx ts-node examples/rgbpp/spore/3-create-spores.ts -``` - -### Transfer RGB++ Spore on BTC - -```shell -npx ts-node examples/rgbpp/spore/4-transfer-spore.ts -``` - -### Leap RGB++ Spore from BTC to CKB - -```shell -npx ts-node examples/rgbpp/spore/5-leap-spore-to-ckb.ts -``` - -### Unlock Spore BTC time cells on CKB - -A cron job in RGB++ Queue service will construct a transaction unlocking the mature BTC time cells to the their `target_ckb_address`. - -However, you can still manually unlock the spore btc time cell through the following command - -**Warning: Wait at least 6 BTC confirmation blocks to unlock the BTC time cells after 5-leap-spore-to-ckb.ts** - -```shell -npx ts-node examples/rgbpp/spore/6-unlock-btc-time-cell.ts -``` - -### Leap Spore from CKB to BTC - -```shell -npx ts-node examples/rgbpp/spore/7-leap-spore-to-btc.ts -``` \ No newline at end of file diff --git a/examples/core/package.json b/examples/core/package.json deleted file mode 100644 index 35f4384a..00000000 --- a/examples/core/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "examples-core", - "version": "0.1.0", - "description": "The core methods and utils of RGB++ and xUDT", - "scripts": { - "build": "tsc -p tsconfig.build.json", - "format": "prettier --write '**/*.ts'", - "lint": "tsc && eslint . && prettier --check '**/*.ts'", - "lint:fix": "tsc && eslint --fix --ext .ts . && prettier --write '**/*.ts'" - }, - "main": "lib", - "files": [ - "lib" - ], - "types": "./lib/index.d.ts", - "dependencies": { - "@exact-realty/multipart-parser": "^1.0.13", - "@nervosnetwork/ckb-sdk-utils": "^0.109.1", - "@rgbpp-sdk/btc": "workspace:^", - "@rgbpp-sdk/ckb": "workspace:^", - "@rgbpp-sdk/service": "workspace:^", - "@spore-sdk/core": "^0.2.0-beta.6", - "axios": "^1.6.8" - }, - "devDependencies": { - "@types/node": "^20.11.28", - "typescript": "^5.4.2" - } -} diff --git a/examples/core/src/index.ts b/examples/core/src/index.ts deleted file mode 100644 index cc87c10b..00000000 --- a/examples/core/src/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './rgbpp'; -export * from './ckb-xudt'; -export * from './utils'; diff --git a/examples/core/tsconfig.json b/examples/core/tsconfig.json deleted file mode 100644 index 671aefb7..00000000 --- a/examples/core/tsconfig.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "compilerOptions": { - "target": "ES2015", - "lib": ["dom", "dom.iterable", "esnext"], - "module": "ES2020", - "outDir": "./lib", - "composite": false, - "resolveJsonModule": true, - "strictNullChecks": true, - "noEmit": true, - "declaration": true, - "declarationMap": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "inlineSources": false, - "isolatedModules": true, - "moduleResolution": "node", - "noUnusedLocals": false, - "noUnusedParameters": false, - "preserveWatchOutput": true, - "skipLibCheck": true, - "strict": true - }, - "include": ["src/**/*.ts"], - "exclude": ["node_modules", "lib"] -} diff --git a/examples/core/.env.example b/examples/rgbpp/.env.example similarity index 100% rename from examples/core/.env.example rename to examples/rgbpp/.env.example diff --git a/examples/core/src/utils/index.ts b/examples/rgbpp/core/env.ts similarity index 92% rename from examples/core/src/utils/index.ts rename to examples/rgbpp/core/env.ts index d969214b..b30b593d 100644 --- a/examples/core/src/utils/index.ts +++ b/examples/rgbpp/core/env.ts @@ -2,9 +2,14 @@ import { AddressPrefix, privateKeyToAddress } from '@nervosnetwork/ckb-sdk-utils import { DataSource, ECPair, ECPairInterface, NetworkType, bitcoin } from '@rgbpp-sdk/btc'; import { Collector } from '@rgbpp-sdk/ckb'; import { BtcAssetsApi } from '@rgbpp-sdk/service'; +import dotenv from 'dotenv'; + +dotenv.config({ path: __dirname + '/../.env' }); export const isMainnet = process.env.IS_MAINNET === 'true' ? true : false; +console.log('IS_MAINNET', process.env.IS_MAINNET); + export const collector = new Collector({ ckbNodeUrl: process.env.CKB_NODE_URL!, ckbIndexerUrl: process.env.CKB_INDEXER_URL!, diff --git a/examples/core/src/rgbpp/index.ts b/examples/rgbpp/core/index.ts similarity index 68% rename from examples/core/src/rgbpp/index.ts rename to examples/rgbpp/core/index.ts index 03e3f45e..89e6a8c2 100644 --- a/examples/core/src/rgbpp/index.ts +++ b/examples/rgbpp/core/index.ts @@ -1,2 +1,3 @@ -export * from './xudt'; export * from './spore'; +export * from './xudt'; +export * from './env'; diff --git a/examples/core/src/rgbpp/spore.ts b/examples/rgbpp/core/spore.ts similarity index 98% rename from examples/core/src/rgbpp/spore.ts rename to examples/rgbpp/core/spore.ts index 095deffe..78807727 100644 --- a/examples/core/src/rgbpp/spore.ts +++ b/examples/rgbpp/core/spore.ts @@ -6,7 +6,7 @@ import { } from '@rgbpp-sdk/ckb'; import { sendRgbppUtxos } from '@rgbpp-sdk/btc'; import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../utils'; +import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from './env'; export interface SporeTransferParams { sporeRgbppLockArgs: Hex; diff --git a/examples/core/src/rgbpp/xudt.ts b/examples/rgbpp/core/xudt.ts similarity index 99% rename from examples/core/src/rgbpp/xudt.ts rename to examples/rgbpp/core/xudt.ts index 3f518447..7a13ddd7 100644 --- a/examples/core/src/rgbpp/xudt.ts +++ b/examples/rgbpp/core/xudt.ts @@ -16,7 +16,7 @@ import { btcKeyPair, btcService, btcDataSource, -} from '../utils'; +} from './env'; import { sendRgbppUtxos } from '@rgbpp-sdk/btc'; export interface LeapToBtcParams { diff --git a/examples/rgbpp/package.json b/examples/rgbpp/package.json index e5f88eb3..fa820dff 100644 --- a/examples/rgbpp/package.json +++ b/examples/rgbpp/package.json @@ -15,11 +15,12 @@ "@rgbpp-sdk/btc": "workspace:^", "@rgbpp-sdk/ckb": "workspace:^", "@rgbpp-sdk/service": "workspace:^", - "@spore-sdk/core": "^0.2.0-beta.6", - "examples-core": "workspace:^" + "@spore-sdk/core": "^0.2.0-beta.6" }, "devDependencies": { "@types/node": "^20.11.28", - "typescript": "^5.4.2" + "typescript": "^5.4.2", + "dotenv": "^16.4.5", + "@types/dotenv": "^8.2.0" } } diff --git a/examples/rgbpp/spore/4-transfer-spore.ts b/examples/rgbpp/spore/4-transfer-spore.ts index 2b6cc2c2..ba7f1092 100644 --- a/examples/rgbpp/spore/4-transfer-spore.ts +++ b/examples/rgbpp/spore/4-transfer-spore.ts @@ -1,5 +1,5 @@ import { buildRgbppLockArgs } from '@rgbpp-sdk/ckb'; -import { SporeTransferParams, transferSporeOnBtc, btcService } from 'examples-core'; +import { SporeTransferParams, transferSporeOnBtc, btcService } from '../core'; const transferSpore = async (params: SporeTransferParams) => { const btcTxId = await transferSporeOnBtc(params); diff --git a/examples/rgbpp/spore/5-leap-spore-to-ckb.ts b/examples/rgbpp/spore/5-leap-spore-to-ckb.ts index 10239eaf..8481900e 100644 --- a/examples/rgbpp/spore/5-leap-spore-to-ckb.ts +++ b/examples/rgbpp/spore/5-leap-spore-to-ckb.ts @@ -1,5 +1,5 @@ import { buildRgbppLockArgs } from '@rgbpp-sdk/ckb'; -import { leapSporeToCkb, btcService, SporeLeapParams } from 'examples-core'; +import { leapSporeToCkb, btcService, SporeLeapParams } from '../core'; const leapSpore = async (params: SporeLeapParams) => { const btcTxId = await leapSporeToCkb(params); diff --git a/examples/rgbpp/spore/6-unlock-btc-time-cell.ts b/examples/rgbpp/spore/6-unlock-btc-time-cell.ts index c610600f..75d5f32f 100644 --- a/examples/rgbpp/spore/6-unlock-btc-time-cell.ts +++ b/examples/rgbpp/spore/6-unlock-btc-time-cell.ts @@ -1,5 +1,5 @@ import { sendCkbTx, getBtcTimeLockScript, buildSporeBtcTimeCellsSpentTx, signBtcTimeCellSpentTx } from '@rgbpp-sdk/ckb'; -import { CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from 'examples-core'; +import { CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from '../core'; // Warning: Wait at least 6 BTC confirmation blocks to spend the BTC time cells after 4-btc-jump-ckb.ts const unlockSporeBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: string }) => { diff --git a/examples/rgbpp/spore/7-leap-spore-to-btc.ts b/examples/rgbpp/spore/7-leap-spore-to-btc.ts index 77d3d081..443bfcca 100644 --- a/examples/rgbpp/spore/7-leap-spore-to-btc.ts +++ b/examples/rgbpp/spore/7-leap-spore-to-btc.ts @@ -5,7 +5,7 @@ import { getSporeTypeScript, genLeapSporeFromCkbToBtcRawTx, } from '@rgbpp-sdk/ckb'; -import { isMainnet, collector, ckbAddress, CKB_PRIVATE_KEY } from 'examples-core'; +import { isMainnet, collector, ckbAddress, CKB_PRIVATE_KEY } from '../core'; const leapSporeFromCkbToBtc = async ({ outIndex, diff --git a/examples/rgbpp/spore/launch/1-prepare-cluster.ts b/examples/rgbpp/spore/launch/1-prepare-cluster.ts index ef80fc3c..fcd37d3c 100644 --- a/examples/rgbpp/spore/launch/1-prepare-cluster.ts +++ b/examples/rgbpp/spore/launch/1-prepare-cluster.ts @@ -10,7 +10,7 @@ import { genRgbppLockScript, getSecp256k1CellDep, } from '@rgbpp-sdk/ckb'; -import { ckbAddress, isMainnet, collector, CKB_PRIVATE_KEY } from 'examples-core'; +import { ckbAddress, isMainnet, collector, CKB_PRIVATE_KEY } from '../../core'; import { CLUSTER_DATA } from './0-cluster-info'; const prepareClusterCell = async ({ outIndex, btcTxId }: { outIndex: number; btcTxId: string }) => { diff --git a/examples/rgbpp/spore/launch/2-create-cluster.ts b/examples/rgbpp/spore/launch/2-create-cluster.ts index e824bf33..e8824147 100644 --- a/examples/rgbpp/spore/launch/2-create-cluster.ts +++ b/examples/rgbpp/spore/launch/2-create-cluster.ts @@ -8,7 +8,7 @@ import { } from '@rgbpp-sdk/ckb'; import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; import { BtcAssetsApiError } from '@rgbpp-sdk/service'; -import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from 'examples-core'; +import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../core'; import { CLUSTER_DATA } from './0-cluster-info'; const createCluster = async ({ ownerRgbppLockArgs }: { ownerRgbppLockArgs: string }) => { diff --git a/examples/rgbpp/spore/launch/3-create-spores.ts b/examples/rgbpp/spore/launch/3-create-spores.ts index 50e1f61a..529e49ba 100644 --- a/examples/rgbpp/spore/launch/3-create-spores.ts +++ b/examples/rgbpp/spore/launch/3-create-spores.ts @@ -20,7 +20,7 @@ import { btcService, CKB_PRIVATE_KEY, ckbAddress, -} from 'examples-core'; +} from '../../core'; interface Params { clusterRgbppLockArgs: Hex; diff --git a/examples/core/tsconfig.build.json b/examples/rgbpp/tsconfig.build.json similarity index 78% rename from examples/core/tsconfig.build.json rename to examples/rgbpp/tsconfig.build.json index c5b3d86f..18f21a86 100644 --- a/examples/core/tsconfig.build.json +++ b/examples/rgbpp/tsconfig.build.json @@ -6,5 +6,5 @@ "outDir": "lib", "noEmit": false }, - "include": ["src/**/*.ts", "src/*.ts"], + "include": ["core/*.ts"], } diff --git a/examples/rgbpp/xudt/1-ckb-leap-btc.ts b/examples/rgbpp/xudt/1-ckb-leap-btc.ts index 05a626d4..ce7ab8df 100644 --- a/examples/rgbpp/xudt/1-ckb-leap-btc.ts +++ b/examples/rgbpp/xudt/1-ckb-leap-btc.ts @@ -1,4 +1,4 @@ -import { leapFromCkbToBtc } from 'examples-core'; +import { leapFromCkbToBtc } from '../core'; // Use your real BTC UTXO information on the BTC Testnet leapFromCkbToBtc({ diff --git a/examples/rgbpp/xudt/2-btc-transfer.ts b/examples/rgbpp/xudt/2-btc-transfer.ts index 52f1e591..321ccb37 100644 --- a/examples/rgbpp/xudt/2-btc-transfer.ts +++ b/examples/rgbpp/xudt/2-btc-transfer.ts @@ -1,5 +1,5 @@ import { buildRgbppLockArgs } from '@rgbpp-sdk/ckb'; -import { RgbppTransferParams, btcService, transferRgbppOnBtc } from 'examples-core'; +import { RgbppTransferParams, btcService, transferRgbppOnBtc } from '../core'; const transfer = async (params: RgbppTransferParams) => { const btcTxId = await transferRgbppOnBtc(params); diff --git a/examples/rgbpp/xudt/3-btc-leap-ckb.ts b/examples/rgbpp/xudt/3-btc-leap-ckb.ts index cbb917f2..cb70f748 100644 --- a/examples/rgbpp/xudt/3-btc-leap-ckb.ts +++ b/examples/rgbpp/xudt/3-btc-leap-ckb.ts @@ -1,5 +1,5 @@ import { buildRgbppLockArgs } from '@rgbpp-sdk/ckb'; -import { LeapToCkbParams, btcService, leapFromBtcToCkb } from 'examples-core'; +import { LeapToCkbParams, btcService, leapFromBtcToCkb } from '../core'; const leapToCKB = async (params: LeapToCkbParams) => { const btcTxId = await leapFromBtcToCkb(params); diff --git a/examples/rgbpp/xudt/4-unlock-btc-time-cell.ts b/examples/rgbpp/xudt/4-unlock-btc-time-cell.ts index 5220339f..c9a78f68 100644 --- a/examples/rgbpp/xudt/4-unlock-btc-time-cell.ts +++ b/examples/rgbpp/xudt/4-unlock-btc-time-cell.ts @@ -1,5 +1,5 @@ import { sendCkbTx, buildBtcTimeCellsSpentTx, getBtcTimeLockScript, signBtcTimeCellSpentTx } from '@rgbpp-sdk/ckb'; -import { CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from 'examples-core'; +import { CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from '../core'; // Warning: Wait at least 6 BTC confirmation blocks to spend the BTC time cells after 4-btc-jump-ckb.ts const unlockBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: string }) => { diff --git a/examples/rgbpp/xudt/launch/1-prepare-launch.ts b/examples/rgbpp/xudt/launch/1-prepare-launch.ts index a5910b38..b11a8a3f 100644 --- a/examples/rgbpp/xudt/launch/1-prepare-launch.ts +++ b/examples/rgbpp/xudt/launch/1-prepare-launch.ts @@ -13,7 +13,7 @@ import { getSecp256k1CellDep, } from '@rgbpp-sdk/ckb'; import { RGBPP_TOKEN_INFO } from './0-rgbpp-token-info'; -import { CKB_PRIVATE_KEY, ckbAddress, collector, isMainnet } from 'examples-core'; +import { CKB_PRIVATE_KEY, ckbAddress, collector, isMainnet } from '../../core'; const prepareLaunchCell = async ({ outIndex, diff --git a/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts b/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts index cdba02b6..1747c5aa 100644 --- a/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts +++ b/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts @@ -9,7 +9,7 @@ import { import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; import { BtcAssetsApiError } from '@rgbpp-sdk/service'; import { RGBPP_TOKEN_INFO } from './0-rgbpp-token-info'; -import { btcAddress, btcDataSource, btcKeyPair, btcService, collector, isMainnet } from 'examples-core'; +import { btcAddress, btcDataSource, btcKeyPair, btcService, collector, isMainnet } from '../../core'; interface Params { ownerRgbppLockArgs: string; diff --git a/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts b/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts index d114ccd9..ba7af483 100644 --- a/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts +++ b/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts @@ -21,7 +21,7 @@ import { btcService, CKB_PRIVATE_KEY, ckbAddress, -} from 'examples-core'; +} from '../../core'; interface Params { rgbppLockArgsList: string[]; diff --git a/examples/rgbpp/xudt/local/2-btc-transfer.ts b/examples/rgbpp/xudt/local/2-btc-transfer.ts index 67a426e6..c7f492f5 100644 --- a/examples/rgbpp/xudt/local/2-btc-transfer.ts +++ b/examples/rgbpp/xudt/local/2-btc-transfer.ts @@ -17,7 +17,7 @@ import { btcDataSource, btcKeyPair, btcService, -} from 'examples-core'; +} from '../../core'; const transfer = async ({ rgbppLockArgsList, toBtcAddress, xudtTypeArgs, transferAmount }: RgbppTransferParams) => { const xudtType: CKBComponents.Script = { diff --git a/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts b/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts index f88048d6..43356b77 100644 --- a/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts +++ b/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts @@ -9,15 +9,7 @@ import { } from '@rgbpp-sdk/ckb'; import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; import { BtcAssetsApiError } from '@rgbpp-sdk/service'; -import { - LeapToCkbParams, - isMainnet, - collector, - btcAddress, - btcDataSource, - btcKeyPair, - btcService, -} from 'examples-core'; +import { LeapToCkbParams, isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../core'; const leapFromBtcToCkb = async ({ rgbppLockArgsList, toCkbAddress, xudtTypeArgs, transferAmount }: LeapToCkbParams) => { const xudtType: CKBComponents.Script = { diff --git a/examples/xudt/.env.example b/examples/xudt/.env.example new file mode 100644 index 00000000..fda5ec43 --- /dev/null +++ b/examples/xudt/.env.example @@ -0,0 +1,29 @@ +# Ture for CKB and BTC Mainnet and false for CKB and BTC Testnet, the default value is false +IS_MAINNET='false' + + +# CKB Variables + +# The CKB secp256k1 private key whose format is 32bytes hex string with 0x prefix +CKB_SECP256K1_PRIVATE_KEY='0x-private-key' + +# CKB node url which should be matched with IS_MAINNET +CKB_NODE_URL='https://testnet.ckb.dev/rpc' + +# CKB indexer url which should be matched with IS_MAINNET +CKB_INDEXER_URL='https://testnet.ckb.dev/indexer' + + +# BTC Variables + +# The BTC private key whose format is 32bytes hex string without 0x prefix +BTC_PRIVATE_KEY='private-key' + +# The BTC assets api url which should be matched with IS_MAINNET +BTC_ASSETS_API_URL='https://btc-assets-api.testnet.mibao.pro'; + +# The BTC assets api token which should be matched with IS_MAINNET +BTC_ASSETS_TOKEN=''; + +# The BTC assets api origin which should be matched with IS_MAINNET +BTC_ASSETS_ORIGIN='https://btc-test.app'; \ No newline at end of file diff --git a/examples/xudt/1-issue-xudt.ts b/examples/xudt/1-issue-xudt.ts index d4a16f78..eb7cebeb 100644 --- a/examples/xudt/1-issue-xudt.ts +++ b/examples/xudt/1-issue-xudt.ts @@ -1,5 +1,5 @@ import { RgbppTokenInfo } from '@rgbpp-sdk/ckb'; -import { issueXudt } from 'examples-core'; +import { issueXudt } from './core/xudt'; const XUDT_TOKEN_INFO: RgbppTokenInfo = { decimal: 8, diff --git a/examples/xudt/2-transfer-xudt.ts b/examples/xudt/2-transfer-xudt.ts index 1e4e09be..a0f59acb 100644 --- a/examples/xudt/2-transfer-xudt.ts +++ b/examples/xudt/2-transfer-xudt.ts @@ -1,5 +1,5 @@ import { RgbppTokenInfo } from '@rgbpp-sdk/ckb'; -import { transferXudt } from 'examples-core'; +import { transferXudt } from './core/xudt'; const XUDT_TOKEN_INFO: RgbppTokenInfo = { decimal: 8, diff --git a/examples/xudt/core/env.ts b/examples/xudt/core/env.ts new file mode 100644 index 00000000..6549daa4 --- /dev/null +++ b/examples/xudt/core/env.ts @@ -0,0 +1,18 @@ +import { AddressPrefix, privateKeyToAddress } from '@nervosnetwork/ckb-sdk-utils'; +import { Collector } from '@rgbpp-sdk/ckb'; +import dotenv from 'dotenv'; + +dotenv.config({ path: __dirname + '/../.env' }); + +export const isMainnet = process.env.IS_MAINNET === 'true' ? true : false; + +console.log('IS_MAINNET', process.env.IS_MAINNET); + +export const collector = new Collector({ + ckbNodeUrl: process.env.CKB_NODE_URL!, + ckbIndexerUrl: process.env.CKB_INDEXER_URL!, +}); +export const CKB_PRIVATE_KEY = process.env.CKB_SECP256K1_PRIVATE_KEY!; +export const ckbAddress = privateKeyToAddress(CKB_PRIVATE_KEY, { + prefix: isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, +}); diff --git a/examples/core/src/ckb-xudt/index.ts b/examples/xudt/core/xudt.ts similarity index 99% rename from examples/core/src/ckb-xudt/index.ts rename to examples/xudt/core/xudt.ts index 5fa40760..e1db691e 100644 --- a/examples/core/src/ckb-xudt/index.ts +++ b/examples/xudt/core/xudt.ts @@ -19,7 +19,7 @@ import { calculateXudtTokenInfoCellCapacity, NoXudtLiveCellError, } from '@rgbpp-sdk/ckb'; -import { CKB_PRIVATE_KEY, ckbAddress, collector, isMainnet } from '../utils'; +import { CKB_PRIVATE_KEY, ckbAddress, collector, isMainnet } from './env'; export interface IssueResult { txHash: string; diff --git a/examples/xudt/package.json b/examples/xudt/package.json index d09c40e3..9583728f 100644 --- a/examples/xudt/package.json +++ b/examples/xudt/package.json @@ -5,12 +5,17 @@ "private": true, "type": "commonjs", "scripts": { + "build": "tsc -p tsconfig.build.json", "format": "prettier --write '**/*.ts'", "lint": "tsc && eslint . && prettier --check '**/*.ts'", "lint:fix": "tsc && eslint --fix --ext .ts . && prettier --write '**/*.ts'" }, "dependencies": { - "@rgbpp-sdk/ckb": "workspace:^", - "examples-core": "workspace:^" + "@nervosnetwork/ckb-sdk-utils": "^0.109.1", + "@rgbpp-sdk/ckb": "workspace:^" + }, + "devDependencies": { + "dotenv": "^16.4.5", + "@types/dotenv": "^8.2.0" } } diff --git a/examples/xudt/tsconfig.build.json b/examples/xudt/tsconfig.build.json new file mode 100644 index 00000000..18f21a86 --- /dev/null +++ b/examples/xudt/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "CommonJS", + "rootDir": "src", + "outDir": "lib", + "noEmit": false + }, + "include": ["core/*.ts"], +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1fe96902..9fb5deb7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -134,37 +134,6 @@ importers: specifier: ^0.21.0 version: 0.21.0(vite@5.2.11) - examples/core: - dependencies: - '@exact-realty/multipart-parser': - specifier: ^1.0.13 - version: 1.0.13 - '@nervosnetwork/ckb-sdk-utils': - specifier: ^0.109.1 - version: 0.109.1 - '@rgbpp-sdk/btc': - specifier: workspace:^ - version: link:../../packages/btc - '@rgbpp-sdk/ckb': - specifier: workspace:^ - version: link:../../packages/ckb - '@rgbpp-sdk/service': - specifier: workspace:^ - version: link:../../packages/service - '@spore-sdk/core': - specifier: ^0.2.0-beta.6 - version: 0.2.0-beta.6(@ckb-lumos/lumos@0.22.0-next.5)(lodash@4.17.21) - axios: - specifier: ^1.6.8 - version: 1.6.8 - devDependencies: - '@types/node': - specifier: ^20.11.28 - version: 20.12.2 - typescript: - specifier: ^5.4.2 - version: 5.4.3 - examples/rgbpp: dependencies: '@exact-realty/multipart-parser': @@ -185,25 +154,35 @@ importers: '@spore-sdk/core': specifier: ^0.2.0-beta.6 version: 0.2.0-beta.6(@ckb-lumos/lumos@0.22.0-next.5)(lodash@4.17.21) - examples-core: - specifier: workspace:^ - version: link:../core devDependencies: + '@types/dotenv': + specifier: ^8.2.0 + version: 8.2.0 '@types/node': specifier: ^20.11.28 version: 20.11.28 + dotenv: + specifier: ^16.4.5 + version: 16.4.5 typescript: specifier: ^5.4.2 version: 5.4.2 examples/xudt: dependencies: + '@nervosnetwork/ckb-sdk-utils': + specifier: ^0.109.1 + version: 0.109.1 '@rgbpp-sdk/ckb': specifier: workspace:^ version: link:../../packages/ckb - examples-core: - specifier: workspace:^ - version: link:../core + devDependencies: + '@types/dotenv': + specifier: ^8.2.0 + version: 8.2.0 + dotenv: + specifier: ^16.4.5 + version: 16.4.5 packages/btc: dependencies: @@ -1739,6 +1718,13 @@ packages: resolution: {integrity: sha512-VvMETBojHvhX4f+ocYTySQlXMZfxKV3Jyb7iCWlWaC+exbedkv6Iv2bZZqI736qXjVguH6IH7bzwMBMfTT+zuQ==} dev: false + /@types/dotenv@8.2.0: + resolution: {integrity: sha512-ylSC9GhfRH7m1EUXBXofhgx4lUWmFeQDINW5oLuS+gxWdfUeW4zJdeVTYVkexEW+e2VUvlZR2kGnGGipAWR7kw==} + deprecated: This is a stub types definition. dotenv provides its own type definitions, so you do not need this installed. + dependencies: + dotenv: 16.4.5 + dev: true + /@types/estree@1.0.5: resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} dev: true @@ -3025,6 +3011,11 @@ packages: engines: {node: '>=10'} dev: true + /dotenv@16.4.5: + resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} + engines: {node: '>=12'} + dev: true + /dotenv@8.6.0: resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} engines: {node: '>=10'} From afa698fc432436644f2322b8e891e40ea56fb652 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Thu, 9 May 2024 14:32:18 +0800 Subject: [PATCH 31/78] refactor: Update examples directory and readme --- examples/rgbpp/.env.example | 17 +- examples/rgbpp/README.md | 111 +++++---- examples/rgbpp/package.json | 2 +- examples/rgbpp/spore/4-transfer-spore.ts | 2 +- examples/rgbpp/spore/5-leap-spore-to-ckb.ts | 2 +- .../rgbpp/spore/6-unlock-btc-time-cell.ts | 2 +- examples/rgbpp/spore/7-leap-spore-to-btc.ts | 2 +- .../rgbpp/spore/launch/1-prepare-cluster.ts | 2 +- .../rgbpp/spore/launch/2-create-cluster.ts | 2 +- .../rgbpp/spore/launch/3-create-spores.ts | 2 +- .../rgbpp/spore/local/4-transfer-spore.ts | 2 +- .../rgbpp/spore/local/5-leap-spore-to-ckb.ts | 2 +- examples/rgbpp/tsconfig.build.json | 10 - examples/rgbpp/{core => utils}/env.ts | 2 - examples/rgbpp/{core => utils}/index.ts | 0 examples/rgbpp/{core => utils}/spore.ts | 0 examples/rgbpp/{core => utils}/xudt.ts | 64 +---- examples/rgbpp/xudt/1-ckb-leap-btc.ts | 41 ++- examples/rgbpp/xudt/2-btc-transfer.ts | 2 +- examples/rgbpp/xudt/3-btc-leap-ckb.ts | 5 +- .../rgbpp/xudt/launch/1-prepare-launch.ts | 2 +- examples/rgbpp/xudt/launch/2-launch-rgbpp.ts | 2 +- .../rgbpp/xudt/launch/3-distribute-rgbpp.ts | 2 +- examples/rgbpp/xudt/local/2-btc-transfer.ts | 2 +- examples/rgbpp/xudt/local/3-btc-leap-ckb.ts | 2 +- .../{ => local}/4-unlock-btc-time-cell.ts | 2 +- examples/xudt/.env.example | 28 +-- examples/xudt/1-issue-xudt.ts | 105 +++++++- examples/xudt/2-transfer-xudt.ts | 133 +++++++++- examples/xudt/README.md | 25 ++ examples/xudt/core/xudt.ts | 233 ------------------ examples/xudt/{core => }/env.ts | 4 +- examples/xudt/package.json | 1 - examples/xudt/tsconfig.build.json | 10 - 34 files changed, 394 insertions(+), 429 deletions(-) delete mode 100644 examples/rgbpp/tsconfig.build.json rename examples/rgbpp/{core => utils}/env.ts (96%) rename examples/rgbpp/{core => utils}/index.ts (100%) rename examples/rgbpp/{core => utils}/spore.ts (100%) rename examples/rgbpp/{core => utils}/xudt.ts (61%) rename examples/rgbpp/xudt/{ => local}/4-unlock-btc-time-cell.ts (98%) delete mode 100644 examples/xudt/core/xudt.ts rename examples/xudt/{core => }/env.ts (85%) delete mode 100644 examples/xudt/tsconfig.build.json diff --git a/examples/rgbpp/.env.example b/examples/rgbpp/.env.example index fda5ec43..950024fd 100644 --- a/examples/rgbpp/.env.example +++ b/examples/rgbpp/.env.example @@ -1,29 +1,28 @@ # Ture for CKB and BTC Mainnet and false for CKB and BTC Testnet, the default value is false -IS_MAINNET='false' - +IS_MAINNET=false # CKB Variables # The CKB secp256k1 private key whose format is 32bytes hex string with 0x prefix -CKB_SECP256K1_PRIVATE_KEY='0x-private-key' +CKB_SECP256K1_PRIVATE_KEY=0x-private-key # CKB node url which should be matched with IS_MAINNET -CKB_NODE_URL='https://testnet.ckb.dev/rpc' +CKB_NODE_URL=https://testnet.ckb.dev/rpc # CKB indexer url which should be matched with IS_MAINNET -CKB_INDEXER_URL='https://testnet.ckb.dev/indexer' +CKB_INDEXER_URL=https://testnet.ckb.dev/indexer # BTC Variables # The BTC private key whose format is 32bytes hex string without 0x prefix -BTC_PRIVATE_KEY='private-key' +BTC_PRIVATE_KEY=private-key # The BTC assets api url which should be matched with IS_MAINNET -BTC_ASSETS_API_URL='https://btc-assets-api.testnet.mibao.pro'; +BTC_ASSETS_API_URL=https://btc-assets-api.testnet.mibao.pro; # The BTC assets api token which should be matched with IS_MAINNET -BTC_ASSETS_TOKEN=''; +BTC_ASSETS_TOKEN=; # The BTC assets api origin which should be matched with IS_MAINNET -BTC_ASSETS_ORIGIN='https://btc-test.app'; \ No newline at end of file +BTC_ASSETS_ORIGIN=https://btc-test.app; \ No newline at end of file diff --git a/examples/rgbpp/README.md b/examples/rgbpp/README.md index 5f90be8a..3e27ce33 100644 --- a/examples/rgbpp/README.md +++ b/examples/rgbpp/README.md @@ -1,85 +1,73 @@ # RGB++ Examples -**All examples are just to demonstrate the use of RGB++ SDK.** +- xUDT directory: The examples for RGB++ UDT issuance, transfer, and leap +- Spore directory: The examples for RGB++ Spore creation, transfer and leap -- Local and Queue directories: The examples for RGB++ UDT issuance, transfer, and leap -- Spore directory: The examples for RGB++ spore creation, transfer and leap -## What you must know about BTC transaction id - -**The BTC transaction id(hash) displayed on BTC explorer is different from the BTC transaction id(hash) in RGB++ lock args. They are in reverse byte order.** - -We follow the following two rules: +## RGB++ xUDT Examples with Queue Service -- Whenever you're working with transaction/block hashes **internally** (e.g. inside raw bitcoin data), you use the **natural** byte order. -- Whenever you're **displaying or searching** for transaction/block hashes, you use the **reverse** byte order. +### How to Start -For detailed rules, please refer to [Byte Order](https://learnmeabitcoin.com/technical/general/byte-order/) +Copy the `.env.example` file to `.env`: -For example, the BTC transaction id(hash) of the RGB++ lock args like this: - -``` -4abc778213bc4da692f93745c2b07410ef2bfaee70417784d4ee8969fb258001 -``` - -But when you're searching for this transaction in [Bitcoin Core](https://bitcoin.org/en/bitcoin-core/) or on a block explorer, you'll see this byte order: - -``` -018025fb6989eed484774170eefa2bef1074b0c24537f992a64dbc138277bc4a +```shell +cd examples/rgbpp && cp .env.example .env ``` -## RGB++ xUDT Examples with Queue service(Recommended) +Update the configuration values: -### Leap xUDT from CKB to BTC +```yaml +# Ture for CKB and BTC Mainnet and false for CKB and BTC Testnet, the default value is false +IS_MAINNET=false -```shell -npx ts-node examples/rgbpp/queue/1-ckb-jump-btc.ts -``` +# CKB Variables -### Transfer RGB++ xUDT on BTC +# The CKB secp256k1 private key whose format is 32bytes hex string with 0x prefix +CKB_SECP256K1_PRIVATE_KEY=0x-private-key -```shell -npx ts-node examples/rgbpp/queue/2-btc-transfer.ts -``` +# CKB node url which should be matched with IS_MAINNET +CKB_NODE_URL=https://testnet.ckb.dev/rpc -### Leap RGB++ xUDT from BTC to CKB +# CKB indexer url which should be matched with IS_MAINNET +CKB_INDEXER_URL=https://testnet.ckb.dev/indexer -```shell -npx ts-node examples/rgbpp/queue/3-btc-jump-ckb.ts -``` +# BTC Variables -### Unlock xUDT BTC time cells on CKB +# The BTC private key whose format is 32bytes hex string without 0x prefix +BTC_PRIVATE_KEY=private-key -A cron job in RGB++ Queue service will construct a transaction unlocking the mature BTC time cells to the their `target_ckb_address`. +# The BTC assets api url which should be matched with IS_MAINNET +BTC_ASSETS_API_URL=https://btc-assets-api.testnet.mibao.pro; +# The BTC assets api token which should be matched with IS_MAINNET +BTC_ASSETS_TOKEN=; -## RGB++ xUDT Local Examples +# The BTC assets api origin which should be matched with IS_MAINNET +BTC_ASSETS_ORIGIN=https://btc-test.app; +``` -### Leap RGB++ xUDT from CKB to BTC +### Leap xUDT from CKB to BTC ```shell -npx ts-node examples/rgbpp/local/1-ckb-jump-btc.ts +npx ts-node examples/rgbpp/xudt/1-ckb-leap-btc.ts ``` ### Transfer RGB++ xUDT on BTC ```shell -npx ts-node examples/rgbpp/local/2-btc-transfer.ts +npx ts-node examples/rgbpp/xudt/2-btc-transfer.ts ``` ### Leap RGB++ xUDT from BTC to CKB ```shell -npx ts-node examples/rgbpp/local/3-btc-jump-ckb.ts +npx ts-node examples/rgbpp/xudt/3-btc-jump-ckb.ts ``` ### Unlock xUDT BTC time cells on CKB -**Warning: Wait at least 6 BTC confirmation blocks to unlock the BTC time cells after 4-btc-jump-ckb.ts** +A cron job in RGB++ Queue service will construct a transaction unlocking the mature BTC time cells to the their `target_ckb_address`. -```shell -npx ts-node examples/rgbpp/local/4-spend-btc-time-cell.ts -``` ## RGB++ Spore Examples @@ -88,18 +76,18 @@ npx ts-node examples/rgbpp/local/4-spend-btc-time-cell.ts ### Create RGB++ Cluster Cell ```shell -npx ts-node examples/rgbpp/spore/1-prepare-cluster.ts +npx ts-node examples/rgbpp/spore/launch/1-prepare-cluster.ts -npx ts-node examples/rgbpp/spore/2-create-cluster.ts +npx ts-node examples/rgbpp/spore/launch/2-create-cluster.ts ``` ### Create RGB++ Spores with Cluster on BTC ```shell -npx ts-node examples/rgbpp/spore/3-create-spores.ts +npx ts-node examples/rgbpp/spore/launch/3-create-spores.ts ``` -### Transfer RGB++ Spore on BTC +### Transfer RGB++ Spore on BTC with Queue Service ```shell npx ts-node examples/rgbpp/spore/4-transfer-spore.ts @@ -115,7 +103,7 @@ npx ts-node examples/rgbpp/spore/5-leap-spore-to-ckb.ts A cron job in RGB++ Queue service will construct a transaction unlocking the mature BTC time cells to the their `target_ckb_address`. -However, you can still manually unlock the spore btc time cell through the following command +However, you can still manually unlock the spore BTC time cell through the following command **Warning: Wait at least 6 BTC confirmation blocks to unlock the BTC time cells after 5-leap-spore-to-ckb.ts** @@ -127,4 +115,27 @@ npx ts-node examples/rgbpp/spore/6-unlock-btc-time-cell.ts ```shell npx ts-node examples/rgbpp/spore/7-leap-spore-to-btc.ts +``` + +## What you must know about BTC transaction id + +**The BTC transaction id(hash) displayed on BTC explorer is different from the BTC transaction id(hash) in RGB++ lock args. They are in reverse byte order.** + +We follow the following two rules: + +- Whenever you're working with transaction/block hashes **internally** (e.g. inside raw bitcoin data), you use the **natural** byte order. +- Whenever you're **displaying or searching** for transaction/block hashes, you use the **reverse** byte order. + +For detailed rules, please refer to [Byte Order](https://learnmeabitcoin.com/technical/general/byte-order/) + +For example, the BTC transaction id(hash) of the RGB++ lock args like this: + +``` +4abc778213bc4da692f93745c2b07410ef2bfaee70417784d4ee8969fb258001 +``` + +But when you're searching for this transaction in [Bitcoin Core](https://bitcoin.org/en/bitcoin-core/) or on a block explorer, you'll see this byte order: + +``` +018025fb6989eed484774170eefa2bef1074b0c24537f992a64dbc138277bc4a ``` \ No newline at end of file diff --git a/examples/rgbpp/package.json b/examples/rgbpp/package.json index fa820dff..36bdc155 100644 --- a/examples/rgbpp/package.json +++ b/examples/rgbpp/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "description": "Examples used for RGBPP assets issuance, transfer, and leaping between BTC and CKB", "private": true, - "type": "module", + "type": "commonjs", "scripts": { "format": "prettier --write '**/*.{js,ts}'", "lint": "tsc && eslint . && prettier --check '**/*.{js,ts}'", diff --git a/examples/rgbpp/spore/4-transfer-spore.ts b/examples/rgbpp/spore/4-transfer-spore.ts index ba7f1092..1d76948f 100644 --- a/examples/rgbpp/spore/4-transfer-spore.ts +++ b/examples/rgbpp/spore/4-transfer-spore.ts @@ -1,5 +1,5 @@ import { buildRgbppLockArgs } from '@rgbpp-sdk/ckb'; -import { SporeTransferParams, transferSporeOnBtc, btcService } from '../core'; +import { SporeTransferParams, transferSporeOnBtc, btcService } from '../utils'; const transferSpore = async (params: SporeTransferParams) => { const btcTxId = await transferSporeOnBtc(params); diff --git a/examples/rgbpp/spore/5-leap-spore-to-ckb.ts b/examples/rgbpp/spore/5-leap-spore-to-ckb.ts index 8481900e..baae35de 100644 --- a/examples/rgbpp/spore/5-leap-spore-to-ckb.ts +++ b/examples/rgbpp/spore/5-leap-spore-to-ckb.ts @@ -1,5 +1,5 @@ import { buildRgbppLockArgs } from '@rgbpp-sdk/ckb'; -import { leapSporeToCkb, btcService, SporeLeapParams } from '../core'; +import { leapSporeToCkb, btcService, SporeLeapParams } from '../utils'; const leapSpore = async (params: SporeLeapParams) => { const btcTxId = await leapSporeToCkb(params); diff --git a/examples/rgbpp/spore/6-unlock-btc-time-cell.ts b/examples/rgbpp/spore/6-unlock-btc-time-cell.ts index 75d5f32f..21946eab 100644 --- a/examples/rgbpp/spore/6-unlock-btc-time-cell.ts +++ b/examples/rgbpp/spore/6-unlock-btc-time-cell.ts @@ -1,5 +1,5 @@ import { sendCkbTx, getBtcTimeLockScript, buildSporeBtcTimeCellsSpentTx, signBtcTimeCellSpentTx } from '@rgbpp-sdk/ckb'; -import { CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from '../core'; +import { CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from '../utils'; // Warning: Wait at least 6 BTC confirmation blocks to spend the BTC time cells after 4-btc-jump-ckb.ts const unlockSporeBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: string }) => { diff --git a/examples/rgbpp/spore/7-leap-spore-to-btc.ts b/examples/rgbpp/spore/7-leap-spore-to-btc.ts index 443bfcca..d8922b1d 100644 --- a/examples/rgbpp/spore/7-leap-spore-to-btc.ts +++ b/examples/rgbpp/spore/7-leap-spore-to-btc.ts @@ -5,7 +5,7 @@ import { getSporeTypeScript, genLeapSporeFromCkbToBtcRawTx, } from '@rgbpp-sdk/ckb'; -import { isMainnet, collector, ckbAddress, CKB_PRIVATE_KEY } from '../core'; +import { isMainnet, collector, ckbAddress, CKB_PRIVATE_KEY } from '../utils'; const leapSporeFromCkbToBtc = async ({ outIndex, diff --git a/examples/rgbpp/spore/launch/1-prepare-cluster.ts b/examples/rgbpp/spore/launch/1-prepare-cluster.ts index fcd37d3c..0aff04fb 100644 --- a/examples/rgbpp/spore/launch/1-prepare-cluster.ts +++ b/examples/rgbpp/spore/launch/1-prepare-cluster.ts @@ -10,7 +10,7 @@ import { genRgbppLockScript, getSecp256k1CellDep, } from '@rgbpp-sdk/ckb'; -import { ckbAddress, isMainnet, collector, CKB_PRIVATE_KEY } from '../../core'; +import { ckbAddress, isMainnet, collector, CKB_PRIVATE_KEY } from '../../utils'; import { CLUSTER_DATA } from './0-cluster-info'; const prepareClusterCell = async ({ outIndex, btcTxId }: { outIndex: number; btcTxId: string }) => { diff --git a/examples/rgbpp/spore/launch/2-create-cluster.ts b/examples/rgbpp/spore/launch/2-create-cluster.ts index e8824147..4eda55e7 100644 --- a/examples/rgbpp/spore/launch/2-create-cluster.ts +++ b/examples/rgbpp/spore/launch/2-create-cluster.ts @@ -8,7 +8,7 @@ import { } from '@rgbpp-sdk/ckb'; import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; import { BtcAssetsApiError } from '@rgbpp-sdk/service'; -import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../core'; +import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../utils'; import { CLUSTER_DATA } from './0-cluster-info'; const createCluster = async ({ ownerRgbppLockArgs }: { ownerRgbppLockArgs: string }) => { diff --git a/examples/rgbpp/spore/launch/3-create-spores.ts b/examples/rgbpp/spore/launch/3-create-spores.ts index 529e49ba..b4deb3cc 100644 --- a/examples/rgbpp/spore/launch/3-create-spores.ts +++ b/examples/rgbpp/spore/launch/3-create-spores.ts @@ -20,7 +20,7 @@ import { btcService, CKB_PRIVATE_KEY, ckbAddress, -} from '../../core'; +} from '../../utils'; interface Params { clusterRgbppLockArgs: Hex; diff --git a/examples/rgbpp/spore/local/4-transfer-spore.ts b/examples/rgbpp/spore/local/4-transfer-spore.ts index 0662d0bd..4635a81e 100644 --- a/examples/rgbpp/spore/local/4-transfer-spore.ts +++ b/examples/rgbpp/spore/local/4-transfer-spore.ts @@ -11,7 +11,7 @@ import { import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; import { BtcAssetsApiError } from '@rgbpp-sdk/service'; import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from 'examples-core'; +import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../utils'; const transferSpore = async ({ sporeRgbppLockArgs, diff --git a/examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts b/examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts index 21e7c6ae..fc3e2319 100644 --- a/examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts +++ b/examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts @@ -11,7 +11,7 @@ import { import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; import { BtcAssetsApiError } from '@rgbpp-sdk/service'; import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from 'examples-core'; +import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../utils'; const transferSpore = async ({ sporeRgbppLockArgs, diff --git a/examples/rgbpp/tsconfig.build.json b/examples/rgbpp/tsconfig.build.json deleted file mode 100644 index 18f21a86..00000000 --- a/examples/rgbpp/tsconfig.build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "module": "CommonJS", - "rootDir": "src", - "outDir": "lib", - "noEmit": false - }, - "include": ["core/*.ts"], -} diff --git a/examples/rgbpp/core/env.ts b/examples/rgbpp/utils/env.ts similarity index 96% rename from examples/rgbpp/core/env.ts rename to examples/rgbpp/utils/env.ts index b30b593d..95cedadc 100644 --- a/examples/rgbpp/core/env.ts +++ b/examples/rgbpp/utils/env.ts @@ -8,8 +8,6 @@ dotenv.config({ path: __dirname + '/../.env' }); export const isMainnet = process.env.IS_MAINNET === 'true' ? true : false; -console.log('IS_MAINNET', process.env.IS_MAINNET); - export const collector = new Collector({ ckbNodeUrl: process.env.CKB_NODE_URL!, ckbIndexerUrl: process.env.CKB_INDEXER_URL!, diff --git a/examples/rgbpp/core/index.ts b/examples/rgbpp/utils/index.ts similarity index 100% rename from examples/rgbpp/core/index.ts rename to examples/rgbpp/utils/index.ts diff --git a/examples/rgbpp/core/spore.ts b/examples/rgbpp/utils/spore.ts similarity index 100% rename from examples/rgbpp/core/spore.ts rename to examples/rgbpp/utils/spore.ts diff --git a/examples/rgbpp/core/xudt.ts b/examples/rgbpp/utils/xudt.ts similarity index 61% rename from examples/rgbpp/core/xudt.ts rename to examples/rgbpp/utils/xudt.ts index 7a13ddd7..2799e8f3 100644 --- a/examples/rgbpp/core/xudt.ts +++ b/examples/rgbpp/utils/xudt.ts @@ -1,68 +1,8 @@ import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { - genCkbJumpBtcVirtualTx, - getSecp256k1CellDep, - buildRgbppLockArgs, - getXudtTypeScript, - genBtcTransferCkbVirtualTx, - genBtcJumpCkbVirtualTx, -} from '@rgbpp-sdk/ckb'; -import { - CKB_PRIVATE_KEY, - isMainnet, - collector, - ckbAddress, - btcAddress, - btcKeyPair, - btcService, - btcDataSource, -} from './env'; +import { getXudtTypeScript, genBtcTransferCkbVirtualTx, genBtcJumpCkbVirtualTx } from '@rgbpp-sdk/ckb'; +import { isMainnet, collector, btcAddress, btcKeyPair, btcService, btcDataSource } from './env'; import { sendRgbppUtxos } from '@rgbpp-sdk/btc'; -export interface LeapToBtcParams { - outIndex: number; - btcTxId: string; - xudtTypeArgs: string; - transferAmount: bigint; -} - -export const leapFromCkbToBtc = async ({ - outIndex, - btcTxId, - xudtTypeArgs, - transferAmount, -}: LeapToBtcParams): Promise => { - const toRgbppLockArgs = buildRgbppLockArgs(outIndex, btcTxId); - - // Warning: Please replace with your real xUDT type script here - const xudtType: CKBComponents.Script = { - ...getXudtTypeScript(isMainnet), - args: xudtTypeArgs, - }; - - const ckbRawTx = await genCkbJumpBtcVirtualTx({ - collector, - fromCkbAddress: ckbAddress, - toRgbppLockArgs, - xudtTypeBytes: serializeScript(xudtType), - transferAmount, - }); - - const emptyWitness = { lock: '', inputType: '', outputType: '' }; - const unsignedTx: CKBComponents.RawTransactionToSign = { - ...ckbRawTx, - cellDeps: [...ckbRawTx.cellDeps, getSecp256k1CellDep(false)], - witnesses: [emptyWitness, ...ckbRawTx.witnesses.slice(1)], - }; - - const signedTx = collector.getCkb().signTransaction(CKB_PRIVATE_KEY)(unsignedTx); - - const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); - console.info(`Rgbpp asset has been jumped from CKB to BTC and tx hash is ${txHash}`); - - return txHash; -}; - export interface RgbppTransferParams { rgbppLockArgsList: string[]; toBtcAddress: string; diff --git a/examples/rgbpp/xudt/1-ckb-leap-btc.ts b/examples/rgbpp/xudt/1-ckb-leap-btc.ts index ce7ab8df..337cc230 100644 --- a/examples/rgbpp/xudt/1-ckb-leap-btc.ts +++ b/examples/rgbpp/xudt/1-ckb-leap-btc.ts @@ -1,4 +1,43 @@ -import { leapFromCkbToBtc } from '../core'; +import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; +import { genCkbJumpBtcVirtualTx, getSecp256k1CellDep, buildRgbppLockArgs, getXudtTypeScript } from '@rgbpp-sdk/ckb'; +import { CKB_PRIVATE_KEY, isMainnet, collector, ckbAddress } from '../utils'; + +interface LeapToBtcParams { + outIndex: number; + btcTxId: string; + xudtTypeArgs: string; + transferAmount: bigint; +} + +const leapFromCkbToBtc = async ({ outIndex, btcTxId, xudtTypeArgs, transferAmount }: LeapToBtcParams) => { + const toRgbppLockArgs = buildRgbppLockArgs(outIndex, btcTxId); + + // Warning: Please replace with your real xUDT type script here + const xudtType: CKBComponents.Script = { + ...getXudtTypeScript(isMainnet), + args: xudtTypeArgs, + }; + + const ckbRawTx = await genCkbJumpBtcVirtualTx({ + collector, + fromCkbAddress: ckbAddress, + toRgbppLockArgs, + xudtTypeBytes: serializeScript(xudtType), + transferAmount, + }); + + const emptyWitness = { lock: '', inputType: '', outputType: '' }; + const unsignedTx: CKBComponents.RawTransactionToSign = { + ...ckbRawTx, + cellDeps: [...ckbRawTx.cellDeps, getSecp256k1CellDep(false)], + witnesses: [emptyWitness, ...ckbRawTx.witnesses.slice(1)], + }; + + const signedTx = collector.getCkb().signTransaction(CKB_PRIVATE_KEY)(unsignedTx); + + const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); + console.info(`Rgbpp asset has been jumped from CKB to BTC and tx hash is ${txHash}`); +}; // Use your real BTC UTXO information on the BTC Testnet leapFromCkbToBtc({ diff --git a/examples/rgbpp/xudt/2-btc-transfer.ts b/examples/rgbpp/xudt/2-btc-transfer.ts index 321ccb37..358eb4ca 100644 --- a/examples/rgbpp/xudt/2-btc-transfer.ts +++ b/examples/rgbpp/xudt/2-btc-transfer.ts @@ -1,5 +1,5 @@ import { buildRgbppLockArgs } from '@rgbpp-sdk/ckb'; -import { RgbppTransferParams, btcService, transferRgbppOnBtc } from '../core'; +import { RgbppTransferParams, btcService, transferRgbppOnBtc } from '../utils'; const transfer = async (params: RgbppTransferParams) => { const btcTxId = await transferRgbppOnBtc(params); diff --git a/examples/rgbpp/xudt/3-btc-leap-ckb.ts b/examples/rgbpp/xudt/3-btc-leap-ckb.ts index cb70f748..655b72e4 100644 --- a/examples/rgbpp/xudt/3-btc-leap-ckb.ts +++ b/examples/rgbpp/xudt/3-btc-leap-ckb.ts @@ -1,9 +1,8 @@ import { buildRgbppLockArgs } from '@rgbpp-sdk/ckb'; -import { LeapToCkbParams, btcService, leapFromBtcToCkb } from '../core'; +import { LeapToCkbParams, btcService, leapFromBtcToCkb } from '../utils'; const leapToCKB = async (params: LeapToCkbParams) => { const btcTxId = await leapFromBtcToCkb(params); - try { const interval = setInterval(async () => { const { state, failedReason } = await btcService.getRgbppTransactionState(btcTxId); @@ -25,8 +24,6 @@ const leapToCKB = async (params: LeapToCkbParams) => { // rgbppLockArgs: outIndexU32 + btcTxId leapToCKB({ - // If the `2-btc-transfer.ts` has been executed, the BTC txId should be the new generated BTC txId by the `2-btc-transfer.ts` - // Otherwise the BTC txId should be same as the the BTC txId of the `1-ckb-jump-btc.ts` rgbppLockArgsList: [buildRgbppLockArgs(1, '6edd4b9327506fab09fb9a0f5e5f35136a6a94bd4c9dd79af04921618fa6c800')], toCkbAddress: 'ckt1qrfrwcdnvssswdwpn3s9v8fp87emat306ctjwsm3nmlkjg8qyza2cqgqq9kxr7vy7yknezj0vj0xptx6thk6pwyr0sxamv6q', xudtTypeArgs: '0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b', diff --git a/examples/rgbpp/xudt/launch/1-prepare-launch.ts b/examples/rgbpp/xudt/launch/1-prepare-launch.ts index b11a8a3f..933049f8 100644 --- a/examples/rgbpp/xudt/launch/1-prepare-launch.ts +++ b/examples/rgbpp/xudt/launch/1-prepare-launch.ts @@ -13,7 +13,7 @@ import { getSecp256k1CellDep, } from '@rgbpp-sdk/ckb'; import { RGBPP_TOKEN_INFO } from './0-rgbpp-token-info'; -import { CKB_PRIVATE_KEY, ckbAddress, collector, isMainnet } from '../../core'; +import { CKB_PRIVATE_KEY, ckbAddress, collector, isMainnet } from '../../utils'; const prepareLaunchCell = async ({ outIndex, diff --git a/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts b/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts index 1747c5aa..9da66519 100644 --- a/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts +++ b/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts @@ -9,7 +9,7 @@ import { import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; import { BtcAssetsApiError } from '@rgbpp-sdk/service'; import { RGBPP_TOKEN_INFO } from './0-rgbpp-token-info'; -import { btcAddress, btcDataSource, btcKeyPair, btcService, collector, isMainnet } from '../../core'; +import { btcAddress, btcDataSource, btcKeyPair, btcService, collector, isMainnet } from '../../utils'; interface Params { ownerRgbppLockArgs: string; diff --git a/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts b/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts index ba7af483..9b05ae58 100644 --- a/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts +++ b/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts @@ -21,7 +21,7 @@ import { btcService, CKB_PRIVATE_KEY, ckbAddress, -} from '../../core'; +} from '../../utils'; interface Params { rgbppLockArgsList: string[]; diff --git a/examples/rgbpp/xudt/local/2-btc-transfer.ts b/examples/rgbpp/xudt/local/2-btc-transfer.ts index c7f492f5..b55bdfa3 100644 --- a/examples/rgbpp/xudt/local/2-btc-transfer.ts +++ b/examples/rgbpp/xudt/local/2-btc-transfer.ts @@ -17,7 +17,7 @@ import { btcDataSource, btcKeyPair, btcService, -} from '../../core'; +} from '../../utils'; const transfer = async ({ rgbppLockArgsList, toBtcAddress, xudtTypeArgs, transferAmount }: RgbppTransferParams) => { const xudtType: CKBComponents.Script = { diff --git a/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts b/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts index 43356b77..0ed7b27d 100644 --- a/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts +++ b/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts @@ -9,7 +9,7 @@ import { } from '@rgbpp-sdk/ckb'; import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; import { BtcAssetsApiError } from '@rgbpp-sdk/service'; -import { LeapToCkbParams, isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../core'; +import { LeapToCkbParams, isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../utils'; const leapFromBtcToCkb = async ({ rgbppLockArgsList, toCkbAddress, xudtTypeArgs, transferAmount }: LeapToCkbParams) => { const xudtType: CKBComponents.Script = { diff --git a/examples/rgbpp/xudt/4-unlock-btc-time-cell.ts b/examples/rgbpp/xudt/local/4-unlock-btc-time-cell.ts similarity index 98% rename from examples/rgbpp/xudt/4-unlock-btc-time-cell.ts rename to examples/rgbpp/xudt/local/4-unlock-btc-time-cell.ts index c9a78f68..b297d3a6 100644 --- a/examples/rgbpp/xudt/4-unlock-btc-time-cell.ts +++ b/examples/rgbpp/xudt/local/4-unlock-btc-time-cell.ts @@ -1,5 +1,5 @@ import { sendCkbTx, buildBtcTimeCellsSpentTx, getBtcTimeLockScript, signBtcTimeCellSpentTx } from '@rgbpp-sdk/ckb'; -import { CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from '../core'; +import { CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from '../../utils'; // Warning: Wait at least 6 BTC confirmation blocks to spend the BTC time cells after 4-btc-jump-ckb.ts const unlockBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: string }) => { diff --git a/examples/xudt/.env.example b/examples/xudt/.env.example index fda5ec43..2b7d3adc 100644 --- a/examples/xudt/.env.example +++ b/examples/xudt/.env.example @@ -1,29 +1,11 @@ -# Ture for CKB and BTC Mainnet and false for CKB and BTC Testnet, the default value is false -IS_MAINNET='false' - - -# CKB Variables +# Ture for CKB Mainnet and false for CKB Testnet, the default value is false +IS_MAINNET=false # The CKB secp256k1 private key whose format is 32bytes hex string with 0x prefix -CKB_SECP256K1_PRIVATE_KEY='0x-private-key' +CKB_SECP256K1_PRIVATE_KEY=0x-private-key # CKB node url which should be matched with IS_MAINNET -CKB_NODE_URL='https://testnet.ckb.dev/rpc' +CKB_NODE_URL=https://testnet.ckb.dev/rpc # CKB indexer url which should be matched with IS_MAINNET -CKB_INDEXER_URL='https://testnet.ckb.dev/indexer' - - -# BTC Variables - -# The BTC private key whose format is 32bytes hex string without 0x prefix -BTC_PRIVATE_KEY='private-key' - -# The BTC assets api url which should be matched with IS_MAINNET -BTC_ASSETS_API_URL='https://btc-assets-api.testnet.mibao.pro'; - -# The BTC assets api token which should be matched with IS_MAINNET -BTC_ASSETS_TOKEN=''; - -# The BTC assets api origin which should be matched with IS_MAINNET -BTC_ASSETS_ORIGIN='https://btc-test.app'; \ No newline at end of file +CKB_INDEXER_URL=https://testnet.ckb.dev/indexer \ No newline at end of file diff --git a/examples/xudt/1-issue-xudt.ts b/examples/xudt/1-issue-xudt.ts index eb7cebeb..fb2cddf8 100644 --- a/examples/xudt/1-issue-xudt.ts +++ b/examples/xudt/1-issue-xudt.ts @@ -1,5 +1,106 @@ -import { RgbppTokenInfo } from '@rgbpp-sdk/ckb'; -import { issueXudt } from './core/xudt'; +import { addressToScript, getTransactionSize, scriptToHash } from '@nervosnetwork/ckb-sdk-utils'; +import { + getSecp256k1CellDep, + RgbppTokenInfo, + NoLiveCellError, + calculateUdtCellCapacity, + MAX_FEE, + MIN_CAPACITY, + getXudtTypeScript, + append0x, + getUniqueTypeScript, + u128ToLe, + encodeRgbppTokenInfo, + getXudtDep, + getUniqueTypeDep, + SECP256K1_WITNESS_LOCK_SIZE, + calculateTransactionFee, + generateUniqueTypeArgs, + calculateXudtTokenInfoCellCapacity, +} from '@rgbpp-sdk/ckb'; +import { CKB_PRIVATE_KEY, ckbAddress, collector, isMainnet } from './env'; + +/** + * issueXudt can be used to issue xUDT assets with unique cell as token info cell. + * @param xudtTotalAmount The xudtTotalAmount specifies the total amount of asset issuance + * @param tokenInfo The xUDT token info which includes decimal, name and symbol + */ +const issueXudt = async ({ xudtTotalAmount, tokenInfo }: { xudtTotalAmount: bigint; tokenInfo: RgbppTokenInfo }) => { + const issueLock = addressToScript(ckbAddress); + + let emptyCells = await collector.getCells({ + lock: issueLock, + }); + if (!emptyCells || emptyCells.length === 0) { + throw new NoLiveCellError('The address has no empty cells'); + } + emptyCells = emptyCells.filter((cell) => !cell.output.type); + + const xudtCapacity = calculateUdtCellCapacity(issueLock); + const xudtInfoCapacity = calculateXudtTokenInfoCellCapacity(tokenInfo, issueLock); + + const txFee = MAX_FEE; + const { inputs, sumInputsCapacity } = collector.collectInputs(emptyCells, xudtCapacity + xudtInfoCapacity, txFee, { + minCapacity: MIN_CAPACITY, + }); + + const xudtType: CKBComponents.Script = { + ...getXudtTypeScript(isMainnet), + args: append0x(scriptToHash(issueLock)), + }; + + console.log('xUDT type script', xudtType); + + let changeCapacity = sumInputsCapacity - xudtCapacity - xudtInfoCapacity; + const outputs: CKBComponents.CellOutput[] = [ + { + lock: issueLock, + type: xudtType, + capacity: append0x(xudtCapacity.toString(16)), + }, + { + lock: issueLock, + type: { + ...getUniqueTypeScript(isMainnet), + args: generateUniqueTypeArgs(inputs[0], 1), + }, + capacity: append0x(xudtInfoCapacity.toString(16)), + }, + { + lock: issueLock, + capacity: append0x(changeCapacity.toString(16)), + }, + ]; + const totalAmount = xudtTotalAmount * BigInt(10 ** tokenInfo.decimal); + const outputsData = [append0x(u128ToLe(totalAmount)), encodeRgbppTokenInfo(tokenInfo), '0x']; + + const emptyWitness = { lock: '', inputType: '', outputType: '' }; + const witnesses = inputs.map((_, index) => (index === 0 ? emptyWitness : '0x')); + + const cellDeps = [getSecp256k1CellDep(isMainnet), getUniqueTypeDep(isMainnet), getXudtDep(isMainnet)]; + + const unsignedTx = { + version: '0x0', + cellDeps, + headerDeps: [], + inputs, + outputs, + outputsData, + witnesses, + }; + + if (txFee === MAX_FEE) { + const txSize = getTransactionSize(unsignedTx) + SECP256K1_WITNESS_LOCK_SIZE; + const estimatedTxFee = calculateTransactionFee(txSize); + changeCapacity -= estimatedTxFee; + unsignedTx.outputs[unsignedTx.outputs.length - 1].capacity = append0x(changeCapacity.toString(16)); + } + + const signedTx = collector.getCkb().signTransaction(CKB_PRIVATE_KEY)(unsignedTx); + const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); + + console.info(`xUDT asset on CKB has been issued and tx hash is ${txHash}`); +}; const XUDT_TOKEN_INFO: RgbppTokenInfo = { decimal: 8, diff --git a/examples/xudt/2-transfer-xudt.ts b/examples/xudt/2-transfer-xudt.ts index a0f59acb..47506e00 100644 --- a/examples/xudt/2-transfer-xudt.ts +++ b/examples/xudt/2-transfer-xudt.ts @@ -1,5 +1,134 @@ -import { RgbppTokenInfo } from '@rgbpp-sdk/ckb'; -import { transferXudt } from './core/xudt'; +import { addressToScript, getTransactionSize } from '@nervosnetwork/ckb-sdk-utils'; +import { + getSecp256k1CellDep, + RgbppTokenInfo, + NoLiveCellError, + calculateUdtCellCapacity, + MAX_FEE, + MIN_CAPACITY, + append0x, + u128ToLe, + getXudtDep, + getUniqueTypeDep, + SECP256K1_WITNESS_LOCK_SIZE, + calculateTransactionFee, + NoXudtLiveCellError, +} from '@rgbpp-sdk/ckb'; +import { CKB_PRIVATE_KEY, ckbAddress, collector, isMainnet } from './env'; + +interface XudtTransferParams { + xudtType: CKBComponents.Script; + receivers: { + toAddress: string; + transferAmount: bigint; + }[]; +} + +/** + * transferXudt can be used to mint xUDT assets or transfer xUDT assets. + * @param xudtType The xUDT type script that comes from 1-issue-xudt + * @param receivers The receiver includes toAddress and transferAmount + */ +const transferXudt = async ({ xudtType, receivers }: XudtTransferParams) => { + const fromLock = addressToScript(ckbAddress); + + const xudtCells = await collector.getCells({ + lock: fromLock, + type: xudtType, + }); + if (!xudtCells || xudtCells.length === 0) { + throw new NoXudtLiveCellError('The address has no xudt cells'); + } + const sumTransferAmount = receivers + .map((receiver) => receiver.transferAmount) + .reduce((prev, current) => prev + current, BigInt(0)); + + const { + inputs: udtInputs, + sumInputsCapacity: sumXudtInputsCapacity, + sumAmount, + } = collector.collectUdtInputs({ + liveCells: xudtCells, + needAmount: sumTransferAmount, + }); + let actualInputsCapacity = sumXudtInputsCapacity; + let inputs = udtInputs; + + const xudtCapacity = calculateUdtCellCapacity(fromLock); + const sumXudtCapacity = xudtCapacity * BigInt(receivers.length); + + const outputs: CKBComponents.CellOutput[] = receivers.map((receiver) => ({ + lock: addressToScript(receiver.toAddress), + type: xudtType, + capacity: append0x(xudtCapacity.toString(16)), + })); + const outputsData = receivers.map((receiver) => append0x(u128ToLe(receiver.transferAmount))); + + const txFee = MAX_FEE; + if (sumXudtInputsCapacity < sumXudtCapacity) { + let emptyCells = await collector.getCells({ + lock: fromLock, + }); + if (!emptyCells || emptyCells.length === 0) { + throw new NoLiveCellError('The address has no empty cells'); + } + emptyCells = emptyCells.filter((cell) => !cell.output.type); + const needCapacity = sumXudtCapacity - sumXudtInputsCapacity + xudtCapacity; + const { inputs: emptyInputs, sumInputsCapacity: sumEmptyCapacity } = collector.collectInputs( + emptyCells, + needCapacity, + txFee, + { minCapacity: MIN_CAPACITY }, + ); + inputs = [...inputs, ...emptyInputs]; + actualInputsCapacity += sumEmptyCapacity; + } + + let changeCapacity = actualInputsCapacity - sumXudtCapacity; + if (sumAmount > sumTransferAmount) { + outputs.push({ + lock: fromLock, + type: xudtType, + capacity: append0x(xudtCapacity.toString(16)), + }); + outputsData.push(append0x(u128ToLe(sumAmount - sumTransferAmount))); + changeCapacity -= xudtCapacity; + } + + outputs.push({ + lock: fromLock, + type: xudtType, + capacity: append0x(changeCapacity.toString(16)), + }); + outputsData.push('0x'); + + const emptyWitness = { lock: '', inputType: '', outputType: '' }; + const witnesses = inputs.map((_, index) => (index === 0 ? emptyWitness : '0x')); + + const cellDeps = [getSecp256k1CellDep(isMainnet), getUniqueTypeDep(isMainnet), getXudtDep(isMainnet)]; + + const unsignedTx = { + version: '0x0', + cellDeps, + headerDeps: [], + inputs, + outputs, + outputsData, + witnesses, + }; + + if (txFee === MAX_FEE) { + const txSize = getTransactionSize(unsignedTx) + SECP256K1_WITNESS_LOCK_SIZE; + const estimatedTxFee = calculateTransactionFee(txSize); + changeCapacity -= estimatedTxFee; + unsignedTx.outputs[unsignedTx.outputs.length - 1].capacity = append0x(changeCapacity.toString(16)); + } + + const signedTx = collector.getCkb().signTransaction(CKB_PRIVATE_KEY)(unsignedTx); + const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); + + console.info(`xUDT asset has been minted or transferred and tx hash is ${txHash}`); +}; const XUDT_TOKEN_INFO: RgbppTokenInfo = { decimal: 8, diff --git a/examples/xudt/README.md b/examples/xudt/README.md index 5f671474..b27036b8 100644 --- a/examples/xudt/README.md +++ b/examples/xudt/README.md @@ -2,6 +2,31 @@ The examples for xUDT issuance, mint and transfer on CKB +### How to Start + +Copy the `.env.example` file to `.env`: + +```shell +cd examples/xudt && cp .env.example .env +``` + +Update the configuration values: + +```yaml +# Ture for CKB Mainnet and false for CKB Testnet, the default value is false +IS_MAINNET=false + +# The CKB secp256k1 private key whose format is 32bytes hex string with 0x prefix +CKB_SECP256K1_PRIVATE_KEY=0x-private-key + +# CKB node url which should be matched with IS_MAINNET +CKB_NODE_URL=https://testnet.ckb.dev/rpc + +# CKB indexer url which should be matched with IS_MAINNET +CKB_INDEXER_URL=https://testnet.ckb.dev/indexer + +``` + ### Issue xUDT on CKB ```shell diff --git a/examples/xudt/core/xudt.ts b/examples/xudt/core/xudt.ts deleted file mode 100644 index e1db691e..00000000 --- a/examples/xudt/core/xudt.ts +++ /dev/null @@ -1,233 +0,0 @@ -import { addressToScript, getTransactionSize, scriptToHash } from '@nervosnetwork/ckb-sdk-utils'; -import { - getSecp256k1CellDep, - RgbppTokenInfo, - NoLiveCellError, - calculateUdtCellCapacity, - MAX_FEE, - MIN_CAPACITY, - getXudtTypeScript, - append0x, - getUniqueTypeScript, - u128ToLe, - encodeRgbppTokenInfo, - getXudtDep, - getUniqueTypeDep, - SECP256K1_WITNESS_LOCK_SIZE, - calculateTransactionFee, - generateUniqueTypeArgs, - calculateXudtTokenInfoCellCapacity, - NoXudtLiveCellError, -} from '@rgbpp-sdk/ckb'; -import { CKB_PRIVATE_KEY, ckbAddress, collector, isMainnet } from './env'; - -export interface IssueResult { - txHash: string; - xudtType: CKBComponents.Script; -} - -/** - * issueXudt can be used to issue xUDT assets with unique cell as token info cell. - * @param xudtTotalAmount The xudtTotalAmount specifies the total amount of asset issuance - * @param tokenInfo The xUDT token info which includes decimal, name and symbol - */ -export const issueXudt = async ({ - xudtTotalAmount, - tokenInfo, -}: { - xudtTotalAmount: bigint; - tokenInfo: RgbppTokenInfo; -}): Promise => { - const issueLock = addressToScript(ckbAddress); - - let emptyCells = await collector.getCells({ - lock: issueLock, - }); - if (!emptyCells || emptyCells.length === 0) { - throw new NoLiveCellError('The address has no empty cells'); - } - emptyCells = emptyCells.filter((cell) => !cell.output.type); - - const xudtCapacity = calculateUdtCellCapacity(issueLock); - const xudtInfoCapacity = calculateXudtTokenInfoCellCapacity(tokenInfo, issueLock); - - const txFee = MAX_FEE; - const { inputs, sumInputsCapacity } = collector.collectInputs(emptyCells, xudtCapacity + xudtInfoCapacity, txFee, { - minCapacity: MIN_CAPACITY, - }); - - const xudtType: CKBComponents.Script = { - ...getXudtTypeScript(isMainnet), - args: append0x(scriptToHash(issueLock)), - }; - - console.log('xUDT type script', xudtType); - - let changeCapacity = sumInputsCapacity - xudtCapacity - xudtInfoCapacity; - const outputs: CKBComponents.CellOutput[] = [ - { - lock: issueLock, - type: xudtType, - capacity: append0x(xudtCapacity.toString(16)), - }, - { - lock: issueLock, - type: { - ...getUniqueTypeScript(isMainnet), - args: generateUniqueTypeArgs(inputs[0], 1), - }, - capacity: append0x(xudtInfoCapacity.toString(16)), - }, - { - lock: issueLock, - capacity: append0x(changeCapacity.toString(16)), - }, - ]; - const totalAmount = xudtTotalAmount * BigInt(10 ** tokenInfo.decimal); - const outputsData = [append0x(u128ToLe(totalAmount)), encodeRgbppTokenInfo(tokenInfo), '0x']; - - const emptyWitness = { lock: '', inputType: '', outputType: '' }; - const witnesses = inputs.map((_, index) => (index === 0 ? emptyWitness : '0x')); - - const cellDeps = [getSecp256k1CellDep(isMainnet), getUniqueTypeDep(isMainnet), getXudtDep(isMainnet)]; - - const unsignedTx = { - version: '0x0', - cellDeps, - headerDeps: [], - inputs, - outputs, - outputsData, - witnesses, - }; - - if (txFee === MAX_FEE) { - const txSize = getTransactionSize(unsignedTx) + SECP256K1_WITNESS_LOCK_SIZE; - const estimatedTxFee = calculateTransactionFee(txSize); - changeCapacity -= estimatedTxFee; - unsignedTx.outputs[unsignedTx.outputs.length - 1].capacity = append0x(changeCapacity.toString(16)); - } - - const signedTx = collector.getCkb().signTransaction(CKB_PRIVATE_KEY)(unsignedTx); - const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); - - console.info(`xUDT asset on CKB has been issued and tx hash is ${txHash}`); - - return { txHash, xudtType }; -}; - -export interface XudtTransferParams { - xudtType: CKBComponents.Script; - receivers: { - toAddress: string; - transferAmount: bigint; - }[]; -} - -/** - * transferXudt can be used to mint xUDT assets or transfer xUDT assets. - * @param xudtType The xUDT type script that comes from 1-issue-xudt - * @param receivers The receiver includes toAddress and transferAmount - */ -export const transferXudt = async ({ xudtType, receivers }: XudtTransferParams) => { - const fromLock = addressToScript(ckbAddress); - - const xudtCells = await collector.getCells({ - lock: fromLock, - type: xudtType, - }); - if (!xudtCells || xudtCells.length === 0) { - throw new NoXudtLiveCellError('The address has no xudt cells'); - } - const sumTransferAmount = receivers - .map((receiver) => receiver.transferAmount) - .reduce((prev, current) => prev + current, BigInt(0)); - - const { - inputs: udtInputs, - sumInputsCapacity: sumXudtInputsCapacity, - sumAmount, - } = collector.collectUdtInputs({ - liveCells: xudtCells, - needAmount: sumTransferAmount, - }); - let actualInputsCapacity = sumXudtInputsCapacity; - let inputs = udtInputs; - - const xudtCapacity = calculateUdtCellCapacity(fromLock); - const sumXudtCapacity = xudtCapacity * BigInt(receivers.length); - - const outputs: CKBComponents.CellOutput[] = receivers.map((receiver) => ({ - lock: addressToScript(receiver.toAddress), - type: xudtType, - capacity: append0x(xudtCapacity.toString(16)), - })); - const outputsData = receivers.map((receiver) => append0x(u128ToLe(receiver.transferAmount))); - - const txFee = MAX_FEE; - if (sumXudtInputsCapacity < sumXudtCapacity) { - let emptyCells = await collector.getCells({ - lock: fromLock, - }); - if (!emptyCells || emptyCells.length === 0) { - throw new NoLiveCellError('The address has no empty cells'); - } - emptyCells = emptyCells.filter((cell) => !cell.output.type); - const needCapacity = sumXudtCapacity - sumXudtInputsCapacity + xudtCapacity; - const { inputs: emptyInputs, sumInputsCapacity: sumEmptyCapacity } = collector.collectInputs( - emptyCells, - needCapacity, - txFee, - { minCapacity: MIN_CAPACITY }, - ); - inputs = [...inputs, ...emptyInputs]; - actualInputsCapacity += sumEmptyCapacity; - } - - let changeCapacity = actualInputsCapacity - sumXudtCapacity; - if (sumAmount > sumTransferAmount) { - outputs.push({ - lock: fromLock, - type: xudtType, - capacity: append0x(xudtCapacity.toString(16)), - }); - outputsData.push(append0x(u128ToLe(sumAmount - sumTransferAmount))); - changeCapacity -= xudtCapacity; - } - - outputs.push({ - lock: fromLock, - type: xudtType, - capacity: append0x(changeCapacity.toString(16)), - }); - outputsData.push('0x'); - - const emptyWitness = { lock: '', inputType: '', outputType: '' }; - const witnesses = inputs.map((_, index) => (index === 0 ? emptyWitness : '0x')); - - const cellDeps = [getSecp256k1CellDep(isMainnet), getUniqueTypeDep(isMainnet), getXudtDep(isMainnet)]; - - const unsignedTx = { - version: '0x0', - cellDeps, - headerDeps: [], - inputs, - outputs, - outputsData, - witnesses, - }; - - if (txFee === MAX_FEE) { - const txSize = getTransactionSize(unsignedTx) + SECP256K1_WITNESS_LOCK_SIZE; - const estimatedTxFee = calculateTransactionFee(txSize); - changeCapacity -= estimatedTxFee; - unsignedTx.outputs[unsignedTx.outputs.length - 1].capacity = append0x(changeCapacity.toString(16)); - } - - const signedTx = collector.getCkb().signTransaction(CKB_PRIVATE_KEY)(unsignedTx); - const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); - - console.info(`xUDT asset has been minted or transferred and tx hash is ${txHash}`); - - return txHash; -}; diff --git a/examples/xudt/core/env.ts b/examples/xudt/env.ts similarity index 85% rename from examples/xudt/core/env.ts rename to examples/xudt/env.ts index 6549daa4..26d0ce2d 100644 --- a/examples/xudt/core/env.ts +++ b/examples/xudt/env.ts @@ -2,12 +2,10 @@ import { AddressPrefix, privateKeyToAddress } from '@nervosnetwork/ckb-sdk-utils import { Collector } from '@rgbpp-sdk/ckb'; import dotenv from 'dotenv'; -dotenv.config({ path: __dirname + '/../.env' }); +dotenv.config({ path: __dirname + '/.env' }); export const isMainnet = process.env.IS_MAINNET === 'true' ? true : false; -console.log('IS_MAINNET', process.env.IS_MAINNET); - export const collector = new Collector({ ckbNodeUrl: process.env.CKB_NODE_URL!, ckbIndexerUrl: process.env.CKB_INDEXER_URL!, diff --git a/examples/xudt/package.json b/examples/xudt/package.json index 9583728f..a538c950 100644 --- a/examples/xudt/package.json +++ b/examples/xudt/package.json @@ -5,7 +5,6 @@ "private": true, "type": "commonjs", "scripts": { - "build": "tsc -p tsconfig.build.json", "format": "prettier --write '**/*.ts'", "lint": "tsc && eslint . && prettier --check '**/*.ts'", "lint:fix": "tsc && eslint --fix --ext .ts . && prettier --write '**/*.ts'" diff --git a/examples/xudt/tsconfig.build.json b/examples/xudt/tsconfig.build.json deleted file mode 100644 index 18f21a86..00000000 --- a/examples/xudt/tsconfig.build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "module": "CommonJS", - "rootDir": "src", - "outDir": "lib", - "noEmit": false - }, - "include": ["core/*.ts"], -} From fee341504ac2412b5e4a0c21723520932d0308ec Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Thu, 9 May 2024 16:40:38 +0800 Subject: [PATCH 32/78] refactor: Update examples with new rgbpp packages --- examples/rgbpp/package.json | 7 +++--- examples/rgbpp/spore/4-transfer-spore.ts | 1 - examples/rgbpp/spore/5-leap-spore-to-ckb.ts | 1 - .../rgbpp/spore/6-unlock-btc-time-cell.ts | 3 ++- examples/rgbpp/spore/7-leap-spore-to-btc.ts | 8 ++----- .../rgbpp/spore/launch/2-create-cluster.ts | 15 ++++++------ .../rgbpp/spore/launch/3-create-spores.ts | 23 +++++++++---------- examples/rgbpp/utils/env.ts | 6 ++--- examples/rgbpp/utils/spore.ts | 9 ++------ examples/rgbpp/utils/xudt.ts | 4 ++-- examples/rgbpp/xudt/1-ckb-leap-btc.ts | 3 ++- examples/rgbpp/xudt/launch/2-launch-rgbpp.ts | 5 ++-- .../rgbpp/xudt/launch/3-distribute-rgbpp.ts | 23 +++++++++---------- examples/rgbpp/xudt/local/2-btc-transfer.ts | 6 ++--- examples/rgbpp/xudt/local/3-btc-leap-ckb.ts | 8 +++---- .../xudt/local/4-unlock-btc-time-cell.ts | 3 ++- pnpm-lock.yaml | 3 +++ 17 files changed, 60 insertions(+), 68 deletions(-) diff --git a/examples/rgbpp/package.json b/examples/rgbpp/package.json index 36bdc155..2457ba4f 100644 --- a/examples/rgbpp/package.json +++ b/examples/rgbpp/package.json @@ -12,10 +12,11 @@ "dependencies": { "@exact-realty/multipart-parser": "^1.0.13", "@nervosnetwork/ckb-sdk-utils": "^0.109.1", - "@rgbpp-sdk/btc": "workspace:^", - "@rgbpp-sdk/ckb": "workspace:^", + "@spore-sdk/core": "^0.2.0-beta.6", + "rgbpp": "workspace:^", "@rgbpp-sdk/service": "workspace:^", - "@spore-sdk/core": "^0.2.0-beta.6" + "@rgbpp-sdk/ckb": "workspace:^", + "@rgbpp-sdk/btc": "workspace:^" }, "devDependencies": { "@types/node": "^20.11.28", diff --git a/examples/rgbpp/spore/4-transfer-spore.ts b/examples/rgbpp/spore/4-transfer-spore.ts index 1d76948f..206bed6a 100644 --- a/examples/rgbpp/spore/4-transfer-spore.ts +++ b/examples/rgbpp/spore/4-transfer-spore.ts @@ -25,7 +25,6 @@ const transferSpore = async (params: SporeTransferParams) => { // Use your real BTC UTXO information on the BTC Testnet // rgbppLockArgs: outIndexU32 + btcTxId transferSpore({ - // The spore rgbpp lock args is from 3-create-spore.ts sporeRgbppLockArgs: buildRgbppLockArgs(2, 'd5868dbde4be5e49876b496449df10150c356843afb6f94b08f8d81f394bb350'), toBtcAddress: 'tb1qhp9fh9qsfeyh0yhewgu27ndqhs5qlrqwau28m7', sporeTypeArgs: '0x42898ea77062256f46e8f1b861d526ae47810ecc51ab50477945d5fa90452706', diff --git a/examples/rgbpp/spore/5-leap-spore-to-ckb.ts b/examples/rgbpp/spore/5-leap-spore-to-ckb.ts index baae35de..7492d2a9 100644 --- a/examples/rgbpp/spore/5-leap-spore-to-ckb.ts +++ b/examples/rgbpp/spore/5-leap-spore-to-ckb.ts @@ -25,7 +25,6 @@ const leapSpore = async (params: SporeLeapParams) => { // Use your real BTC UTXO information on the BTC Testnet // rgbppLockArgs: outIndexU32 + btcTxId leapSpore({ - // The spore rgbpp lock args is from 3-create-spore.ts sporeRgbppLockArgs: buildRgbppLockArgs(3, 'd8a31796fbd42c546f6b22014b9b82b16586ce1df81b0e7ca9a552cdc492a0af'), toCkbAddress: 'ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq0e4xk4rmg5jdkn8aams492a7jlg73ue0gc0ddfj', sporeTypeArgs: '0x42898ea77062256f46e8f1b861d526ae47810ecc51ab50477945d5fa90452706', diff --git a/examples/rgbpp/spore/6-unlock-btc-time-cell.ts b/examples/rgbpp/spore/6-unlock-btc-time-cell.ts index 21946eab..0cc0cc98 100644 --- a/examples/rgbpp/spore/6-unlock-btc-time-cell.ts +++ b/examples/rgbpp/spore/6-unlock-btc-time-cell.ts @@ -1,5 +1,6 @@ -import { sendCkbTx, getBtcTimeLockScript, buildSporeBtcTimeCellsSpentTx, signBtcTimeCellSpentTx } from '@rgbpp-sdk/ckb'; +import { buildSporeBtcTimeCellsSpentTx, signBtcTimeCellSpentTx } from 'rgbpp'; import { CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from '../utils'; +import { sendCkbTx, getBtcTimeLockScript } from '@rgbpp-sdk/ckb'; // Warning: Wait at least 6 BTC confirmation blocks to spend the BTC time cells after 4-btc-jump-ckb.ts const unlockSporeBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: string }) => { diff --git a/examples/rgbpp/spore/7-leap-spore-to-btc.ts b/examples/rgbpp/spore/7-leap-spore-to-btc.ts index d8922b1d..7feab176 100644 --- a/examples/rgbpp/spore/7-leap-spore-to-btc.ts +++ b/examples/rgbpp/spore/7-leap-spore-to-btc.ts @@ -1,11 +1,7 @@ import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { - getSecp256k1CellDep, - buildRgbppLockArgs, - getSporeTypeScript, - genLeapSporeFromCkbToBtcRawTx, -} from '@rgbpp-sdk/ckb'; +import { genLeapSporeFromCkbToBtcRawTx } from 'rgbpp'; import { isMainnet, collector, ckbAddress, CKB_PRIVATE_KEY } from '../utils'; +import { buildRgbppLockArgs, getSecp256k1CellDep, getSporeTypeScript } from '@rgbpp-sdk/ckb'; const leapSporeFromCkbToBtc = async ({ outIndex, diff --git a/examples/rgbpp/spore/launch/2-create-cluster.ts b/examples/rgbpp/spore/launch/2-create-cluster.ts index 4eda55e7..e0889953 100644 --- a/examples/rgbpp/spore/launch/2-create-cluster.ts +++ b/examples/rgbpp/spore/launch/2-create-cluster.ts @@ -1,15 +1,14 @@ +import { BtcAssetsApiError, genCreateClusterCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; +import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../utils'; +import { CLUSTER_DATA } from './0-cluster-info'; +import { transactionToHex } from '@rgbpp-sdk/btc'; import { - buildRgbppLockArgs, appendCkbTxWitnesses, - updateCkbTxWithRealBtcTxId, - sendCkbTx, - genCreateClusterCkbVirtualTx, + buildRgbppLockArgs, generateClusterCreateCoBuild, + sendCkbTx, + updateCkbTxWithRealBtcTxId, } from '@rgbpp-sdk/ckb'; -import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; -import { BtcAssetsApiError } from '@rgbpp-sdk/service'; -import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../utils'; -import { CLUSTER_DATA } from './0-cluster-info'; const createCluster = async ({ ownerRgbppLockArgs }: { ownerRgbppLockArgs: string }) => { const ckbVirtualTxResult = await genCreateClusterCkbVirtualTx({ diff --git a/examples/rgbpp/spore/launch/3-create-spores.ts b/examples/rgbpp/spore/launch/3-create-spores.ts index b4deb3cc..b6be8cc5 100644 --- a/examples/rgbpp/spore/launch/3-create-spores.ts +++ b/examples/rgbpp/spore/launch/3-create-spores.ts @@ -1,15 +1,4 @@ -import { - buildRgbppLockArgs, - appendCkbTxWitnesses, - updateCkbTxWithRealBtcTxId, - sendCkbTx, - genCreateSporeCkbVirtualTx, - Hex, - appendIssuerCellToSporesCreate, - generateSporeCreateCoBuild, -} from '@rgbpp-sdk/ckb'; -import { sendRgbppUtxos, transactionToHex, utf8ToBuffer } from '@rgbpp-sdk/btc'; -import { BtcAssetsApiError } from '@rgbpp-sdk/service'; +import { BtcAssetsApiError, genCreateSporeCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; import { RawSporeData } from '@spore-sdk/core'; import { isMainnet, @@ -21,6 +10,16 @@ import { CKB_PRIVATE_KEY, ckbAddress, } from '../../utils'; +import { + Hex, + appendCkbTxWitnesses, + appendIssuerCellToSporesCreate, + buildRgbppLockArgs, + generateSporeCreateCoBuild, + sendCkbTx, + updateCkbTxWithRealBtcTxId, +} from '@rgbpp-sdk/ckb'; +import { transactionToHex, utf8ToBuffer } from '@rgbpp-sdk/btc'; interface Params { clusterRgbppLockArgs: Hex; diff --git a/examples/rgbpp/utils/env.ts b/examples/rgbpp/utils/env.ts index 95cedadc..66f59bbb 100644 --- a/examples/rgbpp/utils/env.ts +++ b/examples/rgbpp/utils/env.ts @@ -1,8 +1,8 @@ import { AddressPrefix, privateKeyToAddress } from '@nervosnetwork/ckb-sdk-utils'; -import { DataSource, ECPair, ECPairInterface, NetworkType, bitcoin } from '@rgbpp-sdk/btc'; -import { Collector } from '@rgbpp-sdk/ckb'; -import { BtcAssetsApi } from '@rgbpp-sdk/service'; +import { DataSource, BtcAssetsApi } from 'rgbpp'; +import { ECPair, ECPairInterface, bitcoin, NetworkType } from '@rgbpp-sdk/btc'; import dotenv from 'dotenv'; +import { Collector } from '@rgbpp-sdk/ckb'; dotenv.config({ path: __dirname + '/../.env' }); diff --git a/examples/rgbpp/utils/spore.ts b/examples/rgbpp/utils/spore.ts index 78807727..fe298b3c 100644 --- a/examples/rgbpp/utils/spore.ts +++ b/examples/rgbpp/utils/spore.ts @@ -1,10 +1,5 @@ -import { - getSporeTypeScript, - Hex, - genTransferSporeCkbVirtualTx, - genLeapSporeFromBtcToCkbVirtualTx, -} from '@rgbpp-sdk/ckb'; -import { sendRgbppUtxos } from '@rgbpp-sdk/btc'; +import { genTransferSporeCkbVirtualTx, genLeapSporeFromBtcToCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; +import { getSporeTypeScript, Hex } from '@rgbpp-sdk/ckb'; import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from './env'; diff --git a/examples/rgbpp/utils/xudt.ts b/examples/rgbpp/utils/xudt.ts index 2799e8f3..05e10a57 100644 --- a/examples/rgbpp/utils/xudt.ts +++ b/examples/rgbpp/utils/xudt.ts @@ -1,7 +1,7 @@ import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { getXudtTypeScript, genBtcTransferCkbVirtualTx, genBtcJumpCkbVirtualTx } from '@rgbpp-sdk/ckb'; +import { getXudtTypeScript } from '@rgbpp-sdk/ckb'; +import { genBtcTransferCkbVirtualTx, genBtcJumpCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; import { isMainnet, collector, btcAddress, btcKeyPair, btcService, btcDataSource } from './env'; -import { sendRgbppUtxos } from '@rgbpp-sdk/btc'; export interface RgbppTransferParams { rgbppLockArgsList: string[]; diff --git a/examples/rgbpp/xudt/1-ckb-leap-btc.ts b/examples/rgbpp/xudt/1-ckb-leap-btc.ts index 337cc230..936909f4 100644 --- a/examples/rgbpp/xudt/1-ckb-leap-btc.ts +++ b/examples/rgbpp/xudt/1-ckb-leap-btc.ts @@ -1,5 +1,6 @@ import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { genCkbJumpBtcVirtualTx, getSecp256k1CellDep, buildRgbppLockArgs, getXudtTypeScript } from '@rgbpp-sdk/ckb'; +import { genCkbJumpBtcVirtualTx } from 'rgbpp'; +import { getSecp256k1CellDep, buildRgbppLockArgs, getXudtTypeScript } from '@rgbpp-sdk/ckb'; import { CKB_PRIVATE_KEY, isMainnet, collector, ckbAddress } from '../utils'; interface LeapToBtcParams { diff --git a/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts b/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts index 9da66519..06f971aa 100644 --- a/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts +++ b/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts @@ -1,15 +1,14 @@ +import { genRgbppLaunchCkbVirtualTx, sendRgbppUtxos, BtcAssetsApiError } from 'rgbpp'; import { buildRgbppLockArgs, - genRgbppLaunchCkbVirtualTx, RgbppTokenInfo, appendCkbTxWitnesses, updateCkbTxWithRealBtcTxId, sendCkbTx, } from '@rgbpp-sdk/ckb'; -import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; -import { BtcAssetsApiError } from '@rgbpp-sdk/service'; import { RGBPP_TOKEN_INFO } from './0-rgbpp-token-info'; import { btcAddress, btcDataSource, btcKeyPair, btcService, collector, isMainnet } from '../../utils'; +import { transactionToHex } from '@rgbpp-sdk/btc'; interface Params { ownerRgbppLockArgs: string; diff --git a/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts b/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts index 9b05ae58..d4dca486 100644 --- a/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts +++ b/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts @@ -1,16 +1,5 @@ import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { - RgbppBtcAddressReceiver, - appendCkbTxWitnesses, - appendIssuerCellToBtcBatchTransfer, - buildRgbppLockArgs, - genBtcBatchTransferCkbVirtualTx, - getXudtTypeScript, - sendCkbTx, - updateCkbTxWithRealBtcTxId, -} from '@rgbpp-sdk/ckb'; -import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; -import { BtcAssetsApiError } from '@rgbpp-sdk/service'; +import { BtcAssetsApiError, genBtcBatchTransferCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; import { RGBPP_TOKEN_INFO } from './0-rgbpp-token-info'; import { isMainnet, @@ -22,6 +11,16 @@ import { CKB_PRIVATE_KEY, ckbAddress, } from '../../utils'; +import { + RgbppBtcAddressReceiver, + appendCkbTxWitnesses, + appendIssuerCellToBtcBatchTransfer, + buildRgbppLockArgs, + getXudtTypeScript, + sendCkbTx, + updateCkbTxWithRealBtcTxId, +} from '@rgbpp-sdk/ckb'; +import { transactionToHex } from '@rgbpp-sdk/btc'; interface Params { rgbppLockArgsList: string[]; diff --git a/examples/rgbpp/xudt/local/2-btc-transfer.ts b/examples/rgbpp/xudt/local/2-btc-transfer.ts index b55bdfa3..719f6803 100644 --- a/examples/rgbpp/xudt/local/2-btc-transfer.ts +++ b/examples/rgbpp/xudt/local/2-btc-transfer.ts @@ -1,14 +1,12 @@ import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; +import { genBtcTransferCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; import { appendCkbTxWitnesses, buildRgbppLockArgs, - genBtcTransferCkbVirtualTx, sendCkbTx, getXudtTypeScript, updateCkbTxWithRealBtcTxId, } from '@rgbpp-sdk/ckb'; -import { transactionToHex, sendRgbppUtxos } from '@rgbpp-sdk/btc'; -import { BtcAssetsApiError } from '@rgbpp-sdk/service'; import { RgbppTransferParams, isMainnet, @@ -18,6 +16,8 @@ import { btcKeyPair, btcService, } from '../../utils'; +import { transactionToHex } from '@rgbpp-sdk/btc'; +import { BtcAssetsApiError } from '@rgbpp-sdk/service'; const transfer = async ({ rgbppLockArgsList, toBtcAddress, xudtTypeArgs, transferAmount }: RgbppTransferParams) => { const xudtType: CKBComponents.Script = { diff --git a/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts b/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts index 0ed7b27d..5f6f3920 100644 --- a/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts +++ b/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts @@ -1,15 +1,15 @@ import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; +import { genBtcJumpCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; import { appendCkbTxWitnesses, - genBtcJumpCkbVirtualTx, + buildRgbppLockArgs, sendCkbTx, getXudtTypeScript, updateCkbTxWithRealBtcTxId, - buildRgbppLockArgs, } from '@rgbpp-sdk/ckb'; -import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; -import { BtcAssetsApiError } from '@rgbpp-sdk/service'; import { LeapToCkbParams, isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../utils'; +import { transactionToHex } from '@rgbpp-sdk/btc'; +import { BtcAssetsApiError } from '@rgbpp-sdk/service'; const leapFromBtcToCkb = async ({ rgbppLockArgsList, toCkbAddress, xudtTypeArgs, transferAmount }: LeapToCkbParams) => { const xudtType: CKBComponents.Script = { diff --git a/examples/rgbpp/xudt/local/4-unlock-btc-time-cell.ts b/examples/rgbpp/xudt/local/4-unlock-btc-time-cell.ts index b297d3a6..dcc46c9c 100644 --- a/examples/rgbpp/xudt/local/4-unlock-btc-time-cell.ts +++ b/examples/rgbpp/xudt/local/4-unlock-btc-time-cell.ts @@ -1,4 +1,5 @@ -import { sendCkbTx, buildBtcTimeCellsSpentTx, getBtcTimeLockScript, signBtcTimeCellSpentTx } from '@rgbpp-sdk/ckb'; +import { buildBtcTimeCellsSpentTx, signBtcTimeCellSpentTx } from 'rgbpp'; +import { sendCkbTx, getBtcTimeLockScript } from '@rgbpp-sdk/ckb'; import { CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from '../../utils'; // Warning: Wait at least 6 BTC confirmation blocks to spend the BTC time cells after 4-btc-jump-ckb.ts diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9fb5deb7..9781ff83 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -154,6 +154,9 @@ importers: '@spore-sdk/core': specifier: ^0.2.0-beta.6 version: 0.2.0-beta.6(@ckb-lumos/lumos@0.22.0-next.5)(lodash@4.17.21) + rgbpp: + specifier: workspace:^ + version: link:../../packages/rgbpp devDependencies: '@types/dotenv': specifier: ^8.2.0 From e0da8dae99d60946dacb9ca60cbc3f1e96931ec0 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Fri, 10 May 2024 13:15:10 +0800 Subject: [PATCH 33/78] docs: Update examples readme --- examples/rgbpp/README.md | 59 ++++++++++++++++++++++++++++++---------- examples/xudt/README.md | 2 +- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/examples/rgbpp/README.md b/examples/rgbpp/README.md index 3e27ce33..27e742cc 100644 --- a/examples/rgbpp/README.md +++ b/examples/rgbpp/README.md @@ -3,10 +3,7 @@ - xUDT directory: The examples for RGB++ UDT issuance, transfer, and leap - Spore directory: The examples for RGB++ Spore creation, transfer and leap - -## RGB++ xUDT Examples with Queue Service - -### How to Start +## How to Start Copy the `.env.example` file to `.env`: @@ -46,34 +43,64 @@ BTC_ASSETS_TOKEN=; BTC_ASSETS_ORIGIN=https://btc-test.app; ``` -### Leap xUDT from CKB to BTC + +## RGB++ xUDT Examples + +### RGB++ xUDT Launch on BTC + +### 1. Prepare Launch + +```shell +npx ts-node example/rgbpp/xudt/launch/1-prepare-launch.ts +``` +### 2. Launch RGB++ xUDT on BTC + +```shell +npx ts-node example/rgbpp/xudt/launch/2-launch-rgbpp.ts +``` +### 3. Distribute RGB++ xUDT on BTC + +```shell +npx ts-node example/rgbpp/xudt/launch/3-distribute-rgbpp.ts +``` + +### RGB++ xUDT Transfer and Leap + +#### 1. Leap xUDT from CKB to BTC ```shell npx ts-node examples/rgbpp/xudt/1-ckb-leap-btc.ts ``` -### Transfer RGB++ xUDT on BTC +#### 2. Transfer RGB++ xUDT on BTC with Queue Service ```shell npx ts-node examples/rgbpp/xudt/2-btc-transfer.ts ``` -### Leap RGB++ xUDT from BTC to CKB +#### 3. Leap RGB++ xUDT from BTC to CKB ```shell npx ts-node examples/rgbpp/xudt/3-btc-jump-ckb.ts ``` -### Unlock xUDT BTC time cells on CKB +#### 4. Unlock xUDT BTC time cells on CKB A cron job in RGB++ Queue service will construct a transaction unlocking the mature BTC time cells to the their `target_ckb_address`. +However, you can still manually unlock the spore BTC time cell through the following command + +Warning: Wait at least 6 BTC confirmation blocks to unlock the BTC time cells after 3-btc-jump-ckb.ts + +```shell +npx ts-node examples/rgbpp/xudt/launch/4-unlock-btc-time.ts +``` ## RGB++ Spore Examples -**You can use RGB++ Queue service to complete spore transfer and leap, and the examples can be found in `examples/rgbpp/spore/queue`** +### Launch Spores on BTC -### Create RGB++ Cluster Cell +#### 1. Create RGB++ Cluster Cell ```shell npx ts-node examples/rgbpp/spore/launch/1-prepare-cluster.ts @@ -81,25 +108,27 @@ npx ts-node examples/rgbpp/spore/launch/1-prepare-cluster.ts npx ts-node examples/rgbpp/spore/launch/2-create-cluster.ts ``` -### Create RGB++ Spores with Cluster on BTC +#### 2. Create RGB++ Spores with Cluster on BTC ```shell npx ts-node examples/rgbpp/spore/launch/3-create-spores.ts ``` -### Transfer RGB++ Spore on BTC with Queue Service +### Transfer and Leap Spore + +#### 1. Transfer RGB++ Spore on BTC with Queue Service ```shell npx ts-node examples/rgbpp/spore/4-transfer-spore.ts ``` -### Leap RGB++ Spore from BTC to CKB +#### 2. Leap RGB++ Spore from BTC to CKB ```shell npx ts-node examples/rgbpp/spore/5-leap-spore-to-ckb.ts ``` -### Unlock Spore BTC time cells on CKB +#### 3. Unlock Spore BTC time cells on CKB A cron job in RGB++ Queue service will construct a transaction unlocking the mature BTC time cells to the their `target_ckb_address`. @@ -111,7 +140,7 @@ However, you can still manually unlock the spore BTC time cell through the follo npx ts-node examples/rgbpp/spore/6-unlock-btc-time-cell.ts ``` -### Leap Spore from CKB to BTC +#### 4. Leap Spore from CKB to BTC ```shell npx ts-node examples/rgbpp/spore/7-leap-spore-to-btc.ts diff --git a/examples/xudt/README.md b/examples/xudt/README.md index b27036b8..2d35ac28 100644 --- a/examples/xudt/README.md +++ b/examples/xudt/README.md @@ -2,7 +2,7 @@ The examples for xUDT issuance, mint and transfer on CKB -### How to Start +## How to Start Copy the `.env.example` file to `.env`: From 55edb5d603ee90cd13a40dea4265af6884e84aee Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Fri, 10 May 2024 13:55:05 +0800 Subject: [PATCH 34/78] refactor: Remove example rgbpp utils --- examples/rgbpp/README.md | 30 ++--- examples/rgbpp/{utils => }/env.ts | 6 +- examples/rgbpp/package.json | 5 +- examples/rgbpp/spore/4-transfer-spore.ts | 50 ++++++++- examples/rgbpp/spore/5-leap-spore-to-ckb.ts | 53 ++++++++- .../rgbpp/spore/6-unlock-btc-time-cell.ts | 4 +- examples/rgbpp/spore/7-leap-spore-to-btc.ts | 4 +- .../rgbpp/spore/launch/1-prepare-cluster.ts | 4 +- .../rgbpp/spore/launch/2-create-cluster.ts | 6 +- .../rgbpp/spore/launch/3-create-spores.ts | 10 +- .../rgbpp/spore/local/4-transfer-spore.ts | 21 ++-- .../rgbpp/spore/local/5-leap-spore-to-ckb.ts | 21 ++-- examples/rgbpp/tsconfig.json | 4 +- examples/rgbpp/utils/index.ts | 3 - examples/rgbpp/utils/spore.ts | 100 ----------------- examples/rgbpp/utils/xudt.ts | 103 ------------------ examples/rgbpp/xudt/1-ckb-leap-btc.ts | 4 +- examples/rgbpp/xudt/2-btc-transfer.ts | 49 ++++++++- examples/rgbpp/xudt/3-btc-leap-ckb.ts | 53 ++++++++- .../{local => }/4-unlock-btc-time-cell.ts | 6 +- .../rgbpp/xudt/launch/0-rgbpp-token-info.ts | 2 +- .../rgbpp/xudt/launch/1-prepare-launch.ts | 4 +- examples/rgbpp/xudt/launch/2-launch-rgbpp.ts | 6 +- .../rgbpp/xudt/launch/3-distribute-rgbpp.ts | 6 +- examples/rgbpp/xudt/local/2-btc-transfer.ts | 25 ++--- examples/rgbpp/xudt/local/3-btc-leap-ckb.ts | 17 ++- examples/xudt/1-issue-xudt.ts | 2 +- examples/xudt/2-transfer-xudt.ts | 2 +- examples/xudt/README.md | 4 +- examples/xudt/env.ts | 2 +- examples/xudt/package.json | 2 +- examples/xudt/tsconfig.json | 4 +- pnpm-lock.yaml | 13 +-- 33 files changed, 289 insertions(+), 336 deletions(-) rename examples/rgbpp/{utils => }/env.ts (89%) delete mode 100644 examples/rgbpp/utils/index.ts delete mode 100644 examples/rgbpp/utils/spore.ts delete mode 100644 examples/rgbpp/utils/xudt.ts rename examples/rgbpp/xudt/{local => }/4-unlock-btc-time-cell.ts (91%) diff --git a/examples/rgbpp/README.md b/examples/rgbpp/README.md index 27e742cc..6db7996c 100644 --- a/examples/rgbpp/README.md +++ b/examples/rgbpp/README.md @@ -51,17 +51,17 @@ BTC_ASSETS_ORIGIN=https://btc-test.app; ### 1. Prepare Launch ```shell -npx ts-node example/rgbpp/xudt/launch/1-prepare-launch.ts +npx ts-node xudt/launch/1-prepare-launch.ts ``` ### 2. Launch RGB++ xUDT on BTC ```shell -npx ts-node example/rgbpp/xudt/launch/2-launch-rgbpp.ts +npx ts-node xudt/launch/2-launch-rgbpp.ts ``` ### 3. Distribute RGB++ xUDT on BTC ```shell -npx ts-node example/rgbpp/xudt/launch/3-distribute-rgbpp.ts +npx ts-node xudt/launch/3-distribute-rgbpp.ts ``` ### RGB++ xUDT Transfer and Leap @@ -69,19 +69,19 @@ npx ts-node example/rgbpp/xudt/launch/3-distribute-rgbpp.ts #### 1. Leap xUDT from CKB to BTC ```shell -npx ts-node examples/rgbpp/xudt/1-ckb-leap-btc.ts +npx ts-node xudt/1-ckb-leap-btc.ts ``` #### 2. Transfer RGB++ xUDT on BTC with Queue Service ```shell -npx ts-node examples/rgbpp/xudt/2-btc-transfer.ts +npx ts-node xudt/2-btc-transfer.ts ``` #### 3. Leap RGB++ xUDT from BTC to CKB ```shell -npx ts-node examples/rgbpp/xudt/3-btc-jump-ckb.ts +npx ts-node xudt/3-btc-jump-ckb.ts ``` #### 4. Unlock xUDT BTC time cells on CKB @@ -93,25 +93,25 @@ However, you can still manually unlock the spore BTC time cell through the follo Warning: Wait at least 6 BTC confirmation blocks to unlock the BTC time cells after 3-btc-jump-ckb.ts ```shell -npx ts-node examples/rgbpp/xudt/launch/4-unlock-btc-time.ts +npx ts-node xudt/launch/4-unlock-btc-time.ts ``` ## RGB++ Spore Examples -### Launch Spores on BTC +### RGB++ Spores Launch on BTC #### 1. Create RGB++ Cluster Cell ```shell -npx ts-node examples/rgbpp/spore/launch/1-prepare-cluster.ts +npx ts-node spore/launch/1-prepare-cluster.ts -npx ts-node examples/rgbpp/spore/launch/2-create-cluster.ts +npx ts-node spore/launch/2-create-cluster.ts ``` #### 2. Create RGB++ Spores with Cluster on BTC ```shell -npx ts-node examples/rgbpp/spore/launch/3-create-spores.ts +npx ts-node spore/launch/3-create-spores.ts ``` ### Transfer and Leap Spore @@ -119,13 +119,13 @@ npx ts-node examples/rgbpp/spore/launch/3-create-spores.ts #### 1. Transfer RGB++ Spore on BTC with Queue Service ```shell -npx ts-node examples/rgbpp/spore/4-transfer-spore.ts +npx ts-node spore/4-transfer-spore.ts ``` #### 2. Leap RGB++ Spore from BTC to CKB ```shell -npx ts-node examples/rgbpp/spore/5-leap-spore-to-ckb.ts +npx ts-node spore/5-leap-spore-to-ckb.ts ``` #### 3. Unlock Spore BTC time cells on CKB @@ -137,13 +137,13 @@ However, you can still manually unlock the spore BTC time cell through the follo **Warning: Wait at least 6 BTC confirmation blocks to unlock the BTC time cells after 5-leap-spore-to-ckb.ts** ```shell -npx ts-node examples/rgbpp/spore/6-unlock-btc-time-cell.ts +npx ts-node spore/6-unlock-btc-time-cell.ts ``` #### 4. Leap Spore from CKB to BTC ```shell -npx ts-node examples/rgbpp/spore/7-leap-spore-to-btc.ts +npx ts-node spore/7-leap-spore-to-btc.ts ``` ## What you must know about BTC transaction id diff --git a/examples/rgbpp/utils/env.ts b/examples/rgbpp/env.ts similarity index 89% rename from examples/rgbpp/utils/env.ts rename to examples/rgbpp/env.ts index 66f59bbb..3cc7ad07 100644 --- a/examples/rgbpp/utils/env.ts +++ b/examples/rgbpp/env.ts @@ -1,10 +1,10 @@ import { AddressPrefix, privateKeyToAddress } from '@nervosnetwork/ckb-sdk-utils'; import { DataSource, BtcAssetsApi } from 'rgbpp'; -import { ECPair, ECPairInterface, bitcoin, NetworkType } from '@rgbpp-sdk/btc'; +import { ECPair, ECPairInterface, bitcoin, NetworkType } from 'rgbpp/btc'; import dotenv from 'dotenv'; -import { Collector } from '@rgbpp-sdk/ckb'; +import { Collector } from 'rgbpp/ckb'; -dotenv.config({ path: __dirname + '/../.env' }); +dotenv.config({ path: __dirname + '/.env' }); export const isMainnet = process.env.IS_MAINNET === 'true' ? true : false; diff --git a/examples/rgbpp/package.json b/examples/rgbpp/package.json index 2457ba4f..7ee224d2 100644 --- a/examples/rgbpp/package.json +++ b/examples/rgbpp/package.json @@ -13,10 +13,7 @@ "@exact-realty/multipart-parser": "^1.0.13", "@nervosnetwork/ckb-sdk-utils": "^0.109.1", "@spore-sdk/core": "^0.2.0-beta.6", - "rgbpp": "workspace:^", - "@rgbpp-sdk/service": "workspace:^", - "@rgbpp-sdk/ckb": "workspace:^", - "@rgbpp-sdk/btc": "workspace:^" + "rgbpp": "workspace:^" }, "devDependencies": { "@types/node": "^20.11.28", diff --git a/examples/rgbpp/spore/4-transfer-spore.ts b/examples/rgbpp/spore/4-transfer-spore.ts index 206bed6a..3a7738a0 100644 --- a/examples/rgbpp/spore/4-transfer-spore.ts +++ b/examples/rgbpp/spore/4-transfer-spore.ts @@ -1,8 +1,50 @@ -import { buildRgbppLockArgs } from '@rgbpp-sdk/ckb'; -import { SporeTransferParams, transferSporeOnBtc, btcService } from '../utils'; +import { buildRgbppLockArgs } from 'rgbpp/ckb'; +import { genTransferSporeCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; +import { getSporeTypeScript, Hex } from 'rgbpp/ckb'; +import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; +import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../env'; + +interface SporeTransferParams { + sporeRgbppLockArgs: Hex; + toBtcAddress: string; + sporeTypeArgs: Hex; +} + +const transferSpore = async ({ sporeRgbppLockArgs, toBtcAddress, sporeTypeArgs }: SporeTransferParams) => { + const sporeTypeBytes = serializeScript({ + ...getSporeTypeScript(isMainnet), + args: sporeTypeArgs, + }); + + const ckbVirtualTxResult = await genTransferSporeCkbVirtualTx({ + collector, + sporeRgbppLockArgs, + sporeTypeBytes, + isMainnet, + }); + + const { commitment, ckbRawTx } = ckbVirtualTxResult; + + // Send BTC tx + const psbt = await sendRgbppUtxos({ + ckbVirtualTx: ckbRawTx, + commitment, + tos: [toBtcAddress], + ckbCollector: collector, + from: btcAddress!, + source: btcDataSource, + feeRate: 30, + }); + psbt.signAllInputs(btcKeyPair); + psbt.finalizeAllInputs(); + + const btcTx = psbt.extractTransaction(); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); + + console.log('BTC TxId: ', btcTxId); + + await btcService.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); -const transferSpore = async (params: SporeTransferParams) => { - const btcTxId = await transferSporeOnBtc(params); try { const interval = setInterval(async () => { const { state, failedReason } = await btcService.getRgbppTransactionState(btcTxId); diff --git a/examples/rgbpp/spore/5-leap-spore-to-ckb.ts b/examples/rgbpp/spore/5-leap-spore-to-ckb.ts index 7492d2a9..c4af4cde 100644 --- a/examples/rgbpp/spore/5-leap-spore-to-ckb.ts +++ b/examples/rgbpp/spore/5-leap-spore-to-ckb.ts @@ -1,8 +1,51 @@ -import { buildRgbppLockArgs } from '@rgbpp-sdk/ckb'; -import { leapSporeToCkb, btcService, SporeLeapParams } from '../utils'; +import { buildRgbppLockArgs } from 'rgbpp/ckb'; +import { genLeapSporeFromBtcToCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; +import { getSporeTypeScript, Hex } from 'rgbpp/ckb'; +import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; +import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../env'; + +interface SporeLeapParams { + sporeRgbppLockArgs: Hex; + toCkbAddress: string; + sporeTypeArgs: Hex; +} + +const leapSporeFromBtcToCkb = async ({ sporeRgbppLockArgs, toCkbAddress, sporeTypeArgs }: SporeLeapParams) => { + const sporeTypeBytes = serializeScript({ + ...getSporeTypeScript(isMainnet), + args: sporeTypeArgs, + }); + + const ckbVirtualTxResult = await genLeapSporeFromBtcToCkbVirtualTx({ + collector, + sporeRgbppLockArgs, + sporeTypeBytes, + toCkbAddress, + isMainnet, + }); + + const { commitment, ckbRawTx } = ckbVirtualTxResult; + + // Send BTC tx + const psbt = await sendRgbppUtxos({ + ckbVirtualTx: ckbRawTx, + commitment, + tos: [btcAddress!], + ckbCollector: collector, + from: btcAddress!, + source: btcDataSource, + feeRate: 30, + }); + psbt.signAllInputs(btcKeyPair); + psbt.finalizeAllInputs(); + + const btcTx = psbt.extractTransaction(); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); + + console.log('BTC TxId: ', btcTxId); + + await btcService.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); -const leapSpore = async (params: SporeLeapParams) => { - const btcTxId = await leapSporeToCkb(params); try { const interval = setInterval(async () => { const { state, failedReason } = await btcService.getRgbppTransactionState(btcTxId); @@ -24,7 +67,7 @@ const leapSpore = async (params: SporeLeapParams) => { // Use your real BTC UTXO information on the BTC Testnet // rgbppLockArgs: outIndexU32 + btcTxId -leapSpore({ +leapSporeFromBtcToCkb({ sporeRgbppLockArgs: buildRgbppLockArgs(3, 'd8a31796fbd42c546f6b22014b9b82b16586ce1df81b0e7ca9a552cdc492a0af'), toCkbAddress: 'ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq0e4xk4rmg5jdkn8aams492a7jlg73ue0gc0ddfj', sporeTypeArgs: '0x42898ea77062256f46e8f1b861d526ae47810ecc51ab50477945d5fa90452706', diff --git a/examples/rgbpp/spore/6-unlock-btc-time-cell.ts b/examples/rgbpp/spore/6-unlock-btc-time-cell.ts index 0cc0cc98..49b9843a 100644 --- a/examples/rgbpp/spore/6-unlock-btc-time-cell.ts +++ b/examples/rgbpp/spore/6-unlock-btc-time-cell.ts @@ -1,6 +1,6 @@ import { buildSporeBtcTimeCellsSpentTx, signBtcTimeCellSpentTx } from 'rgbpp'; -import { CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from '../utils'; -import { sendCkbTx, getBtcTimeLockScript } from '@rgbpp-sdk/ckb'; +import { CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from '../env'; +import { sendCkbTx, getBtcTimeLockScript } from 'rgbpp/ckb'; // Warning: Wait at least 6 BTC confirmation blocks to spend the BTC time cells after 4-btc-jump-ckb.ts const unlockSporeBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: string }) => { diff --git a/examples/rgbpp/spore/7-leap-spore-to-btc.ts b/examples/rgbpp/spore/7-leap-spore-to-btc.ts index 7feab176..c9deb00f 100644 --- a/examples/rgbpp/spore/7-leap-spore-to-btc.ts +++ b/examples/rgbpp/spore/7-leap-spore-to-btc.ts @@ -1,7 +1,7 @@ import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; import { genLeapSporeFromCkbToBtcRawTx } from 'rgbpp'; -import { isMainnet, collector, ckbAddress, CKB_PRIVATE_KEY } from '../utils'; -import { buildRgbppLockArgs, getSecp256k1CellDep, getSporeTypeScript } from '@rgbpp-sdk/ckb'; +import { isMainnet, collector, ckbAddress, CKB_PRIVATE_KEY } from '../env'; +import { buildRgbppLockArgs, getSecp256k1CellDep, getSporeTypeScript } from 'rgbpp/ckb'; const leapSporeFromCkbToBtc = async ({ outIndex, diff --git a/examples/rgbpp/spore/launch/1-prepare-cluster.ts b/examples/rgbpp/spore/launch/1-prepare-cluster.ts index 0aff04fb..128731a5 100644 --- a/examples/rgbpp/spore/launch/1-prepare-cluster.ts +++ b/examples/rgbpp/spore/launch/1-prepare-cluster.ts @@ -9,8 +9,8 @@ import { calculateTransactionFee, genRgbppLockScript, getSecp256k1CellDep, -} from '@rgbpp-sdk/ckb'; -import { ckbAddress, isMainnet, collector, CKB_PRIVATE_KEY } from '../../utils'; +} from 'rgbpp/ckb'; +import { ckbAddress, isMainnet, collector, CKB_PRIVATE_KEY } from '../../env'; import { CLUSTER_DATA } from './0-cluster-info'; const prepareClusterCell = async ({ outIndex, btcTxId }: { outIndex: number; btcTxId: string }) => { diff --git a/examples/rgbpp/spore/launch/2-create-cluster.ts b/examples/rgbpp/spore/launch/2-create-cluster.ts index e0889953..2b2d09a3 100644 --- a/examples/rgbpp/spore/launch/2-create-cluster.ts +++ b/examples/rgbpp/spore/launch/2-create-cluster.ts @@ -1,14 +1,14 @@ import { BtcAssetsApiError, genCreateClusterCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; -import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../utils'; +import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../env'; import { CLUSTER_DATA } from './0-cluster-info'; -import { transactionToHex } from '@rgbpp-sdk/btc'; +import { transactionToHex } from 'rgbpp/btc'; import { appendCkbTxWitnesses, buildRgbppLockArgs, generateClusterCreateCoBuild, sendCkbTx, updateCkbTxWithRealBtcTxId, -} from '@rgbpp-sdk/ckb'; +} from 'rgbpp/ckb'; const createCluster = async ({ ownerRgbppLockArgs }: { ownerRgbppLockArgs: string }) => { const ckbVirtualTxResult = await genCreateClusterCkbVirtualTx({ diff --git a/examples/rgbpp/spore/launch/3-create-spores.ts b/examples/rgbpp/spore/launch/3-create-spores.ts index b6be8cc5..2a5ccb1e 100644 --- a/examples/rgbpp/spore/launch/3-create-spores.ts +++ b/examples/rgbpp/spore/launch/3-create-spores.ts @@ -9,7 +9,7 @@ import { btcService, CKB_PRIVATE_KEY, ckbAddress, -} from '../../utils'; +} from '../../env'; import { Hex, appendCkbTxWitnesses, @@ -18,10 +18,10 @@ import { generateSporeCreateCoBuild, sendCkbTx, updateCkbTxWithRealBtcTxId, -} from '@rgbpp-sdk/ckb'; -import { transactionToHex, utf8ToBuffer } from '@rgbpp-sdk/btc'; +} from 'rgbpp/ckb'; +import { transactionToHex, utf8ToBuffer } from 'rgbpp/btc'; -interface Params { +interface SporeCreateParams { clusterRgbppLockArgs: Hex; receivers: { toBtcAddress: string; @@ -29,7 +29,7 @@ interface Params { }[]; } -const createSpores = async ({ clusterRgbppLockArgs, receivers }: Params) => { +const createSpores = async ({ clusterRgbppLockArgs, receivers }: SporeCreateParams) => { const ckbVirtualTxResult = await genCreateSporeCkbVirtualTx({ collector, sporeDataList: receivers.map((receiver) => receiver.sporeData), diff --git a/examples/rgbpp/spore/local/4-transfer-spore.ts b/examples/rgbpp/spore/local/4-transfer-spore.ts index 4635a81e..369a0a9f 100644 --- a/examples/rgbpp/spore/local/4-transfer-spore.ts +++ b/examples/rgbpp/spore/local/4-transfer-spore.ts @@ -7,21 +7,20 @@ import { Hex, generateSporeTransferCoBuild, genTransferSporeCkbVirtualTx, -} from '@rgbpp-sdk/ckb'; -import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; -import { BtcAssetsApiError } from '@rgbpp-sdk/service'; +} from 'rgbpp/ckb'; +import { sendRgbppUtxos, transactionToHex } from 'rgbpp/btc'; +import { BtcAssetsApiError } from 'rgbpp'; import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../utils'; +import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../env'; -const transferSpore = async ({ - sporeRgbppLockArgs, - toBtcAddress, - sporeTypeArgs, -}: { +interface SporeTransferParams { sporeRgbppLockArgs: Hex; toBtcAddress: string; - sporeTypeArgs: string; -}) => { + sporeTypeArgs: Hex; +} + +// Warning: It is not recommended for developers to use local examples unless you understand the entire process of RGB++ transactions. +const transferSpore = async ({ sporeRgbppLockArgs, toBtcAddress, sporeTypeArgs }: SporeTransferParams) => { // The spore type script is from 3-create-spore.ts, you can find it from the ckb tx spore output cells const sporeTypeBytes = serializeScript({ ...getSporeTypeScript(isMainnet), diff --git a/examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts b/examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts index fc3e2319..5d4cc7a3 100644 --- a/examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts +++ b/examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts @@ -7,21 +7,20 @@ import { Hex, generateSporeTransferCoBuild, genLeapSporeFromBtcToCkbVirtualTx, -} from '@rgbpp-sdk/ckb'; -import { sendRgbppUtxos, transactionToHex } from '@rgbpp-sdk/btc'; -import { BtcAssetsApiError } from '@rgbpp-sdk/service'; +} from 'rgbpp/ckb'; +import { sendRgbppUtxos, transactionToHex } from 'rgbpp/btc'; import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../utils'; +import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../env'; +import { BtcAssetsApiError } from 'rgbpp'; -const transferSpore = async ({ - sporeRgbppLockArgs, - toCkbAddress, - sporeTypeArgs, -}: { +interface SporeLeapParams { sporeRgbppLockArgs: Hex; toCkbAddress: string; sporeTypeArgs: Hex; -}) => { +} + +// Warning: It is not recommended for developers to use local examples unless you understand the entire process of RGB++ transactions. +const leapSpore = async ({ sporeRgbppLockArgs, toCkbAddress, sporeTypeArgs }: SporeLeapParams) => { // The spore type script is from 3-create-spore.ts, you can find it from the ckb tx spore output cells const sporeTypeBytes = serializeScript({ ...getSporeTypeScript(isMainnet), @@ -90,7 +89,7 @@ const transferSpore = async ({ // Use your real BTC UTXO information on the BTC Testnet // rgbppLockArgs: outIndexU32 + btcTxId -transferSpore({ +leapSpore({ // The spore rgbpp lock args is from 3-create-spore.ts sporeRgbppLockArgs: buildRgbppLockArgs(3, 'd8a31796fbd42c546f6b22014b9b82b16586ce1df81b0e7ca9a552cdc492a0af'), toCkbAddress: 'ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq0e4xk4rmg5jdkn8aams492a7jlg73ue0gc0ddfj', diff --git a/examples/rgbpp/tsconfig.json b/examples/rgbpp/tsconfig.json index a610e3f5..b092d7f8 100644 --- a/examples/rgbpp/tsconfig.json +++ b/examples/rgbpp/tsconfig.json @@ -3,7 +3,7 @@ "compilerOptions": { "target": "ES2015", "lib": ["dom", "dom.iterable", "esnext"], - "module": "CommonJS", + "module": "NodeNext", "composite": false, "resolveJsonModule": true, "strictNullChecks": true, @@ -14,7 +14,7 @@ "forceConsistentCasingInFileNames": true, "inlineSources": false, "isolatedModules": true, - "moduleResolution": "node", + "moduleResolution": "NodeNext", "noUnusedLocals": false, "noUnusedParameters": false, "preserveWatchOutput": true, diff --git a/examples/rgbpp/utils/index.ts b/examples/rgbpp/utils/index.ts deleted file mode 100644 index 89e6a8c2..00000000 --- a/examples/rgbpp/utils/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './spore'; -export * from './xudt'; -export * from './env'; diff --git a/examples/rgbpp/utils/spore.ts b/examples/rgbpp/utils/spore.ts deleted file mode 100644 index fe298b3c..00000000 --- a/examples/rgbpp/utils/spore.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { genTransferSporeCkbVirtualTx, genLeapSporeFromBtcToCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; -import { getSporeTypeScript, Hex } from '@rgbpp-sdk/ckb'; -import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from './env'; - -export interface SporeTransferParams { - sporeRgbppLockArgs: Hex; - toBtcAddress: string; - sporeTypeArgs: Hex; -} - -export const transferSporeOnBtc = async ({ - sporeRgbppLockArgs, - toBtcAddress, - sporeTypeArgs, -}: SporeTransferParams): Promise => { - const sporeTypeBytes = serializeScript({ - ...getSporeTypeScript(isMainnet), - args: sporeTypeArgs, - }); - - const ckbVirtualTxResult = await genTransferSporeCkbVirtualTx({ - collector, - sporeRgbppLockArgs, - sporeTypeBytes, - isMainnet, - }); - - const { commitment, ckbRawTx } = ckbVirtualTxResult; - - // Send BTC tx - const psbt = await sendRgbppUtxos({ - ckbVirtualTx: ckbRawTx, - commitment, - tos: [toBtcAddress], - ckbCollector: collector, - from: btcAddress!, - source: btcDataSource, - feeRate: 30, - }); - psbt.signAllInputs(btcKeyPair); - psbt.finalizeAllInputs(); - - const btcTx = psbt.extractTransaction(); - const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); - - console.log('BTC TxId: ', btcTxId); - - await btcService.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); - - return btcTxId; -}; - -export interface SporeLeapParams { - sporeRgbppLockArgs: Hex; - toCkbAddress: string; - sporeTypeArgs: Hex; -} -export const leapSporeToCkb = async ({ - sporeRgbppLockArgs, - toCkbAddress, - sporeTypeArgs, -}: SporeLeapParams): Promise => { - const sporeTypeBytes = serializeScript({ - ...getSporeTypeScript(isMainnet), - args: sporeTypeArgs, - }); - - const ckbVirtualTxResult = await genLeapSporeFromBtcToCkbVirtualTx({ - collector, - sporeRgbppLockArgs, - sporeTypeBytes, - toCkbAddress, - isMainnet, - }); - - const { commitment, ckbRawTx } = ckbVirtualTxResult; - - // Send BTC tx - const psbt = await sendRgbppUtxos({ - ckbVirtualTx: ckbRawTx, - commitment, - tos: [btcAddress!], - ckbCollector: collector, - from: btcAddress!, - source: btcDataSource, - feeRate: 30, - }); - psbt.signAllInputs(btcKeyPair); - psbt.finalizeAllInputs(); - - const btcTx = psbt.extractTransaction(); - const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); - - console.log('BTC TxId: ', btcTxId); - - await btcService.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); - - return btcTxId; -}; diff --git a/examples/rgbpp/utils/xudt.ts b/examples/rgbpp/utils/xudt.ts deleted file mode 100644 index 05e10a57..00000000 --- a/examples/rgbpp/utils/xudt.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { getXudtTypeScript } from '@rgbpp-sdk/ckb'; -import { genBtcTransferCkbVirtualTx, genBtcJumpCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; -import { isMainnet, collector, btcAddress, btcKeyPair, btcService, btcDataSource } from './env'; - -export interface RgbppTransferParams { - rgbppLockArgsList: string[]; - toBtcAddress: string; - xudtTypeArgs: string; - transferAmount: bigint; -} -export const transferRgbppOnBtc = async ({ - rgbppLockArgsList, - toBtcAddress, - xudtTypeArgs, - transferAmount, -}: RgbppTransferParams): Promise => { - const xudtType: CKBComponents.Script = { - ...getXudtTypeScript(isMainnet), - args: xudtTypeArgs, - }; - - const ckbVirtualTxResult = await genBtcTransferCkbVirtualTx({ - collector, - rgbppLockArgsList, - xudtTypeBytes: serializeScript(xudtType), - transferAmount, - isMainnet, - }); - - const { commitment, ckbRawTx } = ckbVirtualTxResult; - - // Send BTC tx - const psbt = await sendRgbppUtxos({ - ckbVirtualTx: ckbRawTx, - commitment, - tos: [toBtcAddress], - ckbCollector: collector, - from: btcAddress!, - source: btcDataSource, - }); - psbt.signAllInputs(btcKeyPair); - psbt.finalizeAllInputs(); - - const btcTx = psbt.extractTransaction(); - const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); - - console.log('BTC TxId: ', btcTxId); - - await btcService.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); - - return btcTxId; -}; - -export interface LeapToCkbParams { - rgbppLockArgsList: string[]; - toCkbAddress: string; - xudtTypeArgs: string; - transferAmount: bigint; -} -export const leapFromBtcToCkb = async ({ - rgbppLockArgsList, - toCkbAddress, - xudtTypeArgs, - transferAmount, -}: LeapToCkbParams): Promise => { - const xudtType: CKBComponents.Script = { - ...getXudtTypeScript(isMainnet), - args: xudtTypeArgs, - }; - - const ckbVirtualTxResult = await genBtcJumpCkbVirtualTx({ - collector, - rgbppLockArgsList, - xudtTypeBytes: serializeScript(xudtType), - transferAmount, - toCkbAddress, - isMainnet, - }); - - const { commitment, ckbRawTx } = ckbVirtualTxResult; - - // Send BTC tx - const psbt = await sendRgbppUtxos({ - ckbVirtualTx: ckbRawTx, - commitment, - tos: [btcAddress!], - ckbCollector: collector, - from: btcAddress!, - source: btcDataSource, - }); - psbt.signAllInputs(btcKeyPair); - psbt.finalizeAllInputs(); - - const btcTx = psbt.extractTransaction(); - const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); - - console.log('BTC TxId: ', btcTxId); - - await btcService.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); - - return btcTxId; -}; diff --git a/examples/rgbpp/xudt/1-ckb-leap-btc.ts b/examples/rgbpp/xudt/1-ckb-leap-btc.ts index 936909f4..aeb221de 100644 --- a/examples/rgbpp/xudt/1-ckb-leap-btc.ts +++ b/examples/rgbpp/xudt/1-ckb-leap-btc.ts @@ -1,7 +1,7 @@ import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; import { genCkbJumpBtcVirtualTx } from 'rgbpp'; -import { getSecp256k1CellDep, buildRgbppLockArgs, getXudtTypeScript } from '@rgbpp-sdk/ckb'; -import { CKB_PRIVATE_KEY, isMainnet, collector, ckbAddress } from '../utils'; +import { getSecp256k1CellDep, buildRgbppLockArgs, getXudtTypeScript } from 'rgbpp/ckb'; +import { CKB_PRIVATE_KEY, isMainnet, collector, ckbAddress } from '../env'; interface LeapToBtcParams { outIndex: number; diff --git a/examples/rgbpp/xudt/2-btc-transfer.ts b/examples/rgbpp/xudt/2-btc-transfer.ts index 358eb4ca..047d8822 100644 --- a/examples/rgbpp/xudt/2-btc-transfer.ts +++ b/examples/rgbpp/xudt/2-btc-transfer.ts @@ -1,8 +1,49 @@ -import { buildRgbppLockArgs } from '@rgbpp-sdk/ckb'; -import { RgbppTransferParams, btcService, transferRgbppOnBtc } from '../utils'; +import { buildRgbppLockArgs, getXudtTypeScript } from 'rgbpp/ckb'; +import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; +import { genBtcTransferCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; +import { isMainnet, collector, btcAddress, btcKeyPair, btcService, btcDataSource } from '../env'; -const transfer = async (params: RgbppTransferParams) => { - const btcTxId = await transferRgbppOnBtc(params); +interface RgbppTransferParams { + rgbppLockArgsList: string[]; + toBtcAddress: string; + xudtTypeArgs: string; + transferAmount: bigint; +} + +const transfer = async ({ rgbppLockArgsList, toBtcAddress, xudtTypeArgs, transferAmount }: RgbppTransferParams) => { + const xudtType: CKBComponents.Script = { + ...getXudtTypeScript(isMainnet), + args: xudtTypeArgs, + }; + + const ckbVirtualTxResult = await genBtcTransferCkbVirtualTx({ + collector, + rgbppLockArgsList, + xudtTypeBytes: serializeScript(xudtType), + transferAmount, + isMainnet, + }); + + const { commitment, ckbRawTx } = ckbVirtualTxResult; + + // Send BTC tx + const psbt = await sendRgbppUtxos({ + ckbVirtualTx: ckbRawTx, + commitment, + tos: [toBtcAddress], + ckbCollector: collector, + from: btcAddress!, + source: btcDataSource, + }); + psbt.signAllInputs(btcKeyPair); + psbt.finalizeAllInputs(); + + const btcTx = psbt.extractTransaction(); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); + + console.log('BTC TxId: ', btcTxId); + + await btcService.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); try { const interval = setInterval(async () => { diff --git a/examples/rgbpp/xudt/3-btc-leap-ckb.ts b/examples/rgbpp/xudt/3-btc-leap-ckb.ts index 655b72e4..406058b3 100644 --- a/examples/rgbpp/xudt/3-btc-leap-ckb.ts +++ b/examples/rgbpp/xudt/3-btc-leap-ckb.ts @@ -1,8 +1,51 @@ -import { buildRgbppLockArgs } from '@rgbpp-sdk/ckb'; -import { LeapToCkbParams, btcService, leapFromBtcToCkb } from '../utils'; +import { buildRgbppLockArgs, getXudtTypeScript } from 'rgbpp/ckb'; +import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; +import { genBtcJumpCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; +import { isMainnet, collector, btcAddress, btcKeyPair, btcService, btcDataSource } from '../env'; + +interface LeapToCkbParams { + rgbppLockArgsList: string[]; + toCkbAddress: string; + xudtTypeArgs: string; + transferAmount: bigint; +} + +const leapFromBtcToCKB = async ({ rgbppLockArgsList, toCkbAddress, xudtTypeArgs, transferAmount }: LeapToCkbParams) => { + const xudtType: CKBComponents.Script = { + ...getXudtTypeScript(isMainnet), + args: xudtTypeArgs, + }; + + const ckbVirtualTxResult = await genBtcJumpCkbVirtualTx({ + collector, + rgbppLockArgsList, + xudtTypeBytes: serializeScript(xudtType), + transferAmount, + toCkbAddress, + isMainnet, + }); + + const { commitment, ckbRawTx } = ckbVirtualTxResult; + + // Send BTC tx + const psbt = await sendRgbppUtxos({ + ckbVirtualTx: ckbRawTx, + commitment, + tos: [btcAddress!], + ckbCollector: collector, + from: btcAddress!, + source: btcDataSource, + }); + psbt.signAllInputs(btcKeyPair); + psbt.finalizeAllInputs(); + + const btcTx = psbt.extractTransaction(); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); + + console.log('BTC TxId: ', btcTxId); + + await btcService.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); -const leapToCKB = async (params: LeapToCkbParams) => { - const btcTxId = await leapFromBtcToCkb(params); try { const interval = setInterval(async () => { const { state, failedReason } = await btcService.getRgbppTransactionState(btcTxId); @@ -23,7 +66,7 @@ const leapToCKB = async (params: LeapToCkbParams) => { }; // rgbppLockArgs: outIndexU32 + btcTxId -leapToCKB({ +leapFromBtcToCKB({ rgbppLockArgsList: [buildRgbppLockArgs(1, '6edd4b9327506fab09fb9a0f5e5f35136a6a94bd4c9dd79af04921618fa6c800')], toCkbAddress: 'ckt1qrfrwcdnvssswdwpn3s9v8fp87emat306ctjwsm3nmlkjg8qyza2cqgqq9kxr7vy7yknezj0vj0xptx6thk6pwyr0sxamv6q', xudtTypeArgs: '0x1ba116c119d1cfd98a53e9d1a615cf2af2bb87d95515c9d217d367054cfc696b', diff --git a/examples/rgbpp/xudt/local/4-unlock-btc-time-cell.ts b/examples/rgbpp/xudt/4-unlock-btc-time-cell.ts similarity index 91% rename from examples/rgbpp/xudt/local/4-unlock-btc-time-cell.ts rename to examples/rgbpp/xudt/4-unlock-btc-time-cell.ts index dcc46c9c..fdf6f87f 100644 --- a/examples/rgbpp/xudt/local/4-unlock-btc-time-cell.ts +++ b/examples/rgbpp/xudt/4-unlock-btc-time-cell.ts @@ -1,6 +1,6 @@ import { buildBtcTimeCellsSpentTx, signBtcTimeCellSpentTx } from 'rgbpp'; -import { sendCkbTx, getBtcTimeLockScript } from '@rgbpp-sdk/ckb'; -import { CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from '../../utils'; +import { sendCkbTx, getBtcTimeLockScript } from 'rgbpp/ckb'; +import { CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from '../env'; // Warning: Wait at least 6 BTC confirmation blocks to spend the BTC time cells after 4-btc-jump-ckb.ts const unlockBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: string }) => { @@ -30,8 +30,6 @@ const unlockBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: string isMainnet, }); - console.log(JSON.stringify(signedTx)); - const txHash = await sendCkbTx({ collector, signedTx }); console.info(`BTC time cell has been spent and tx hash is ${txHash}`); }; diff --git a/examples/rgbpp/xudt/launch/0-rgbpp-token-info.ts b/examples/rgbpp/xudt/launch/0-rgbpp-token-info.ts index 67a7cc39..67354cbf 100644 --- a/examples/rgbpp/xudt/launch/0-rgbpp-token-info.ts +++ b/examples/rgbpp/xudt/launch/0-rgbpp-token-info.ts @@ -1,4 +1,4 @@ -import { RgbppTokenInfo } from '@rgbpp-sdk/ckb'; +import { RgbppTokenInfo } from 'rgbpp/ckb'; export const RGBPP_TOKEN_INFO: RgbppTokenInfo = { decimal: 8, diff --git a/examples/rgbpp/xudt/launch/1-prepare-launch.ts b/examples/rgbpp/xudt/launch/1-prepare-launch.ts index 933049f8..dfd73a92 100644 --- a/examples/rgbpp/xudt/launch/1-prepare-launch.ts +++ b/examples/rgbpp/xudt/launch/1-prepare-launch.ts @@ -11,9 +11,9 @@ import { calculateTransactionFee, genRgbppLockScript, getSecp256k1CellDep, -} from '@rgbpp-sdk/ckb'; +} from 'rgbpp/ckb'; import { RGBPP_TOKEN_INFO } from './0-rgbpp-token-info'; -import { CKB_PRIVATE_KEY, ckbAddress, collector, isMainnet } from '../../utils'; +import { CKB_PRIVATE_KEY, ckbAddress, collector, isMainnet } from '../../env'; const prepareLaunchCell = async ({ outIndex, diff --git a/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts b/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts index 06f971aa..50d751f5 100644 --- a/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts +++ b/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts @@ -5,10 +5,10 @@ import { appendCkbTxWitnesses, updateCkbTxWithRealBtcTxId, sendCkbTx, -} from '@rgbpp-sdk/ckb'; +} from 'rgbpp/ckb'; import { RGBPP_TOKEN_INFO } from './0-rgbpp-token-info'; -import { btcAddress, btcDataSource, btcKeyPair, btcService, collector, isMainnet } from '../../utils'; -import { transactionToHex } from '@rgbpp-sdk/btc'; +import { btcAddress, btcDataSource, btcKeyPair, btcService, collector, isMainnet } from '../../env'; +import { transactionToHex } from 'rgbpp/btc'; interface Params { ownerRgbppLockArgs: string; diff --git a/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts b/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts index d4dca486..b1da9a36 100644 --- a/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts +++ b/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts @@ -10,7 +10,7 @@ import { btcService, CKB_PRIVATE_KEY, ckbAddress, -} from '../../utils'; +} from '../../env'; import { RgbppBtcAddressReceiver, appendCkbTxWitnesses, @@ -19,8 +19,8 @@ import { getXudtTypeScript, sendCkbTx, updateCkbTxWithRealBtcTxId, -} from '@rgbpp-sdk/ckb'; -import { transactionToHex } from '@rgbpp-sdk/btc'; +} from 'rgbpp/ckb'; +import { transactionToHex } from 'rgbpp/btc'; interface Params { rgbppLockArgsList: string[]; diff --git a/examples/rgbpp/xudt/local/2-btc-transfer.ts b/examples/rgbpp/xudt/local/2-btc-transfer.ts index 719f6803..4de9ab89 100644 --- a/examples/rgbpp/xudt/local/2-btc-transfer.ts +++ b/examples/rgbpp/xudt/local/2-btc-transfer.ts @@ -1,24 +1,23 @@ import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { genBtcTransferCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; +import { genBtcTransferCkbVirtualTx, sendRgbppUtxos, BtcAssetsApiError } from 'rgbpp'; import { appendCkbTxWitnesses, buildRgbppLockArgs, sendCkbTx, getXudtTypeScript, updateCkbTxWithRealBtcTxId, -} from '@rgbpp-sdk/ckb'; -import { - RgbppTransferParams, - isMainnet, - collector, - btcAddress, - btcDataSource, - btcKeyPair, - btcService, -} from '../../utils'; -import { transactionToHex } from '@rgbpp-sdk/btc'; -import { BtcAssetsApiError } from '@rgbpp-sdk/service'; +} from 'rgbpp/ckb'; +import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../env'; +import { transactionToHex } from 'rgbpp/btc'; + +interface RgbppTransferParams { + rgbppLockArgsList: string[]; + toBtcAddress: string; + xudtTypeArgs: string; + transferAmount: bigint; +} +// Warning: It is not recommended for developers to use local examples unless you understand the entire process of RGB++ transactions. const transfer = async ({ rgbppLockArgsList, toBtcAddress, xudtTypeArgs, transferAmount }: RgbppTransferParams) => { const xudtType: CKBComponents.Script = { ...getXudtTypeScript(isMainnet), diff --git a/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts b/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts index 5f6f3920..877015ed 100644 --- a/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts +++ b/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts @@ -1,16 +1,23 @@ import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; -import { genBtcJumpCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; +import { genBtcJumpCkbVirtualTx, sendRgbppUtxos, BtcAssetsApiError } from 'rgbpp'; import { appendCkbTxWitnesses, buildRgbppLockArgs, sendCkbTx, getXudtTypeScript, updateCkbTxWithRealBtcTxId, -} from '@rgbpp-sdk/ckb'; -import { LeapToCkbParams, isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../utils'; -import { transactionToHex } from '@rgbpp-sdk/btc'; -import { BtcAssetsApiError } from '@rgbpp-sdk/service'; +} from 'rgbpp/ckb'; +import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../env'; +import { transactionToHex } from 'rgbpp/btc'; +interface LeapToCkbParams { + rgbppLockArgsList: string[]; + toCkbAddress: string; + xudtTypeArgs: string; + transferAmount: bigint; +} + +// Warning: It is not recommended for developers to use local examples unless you understand the entire process of RGB++ transactions. const leapFromBtcToCkb = async ({ rgbppLockArgsList, toCkbAddress, xudtTypeArgs, transferAmount }: LeapToCkbParams) => { const xudtType: CKBComponents.Script = { ...getXudtTypeScript(isMainnet), diff --git a/examples/xudt/1-issue-xudt.ts b/examples/xudt/1-issue-xudt.ts index fb2cddf8..09d9c4b7 100644 --- a/examples/xudt/1-issue-xudt.ts +++ b/examples/xudt/1-issue-xudt.ts @@ -17,7 +17,7 @@ import { calculateTransactionFee, generateUniqueTypeArgs, calculateXudtTokenInfoCellCapacity, -} from '@rgbpp-sdk/ckb'; +} from 'rgbpp/ckb'; import { CKB_PRIVATE_KEY, ckbAddress, collector, isMainnet } from './env'; /** diff --git a/examples/xudt/2-transfer-xudt.ts b/examples/xudt/2-transfer-xudt.ts index 47506e00..65a20cb5 100644 --- a/examples/xudt/2-transfer-xudt.ts +++ b/examples/xudt/2-transfer-xudt.ts @@ -13,7 +13,7 @@ import { SECP256K1_WITNESS_LOCK_SIZE, calculateTransactionFee, NoXudtLiveCellError, -} from '@rgbpp-sdk/ckb'; +} from 'rgbpp/ckb'; import { CKB_PRIVATE_KEY, ckbAddress, collector, isMainnet } from './env'; interface XudtTransferParams { diff --git a/examples/xudt/README.md b/examples/xudt/README.md index 2d35ac28..06a6ec21 100644 --- a/examples/xudt/README.md +++ b/examples/xudt/README.md @@ -30,7 +30,7 @@ CKB_INDEXER_URL=https://testnet.ckb.dev/indexer ### Issue xUDT on CKB ```shell -npx ts-node examples/rgbpp/xudt/1-issue-xudt.ts +npx ts-node 1-issue-xudt.ts ``` ### Mint/Transfer xUDT on CKB @@ -38,5 +38,5 @@ npx ts-node examples/rgbpp/xudt/1-issue-xudt.ts You can use this command to mint or transfer xUDT assets ```shell -npx ts-node examples/rgbpp/xudt/2-transfer-xudt.ts +npx ts-node 2-transfer-xudt.ts ``` diff --git a/examples/xudt/env.ts b/examples/xudt/env.ts index 26d0ce2d..7cf52cd7 100644 --- a/examples/xudt/env.ts +++ b/examples/xudt/env.ts @@ -1,5 +1,5 @@ import { AddressPrefix, privateKeyToAddress } from '@nervosnetwork/ckb-sdk-utils'; -import { Collector } from '@rgbpp-sdk/ckb'; +import { Collector } from 'rgbpp/ckb'; import dotenv from 'dotenv'; dotenv.config({ path: __dirname + '/.env' }); diff --git a/examples/xudt/package.json b/examples/xudt/package.json index a538c950..1697b172 100644 --- a/examples/xudt/package.json +++ b/examples/xudt/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@nervosnetwork/ckb-sdk-utils": "^0.109.1", - "@rgbpp-sdk/ckb": "workspace:^" + "rgbpp": "workspace:^" }, "devDependencies": { "dotenv": "^16.4.5", diff --git a/examples/xudt/tsconfig.json b/examples/xudt/tsconfig.json index 41f00618..4cc7c200 100644 --- a/examples/xudt/tsconfig.json +++ b/examples/xudt/tsconfig.json @@ -3,7 +3,7 @@ "compilerOptions": { "target": "ES2015", "lib": ["dom", "dom.iterable", "esnext"], - "module": "CommonJS", + "module": "NodeNext", "composite": false, "resolveJsonModule": true, "strictNullChecks": true, @@ -14,7 +14,7 @@ "forceConsistentCasingInFileNames": true, "inlineSources": false, "isolatedModules": true, - "moduleResolution": "node", + "moduleResolution": "NodeNext", "noUnusedLocals": false, "noUnusedParameters": false, "preserveWatchOutput": true, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9781ff83..15cdd98e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -142,15 +142,6 @@ importers: '@nervosnetwork/ckb-sdk-utils': specifier: ^0.109.1 version: 0.109.1 - '@rgbpp-sdk/btc': - specifier: workspace:^ - version: link:../../packages/btc - '@rgbpp-sdk/ckb': - specifier: workspace:^ - version: link:../../packages/ckb - '@rgbpp-sdk/service': - specifier: workspace:^ - version: link:../../packages/service '@spore-sdk/core': specifier: ^0.2.0-beta.6 version: 0.2.0-beta.6(@ckb-lumos/lumos@0.22.0-next.5)(lodash@4.17.21) @@ -176,9 +167,9 @@ importers: '@nervosnetwork/ckb-sdk-utils': specifier: ^0.109.1 version: 0.109.1 - '@rgbpp-sdk/ckb': + rgbpp: specifier: workspace:^ - version: link:../../packages/ckb + version: link:../../packages/rgbpp devDependencies: '@types/dotenv': specifier: ^8.2.0 From bc34d9a3628286d4070203f84d9b5539d7f619b5 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Fri, 10 May 2024 16:06:12 +0800 Subject: [PATCH 35/78] feat: Import rgbpp package v0.1.0 for examples --- examples/rgbpp/package.json | 2 +- examples/xudt/package.json | 2 +- pnpm-lock.yaml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/rgbpp/package.json b/examples/rgbpp/package.json index 7ee224d2..2e0e4279 100644 --- a/examples/rgbpp/package.json +++ b/examples/rgbpp/package.json @@ -13,7 +13,7 @@ "@exact-realty/multipart-parser": "^1.0.13", "@nervosnetwork/ckb-sdk-utils": "^0.109.1", "@spore-sdk/core": "^0.2.0-beta.6", - "rgbpp": "workspace:^" + "rgbpp": "0.1.0" }, "devDependencies": { "@types/node": "^20.11.28", diff --git a/examples/xudt/package.json b/examples/xudt/package.json index 1697b172..dc1be38d 100644 --- a/examples/xudt/package.json +++ b/examples/xudt/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@nervosnetwork/ckb-sdk-utils": "^0.109.1", - "rgbpp": "workspace:^" + "rgbpp": "0.1.0" }, "devDependencies": { "dotenv": "^16.4.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 15cdd98e..f325b088 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -146,7 +146,7 @@ importers: specifier: ^0.2.0-beta.6 version: 0.2.0-beta.6(@ckb-lumos/lumos@0.22.0-next.5)(lodash@4.17.21) rgbpp: - specifier: workspace:^ + specifier: 0.1.0 version: link:../../packages/rgbpp devDependencies: '@types/dotenv': @@ -168,7 +168,7 @@ importers: specifier: ^0.109.1 version: 0.109.1 rgbpp: - specifier: workspace:^ + specifier: 0.1.0 version: link:../../packages/rgbpp devDependencies: '@types/dotenv': From dd898489f4aa6e63ab7dce7414277c9964d49527 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Fri, 10 May 2024 16:24:02 +0800 Subject: [PATCH 36/78] feat: Export RawClusterData and RawSporeData from ckb package --- examples/rgbpp/README.md | 8 ++++---- examples/rgbpp/package.json | 4 +--- examples/rgbpp/spore/launch/0-cluster-info.ts | 4 +++- examples/rgbpp/spore/launch/3-create-spores.ts | 2 +- packages/ckb/src/spore/index.ts | 2 ++ pnpm-lock.yaml | 8 +------- 6 files changed, 12 insertions(+), 16 deletions(-) diff --git a/examples/rgbpp/README.md b/examples/rgbpp/README.md index 6db7996c..4560aa14 100644 --- a/examples/rgbpp/README.md +++ b/examples/rgbpp/README.md @@ -78,10 +78,10 @@ npx ts-node xudt/1-ckb-leap-btc.ts npx ts-node xudt/2-btc-transfer.ts ``` -#### 3. Leap RGB++ xUDT from BTC to CKB +#### 3. Leap RGB++ xUDT from BTC to CKB with Queue Service ```shell -npx ts-node xudt/3-btc-jump-ckb.ts +npx ts-node xudt/3-btc-leap-ckb.ts ``` #### 4. Unlock xUDT BTC time cells on CKB @@ -90,7 +90,7 @@ A cron job in RGB++ Queue service will construct a transaction unlocking the mat However, you can still manually unlock the spore BTC time cell through the following command -Warning: Wait at least 6 BTC confirmation blocks to unlock the BTC time cells after 3-btc-jump-ckb.ts +Warning: Wait at least 6 BTC confirmation blocks to unlock the BTC time cells after 3-btc-leap-ckb.ts ```shell npx ts-node xudt/launch/4-unlock-btc-time.ts @@ -167,4 +167,4 @@ But when you're searching for this transaction in [Bitcoin Core](https://bitcoin ``` 018025fb6989eed484774170eefa2bef1074b0c24537f992a64dbc138277bc4a -``` \ No newline at end of file +``` diff --git a/examples/rgbpp/package.json b/examples/rgbpp/package.json index 2e0e4279..9131267f 100644 --- a/examples/rgbpp/package.json +++ b/examples/rgbpp/package.json @@ -10,10 +10,8 @@ "lint:fix": "tsc && eslint --fix --ext .js,.ts . && prettier --write '**/*.{js,ts}'" }, "dependencies": { - "@exact-realty/multipart-parser": "^1.0.13", "@nervosnetwork/ckb-sdk-utils": "^0.109.1", - "@spore-sdk/core": "^0.2.0-beta.6", - "rgbpp": "0.1.0" + "rgbpp": "workspace:*" }, "devDependencies": { "@types/node": "^20.11.28", diff --git a/examples/rgbpp/spore/launch/0-cluster-info.ts b/examples/rgbpp/spore/launch/0-cluster-info.ts index 4ad3c354..cd89d711 100644 --- a/examples/rgbpp/spore/launch/0-cluster-info.ts +++ b/examples/rgbpp/spore/launch/0-cluster-info.ts @@ -1,4 +1,6 @@ -export const CLUSTER_DATA = { +import { RawClusterData } from 'rgbpp/ckb'; + +export const CLUSTER_DATA: RawClusterData = { name: 'Cluster name', description: 'Description of the cluster', }; diff --git a/examples/rgbpp/spore/launch/3-create-spores.ts b/examples/rgbpp/spore/launch/3-create-spores.ts index 2a5ccb1e..b30e5725 100644 --- a/examples/rgbpp/spore/launch/3-create-spores.ts +++ b/examples/rgbpp/spore/launch/3-create-spores.ts @@ -1,5 +1,4 @@ import { BtcAssetsApiError, genCreateSporeCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; -import { RawSporeData } from '@spore-sdk/core'; import { isMainnet, collector, @@ -18,6 +17,7 @@ import { generateSporeCreateCoBuild, sendCkbTx, updateCkbTxWithRealBtcTxId, + RawSporeData, } from 'rgbpp/ckb'; import { transactionToHex, utf8ToBuffer } from 'rgbpp/btc'; diff --git a/packages/ckb/src/spore/index.ts b/packages/ckb/src/spore/index.ts index 0dde8337..c257a082 100644 --- a/packages/ckb/src/spore/index.ts +++ b/packages/ckb/src/spore/index.ts @@ -1,3 +1,5 @@ +export type { RawSporeData, RawClusterData } from '@spore-sdk/core'; + export * from './cluster'; export * from './spore'; export * from './leap'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f325b088..659e1255 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -136,17 +136,11 @@ importers: examples/rgbpp: dependencies: - '@exact-realty/multipart-parser': - specifier: ^1.0.13 - version: 1.0.13 '@nervosnetwork/ckb-sdk-utils': specifier: ^0.109.1 version: 0.109.1 - '@spore-sdk/core': - specifier: ^0.2.0-beta.6 - version: 0.2.0-beta.6(@ckb-lumos/lumos@0.22.0-next.5)(lodash@4.17.21) rgbpp: - specifier: 0.1.0 + specifier: workspace:* version: link:../../packages/rgbpp devDependencies: '@types/dotenv': From 002d3f4b4fdc756062b7917a00e2492d11941665 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Fri, 10 May 2024 18:22:48 +0800 Subject: [PATCH 37/78] refactor: Update examples variable names --- examples/rgbpp/.env.example | 6 +++--- examples/rgbpp/README.md | 6 +++--- examples/rgbpp/env.ts | 8 ++++---- examples/xudt/.env.example | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/rgbpp/.env.example b/examples/rgbpp/.env.example index 950024fd..5fcc170e 100644 --- a/examples/rgbpp/.env.example +++ b/examples/rgbpp/.env.example @@ -19,10 +19,10 @@ CKB_INDEXER_URL=https://testnet.ckb.dev/indexer BTC_PRIVATE_KEY=private-key # The BTC assets api url which should be matched with IS_MAINNET -BTC_ASSETS_API_URL=https://btc-assets-api.testnet.mibao.pro; +VITE_BTC_SERVICE_URL=https://btc-assets-api.testnet.mibao.pro; # The BTC assets api token which should be matched with IS_MAINNET -BTC_ASSETS_TOKEN=; +VITE_BTC_SERVICE_TOKEN=; # The BTC assets api origin which should be matched with IS_MAINNET -BTC_ASSETS_ORIGIN=https://btc-test.app; \ No newline at end of file +VITE_BTC_SERVICE_ORIGIN=https://btc-test.app; diff --git a/examples/rgbpp/README.md b/examples/rgbpp/README.md index 4560aa14..bef1d600 100644 --- a/examples/rgbpp/README.md +++ b/examples/rgbpp/README.md @@ -34,13 +34,13 @@ CKB_INDEXER_URL=https://testnet.ckb.dev/indexer BTC_PRIVATE_KEY=private-key # The BTC assets api url which should be matched with IS_MAINNET -BTC_ASSETS_API_URL=https://btc-assets-api.testnet.mibao.pro; +VITE_BTC_SERVICE_URL=https://btc-assets-api.testnet.mibao.pro; # The BTC assets api token which should be matched with IS_MAINNET -BTC_ASSETS_TOKEN=; +VITE_BTC_SERVICE_TOKEN=; # The BTC assets api origin which should be matched with IS_MAINNET -BTC_ASSETS_ORIGIN=https://btc-test.app; +VITE_BTC_SERVICE_ORIGIN=https://btc-test.app; ``` diff --git a/examples/rgbpp/env.ts b/examples/rgbpp/env.ts index 3cc7ad07..fd50a805 100644 --- a/examples/rgbpp/env.ts +++ b/examples/rgbpp/env.ts @@ -18,9 +18,9 @@ export const ckbAddress = privateKeyToAddress(CKB_PRIVATE_KEY, { }); export const BTC_PRIVATE_KEY = process.env.BTC_PRIVATE_KEY!; -export const BTC_ASSETS_API_URL = process.env.BTC_ASSETS_API_URL!; -export const BTC_ASSETS_TOKEN = process.env.BTC_ASSETS_TOKEN!; -export const BTC_ASSETS_ORIGIN = process.env.BTC_ASSETS_ORIGIN!; +export const BTC_SERVICE_URL = process.env.VITE_BTC_SERVICE_URL!; +export const BTC_SERVICE_TOKEN = process.env.VITE_BTC_SERVICE_TOKEN!; +export const BTC_SERVICE_ORIGIN = process.env.VITE_BTC_SERVICE_ORIGIN!; const network = isMainnet ? bitcoin.networks.bitcoin : bitcoin.networks.testnet; export const btcKeyPair: ECPairInterface = ECPair.fromPrivateKey(Buffer.from(BTC_PRIVATE_KEY, 'hex'), { network }); @@ -30,5 +30,5 @@ export const { address: btcAddress } = bitcoin.payments.p2wpkh({ }); const networkType = isMainnet ? NetworkType.MAINNET : NetworkType.TESTNET; -export const btcService = BtcAssetsApi.fromToken(BTC_ASSETS_API_URL, BTC_ASSETS_TOKEN, BTC_ASSETS_ORIGIN); +export const btcService = BtcAssetsApi.fromToken(BTC_SERVICE_URL, BTC_SERVICE_TOKEN, BTC_SERVICE_ORIGIN); export const btcDataSource = new DataSource(btcService, networkType); diff --git a/examples/xudt/.env.example b/examples/xudt/.env.example index 2b7d3adc..05aa5a77 100644 --- a/examples/xudt/.env.example +++ b/examples/xudt/.env.example @@ -8,4 +8,4 @@ CKB_SECP256K1_PRIVATE_KEY=0x-private-key CKB_NODE_URL=https://testnet.ckb.dev/rpc # CKB indexer url which should be matched with IS_MAINNET -CKB_INDEXER_URL=https://testnet.ckb.dev/indexer \ No newline at end of file +CKB_INDEXER_URL=https://testnet.ckb.dev/indexer From c918f260559779f6e0d7aa5fdab4c79a79e222e5 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Sat, 11 May 2024 17:13:01 +0800 Subject: [PATCH 38/78] style: Remove semicolon of .env.example --- examples/rgbpp/.env.example | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/rgbpp/.env.example b/examples/rgbpp/.env.example index 5fcc170e..f1843bec 100644 --- a/examples/rgbpp/.env.example +++ b/examples/rgbpp/.env.example @@ -19,10 +19,10 @@ CKB_INDEXER_URL=https://testnet.ckb.dev/indexer BTC_PRIVATE_KEY=private-key # The BTC assets api url which should be matched with IS_MAINNET -VITE_BTC_SERVICE_URL=https://btc-assets-api.testnet.mibao.pro; +VITE_BTC_SERVICE_URL=https://btc-assets-api.testnet.mibao.pro # The BTC assets api token which should be matched with IS_MAINNET -VITE_BTC_SERVICE_TOKEN=; +VITE_BTC_SERVICE_TOKEN= # The BTC assets api origin which should be matched with IS_MAINNET -VITE_BTC_SERVICE_ORIGIN=https://btc-test.app; +VITE_BTC_SERVICE_ORIGIN=https://btc-test.app From d9a276915d92cae1ef1ae3ace47f8f844b058429 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Tue, 14 May 2024 15:42:20 +0800 Subject: [PATCH 39/78] Update examples/xudt/.env.example Co-authored-by: Flouse <1297478+Flouse@users.noreply.github.com> --- examples/xudt/.env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/xudt/.env.example b/examples/xudt/.env.example index 05aa5a77..3f2ce3bf 100644 --- a/examples/xudt/.env.example +++ b/examples/xudt/.env.example @@ -1,4 +1,4 @@ -# Ture for CKB Mainnet and false for CKB Testnet, the default value is false +# True for CKB Mainnet and false for CKB Testnet, the default value is false IS_MAINNET=false # The CKB secp256k1 private key whose format is 32bytes hex string with 0x prefix From ec6fde2d6b8478cd2459c8e0c7cfb703d4ad58f9 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Tue, 14 May 2024 16:52:13 +0800 Subject: [PATCH 40/78] refactor: Update xudt examples and readme --- examples/rgbpp/.env.example | 3 ++- examples/rgbpp/README.md | 11 ++++++----- examples/{xudt => xudt-on-ckb}/.env.example | 0 examples/{xudt => xudt-on-ckb}/1-issue-xudt.ts | 0 examples/{xudt => xudt-on-ckb}/2-transfer-xudt.ts | 0 examples/{xudt => xudt-on-ckb}/README.md | 2 +- examples/{xudt => xudt-on-ckb}/env.ts | 0 examples/{xudt => xudt-on-ckb}/package.json | 2 +- examples/{xudt => xudt-on-ckb}/tsconfig.json | 0 pnpm-lock.yaml | 2 +- 10 files changed, 11 insertions(+), 9 deletions(-) rename examples/{xudt => xudt-on-ckb}/.env.example (100%) rename examples/{xudt => xudt-on-ckb}/1-issue-xudt.ts (100%) rename examples/{xudt => xudt-on-ckb}/2-transfer-xudt.ts (100%) rename examples/{xudt => xudt-on-ckb}/README.md (92%) rename examples/{xudt => xudt-on-ckb}/env.ts (100%) rename examples/{xudt => xudt-on-ckb}/package.json (93%) rename examples/{xudt => xudt-on-ckb}/tsconfig.json (100%) diff --git a/examples/rgbpp/.env.example b/examples/rgbpp/.env.example index f1843bec..281dcbcf 100644 --- a/examples/rgbpp/.env.example +++ b/examples/rgbpp/.env.example @@ -1,4 +1,4 @@ -# Ture for CKB and BTC Mainnet and false for CKB and BTC Testnet, the default value is false +# True for CKB and BTC Mainnet and false for CKB and BTC Testnet, the default value is false IS_MAINNET=false # CKB Variables @@ -22,6 +22,7 @@ BTC_PRIVATE_KEY=private-key VITE_BTC_SERVICE_URL=https://btc-assets-api.testnet.mibao.pro # The BTC assets api token which should be matched with IS_MAINNET +# To get an access token, please refer to https://github.com/ckb-cell/rgbpp-sdk/tree/develop/packages/service#get-an-access-token VITE_BTC_SERVICE_TOKEN= # The BTC assets api origin which should be matched with IS_MAINNET diff --git a/examples/rgbpp/README.md b/examples/rgbpp/README.md index bef1d600..af072c7d 100644 --- a/examples/rgbpp/README.md +++ b/examples/rgbpp/README.md @@ -14,7 +14,7 @@ cd examples/rgbpp && cp .env.example .env Update the configuration values: ```yaml -# Ture for CKB and BTC Mainnet and false for CKB and BTC Testnet, the default value is false +# True for CKB and BTC Mainnet and false for CKB and BTC Testnet, the default value is false IS_MAINNET=false # CKB Variables @@ -37,6 +37,7 @@ BTC_PRIVATE_KEY=private-key VITE_BTC_SERVICE_URL=https://btc-assets-api.testnet.mibao.pro; # The BTC assets api token which should be matched with IS_MAINNET +# To get an access token, please refer to https://github.com/ckb-cell/rgbpp-sdk/tree/develop/packages/service#get-an-access-token VITE_BTC_SERVICE_TOKEN=; # The BTC assets api origin which should be matched with IS_MAINNET @@ -48,17 +49,17 @@ VITE_BTC_SERVICE_ORIGIN=https://btc-test.app; ### RGB++ xUDT Launch on BTC -### 1. Prepare Launch +#### 1. Prepare Launch ```shell npx ts-node xudt/launch/1-prepare-launch.ts ``` -### 2. Launch RGB++ xUDT on BTC +#### 2. Launch RGB++ xUDT on BTC ```shell npx ts-node xudt/launch/2-launch-rgbpp.ts ``` -### 3. Distribute RGB++ xUDT on BTC +#### 3. Distribute RGB++ xUDT on BTC ```shell npx ts-node xudt/launch/3-distribute-rgbpp.ts @@ -93,7 +94,7 @@ However, you can still manually unlock the spore BTC time cell through the follo Warning: Wait at least 6 BTC confirmation blocks to unlock the BTC time cells after 3-btc-leap-ckb.ts ```shell -npx ts-node xudt/launch/4-unlock-btc-time.ts +npx ts-node xudt/4-unlock-btc-time.ts ``` ## RGB++ Spore Examples diff --git a/examples/xudt/.env.example b/examples/xudt-on-ckb/.env.example similarity index 100% rename from examples/xudt/.env.example rename to examples/xudt-on-ckb/.env.example diff --git a/examples/xudt/1-issue-xudt.ts b/examples/xudt-on-ckb/1-issue-xudt.ts similarity index 100% rename from examples/xudt/1-issue-xudt.ts rename to examples/xudt-on-ckb/1-issue-xudt.ts diff --git a/examples/xudt/2-transfer-xudt.ts b/examples/xudt-on-ckb/2-transfer-xudt.ts similarity index 100% rename from examples/xudt/2-transfer-xudt.ts rename to examples/xudt-on-ckb/2-transfer-xudt.ts diff --git a/examples/xudt/README.md b/examples/xudt-on-ckb/README.md similarity index 92% rename from examples/xudt/README.md rename to examples/xudt-on-ckb/README.md index 06a6ec21..5e3d4afb 100644 --- a/examples/xudt/README.md +++ b/examples/xudt-on-ckb/README.md @@ -13,7 +13,7 @@ cd examples/xudt && cp .env.example .env Update the configuration values: ```yaml -# Ture for CKB Mainnet and false for CKB Testnet, the default value is false +# True for CKB Mainnet and false for CKB Testnet, the default value is false IS_MAINNET=false # The CKB secp256k1 private key whose format is 32bytes hex string with 0x prefix diff --git a/examples/xudt/env.ts b/examples/xudt-on-ckb/env.ts similarity index 100% rename from examples/xudt/env.ts rename to examples/xudt-on-ckb/env.ts diff --git a/examples/xudt/package.json b/examples/xudt-on-ckb/package.json similarity index 93% rename from examples/xudt/package.json rename to examples/xudt-on-ckb/package.json index dc1be38d..e44b806e 100644 --- a/examples/xudt/package.json +++ b/examples/xudt-on-ckb/package.json @@ -1,5 +1,5 @@ { - "name": "xudt-examples", + "name": "xudt-on-ckb-examples", "version": "0.1.0", "description": "Examples used for xUDT on CKB assets issuance and transfer", "private": true, diff --git a/examples/xudt/tsconfig.json b/examples/xudt-on-ckb/tsconfig.json similarity index 100% rename from examples/xudt/tsconfig.json rename to examples/xudt-on-ckb/tsconfig.json diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 659e1255..a22cbfef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -156,7 +156,7 @@ importers: specifier: ^5.4.2 version: 5.4.2 - examples/xudt: + examples/xudt-on-ckb: dependencies: '@nervosnetwork/ckb-sdk-utils': specifier: ^0.109.1 From 3610f7c1b37753377196dee4b8c380cc97615e49 Mon Sep 17 00:00:00 2001 From: Shook Date: Tue, 14 May 2024 18:30:03 +0800 Subject: [PATCH 41/78] refactor: improve readability of "if statement" in service requests --- packages/service/src/service/base.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/service/src/service/base.ts b/packages/service/src/service/base.ts index b8bab5cd..3007cc88 100644 --- a/packages/service/src/service/base.ts +++ b/packages/service/src/service/base.ts @@ -96,7 +96,7 @@ export class BtcAssetsApiBase implements BaseApis { if (status !== 200 && status !== 404 && !allow404) { throw BtcAssetsApiError.withComment(ErrorCodes.ASSETS_API_RESPONSE_ERROR, comment, context); } - if (status !== 200) { + if (status === 404 && allow404) { return undefined as T; } From 4c68107d6329a804aaab8b2abb9eb11594cd93f0 Mon Sep 17 00:00:00 2001 From: Shook Date: Tue, 14 May 2024 18:33:24 +0800 Subject: [PATCH 42/78] refactor: improve readability of the service fetch params --- packages/service/src/service/base.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/service/src/service/base.ts b/packages/service/src/service/base.ts index 3007cc88..5abf1453 100644 --- a/packages/service/src/service/base.ts +++ b/packages/service/src/service/base.ts @@ -32,15 +32,14 @@ export class BtcAssetsApiBase implements BaseApis { await this.init(); } - const packedParams = params ? '?' + new URLSearchParams(pickBy(params, (val) => val !== undefined)).toString() : ''; - const withOriginHeaders = this.origin ? { origin: this.origin } : undefined; - const withAuthHeaders = requireToken && this.token ? { Authorization: `Bearer ${this.token}` } : undefined; + const pickedParams = pickBy(params, (val) => val !== undefined); + const packedParams = params ? '?' + new URLSearchParams(pickedParams).toString() : ''; const url = `${this.url}${route}${packedParams}`; const res = await fetch(url, { method, headers: { - ...withOriginHeaders, - ...withAuthHeaders, + authorization: this.token ? `Bearer ${this.token}` : undefined, + origin: this.origin, ...headers, }, ...otherOptions, From a3e4a819e2591a72dc7612cad25bf382ff33d5bc Mon Sep 17 00:00:00 2001 From: Shook Date: Tue, 14 May 2024 19:17:10 +0800 Subject: [PATCH 43/78] chore: set service tests timeout to 20 sec --- packages/service/vitest.config.mts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/service/vitest.config.mts b/packages/service/vitest.config.mts index 2d9b2ac0..69b2c0b4 100644 --- a/packages/service/vitest.config.mts +++ b/packages/service/vitest.config.mts @@ -3,7 +3,7 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { watch: false, - testTimeout: 15000, + testTimeout: 20000, reporters: ['verbose'], exclude: ['lib', 'node_modules'], }, From 5c39b45106aa124f25b254d2750ba57c6b7bb2b5 Mon Sep 17 00:00:00 2001 From: Shook Date: Wed, 15 May 2024 12:48:27 +0800 Subject: [PATCH 44/78] refactor: add notes to TxBuilder.payFee() related functions, and simplify some code --- packages/btc/src/transaction/build.ts | 74 +++++++++++++++++---------- 1 file changed, 47 insertions(+), 27 deletions(-) diff --git a/packages/btc/src/transaction/build.ts b/packages/btc/src/transaction/build.ts index 9ff8de23..6039c75b 100644 --- a/packages/btc/src/transaction/build.ts +++ b/packages/btc/src/transaction/build.ts @@ -145,17 +145,15 @@ export class TxBuilder { const originalInputs = clone(this.inputs); const originalOutputs = clone(this.outputs); - // Fetch the latest average fee rate if feeRate param is not provided - // The transaction is expected be confirmed within half an hour with the fee rate - let averageFeeRate: number | undefined; + // Fill a default recommended fee rate if props.feeRate is not provided + let defaultFeeRate: number | undefined; if (!feeRate && !this.feeRate) { const feeRates = await this.source.service.getBtcRecommendedFeeRates(); - averageFeeRate = feeRates.fastestFee; + defaultFeeRate = feeRates.fastestFee; } - // Use the feeRate param if it is specified, - // otherwise use the average fee rate from the DataSource - const currentFeeRate = feeRate ?? this.feeRate ?? averageFeeRate!; + // Use props.feeRate if it's specified + const currentFeeRate = feeRate ?? this.feeRate ?? defaultFeeRate!; let currentFee = 0; let previousFee = 0; @@ -172,8 +170,8 @@ export class TxBuilder { const safeToProcess = inputsTotal > 0 || previousFee > 0; const returnAmount = needReturn - previousFee; if (safeToProcess && returnAmount > 0) { - // If sum(inputs) - sum(outputs) > fee, return change while deducting fee - // Note, should not deduct fee from outputs while also returning change at the same time + // If sum(inputs) - sum(outputs) > fee, return (change - fee) to a non-fixed output or to a new output. + // Note when returning change to a new output, another satoshi collection may be needed. await this.injectChange({ address: changeAddress ?? address, amount: returnAmount, @@ -181,6 +179,8 @@ export class TxBuilder { fromPublicKey: publicKey, }); } else { + // If the inputs have insufficient satoshi, a satoshi collection is required. + // For protection, at least collect 1 satoshi if the inputs are empty or the fee hasn't been calculated. const protectionAmount = safeToProcess ? 0 : 1; const targetAmount = needCollect - needReturn + previousFee + protectionAmount; await this.injectSatoshi({ @@ -192,8 +192,11 @@ export class TxBuilder { }); } + // Calculate network fee const addressType = getAddressType(address); currentFee = await this.calculateFee(addressType, currentFeeRate); + + // If (fee = previousFee ±1), the fee is considered acceptable/expected. isFeeExpected = [-1, 0, 1].includes(currentFee - previousFee); if (!isLoopedOnce) { isLoopedOnce = true; @@ -218,18 +221,18 @@ export class TxBuilder { throw TxBuildError.withComment(ErrorCodes.UNSUPPORTED_ADDRESS_TYPE, props.address); } + const targetAmount = props.targetAmount; const injectCollected = props.injectCollected ?? false; const deductFromOutputs = props.deductFromOutputs ?? true; let collected = 0; let changeAmount = 0; - let targetAmount = props.targetAmount; - - const _collect = async (_targetAmount: number, stack?: boolean) => { - if (stack) { - targetAmount += _targetAmount; - } + /** + * Collect from the "from" address via DataSource. + * Will update the value of inputs/collected/changeAmount. + */ + const _collect = async (_targetAmount: number) => { const { utxos, satoshi } = await this.source.collectSatoshi({ address: props.address, targetAmount: _targetAmount, @@ -249,6 +252,11 @@ export class TxBuilder { collected += satoshi; _updateChangeAmount(); }; + /** + * Update changeAmount depends on injectedCollected: + * - true: If targetAmount=1000, collected=2000, changeAmount=2000+1000=3000 + * - false: If targetAmount=1000, collected=2000, changeAmount=2000-1000=1000 + */ const _updateChangeAmount = () => { if (injectCollected) { changeAmount = collected + targetAmount; @@ -257,7 +265,7 @@ export class TxBuilder { } }; - // Collect from outputs + // 1. Collect from the non-fixed outputs if (deductFromOutputs) { for (let i = 0; i < this.outputs.length; i++) { const output = this.outputs[i]; @@ -268,21 +276,20 @@ export class TxBuilder { break; } - // If output.protected is true, do not destroy the output - // Only collect the satoshi from (output.value - minUtxoSatoshi) const minUtxoSatoshi = output.minUtxoSatoshi ?? this.minUtxoSatoshi; const freeAmount = output.value - minUtxoSatoshi; const remain = targetAmount - collected; if (output.protected) { - // freeAmount=100, remain=50, collectAmount=50 - // freeAmount=100, remain=150, collectAmount=100 + // If output.protected=true: + // - Only deduct free satoshi from the output + // - Won't destroy the output, at least keep (output.value = minUtxoSatoshi) const collectAmount = Math.min(freeAmount, remain); output.value -= collectAmount; collected += collectAmount; } else { - // output.value=200, freeAmount=100, remain=50, collectAmount=50 - // output.value=200, freeAmount=100, remain=150, collectAmount=100 - // output.value=100, freeAmount=0, remain=150, collectAmount=100 + // If output.protected=false: + // - If (target collect amount > output.value), deduct all output.value + // - Destroy the output if all value is deducted const collectAmount = output.value > remain ? Math.min(freeAmount, remain) : output.value; output.value -= collectAmount; collected += collectAmount; @@ -295,19 +302,21 @@ export class TxBuilder { } } - // Collect target amount of satoshi from DataSource + // 2. Collect from the "from" address if (collected < targetAmount) { await _collect(targetAmount - collected); } - // If 0 < change amount < minUtxoSatoshi, collect one more time + // 3. Collect from "from" one more time if: + // - Need to create an output to return change (changeAmount > 0) + // - The change is insufficient for a non-dust output (changeAmount < minUtxoSatoshi) const needForChange = changeAmount > 0 && changeAmount < this.minUtxoSatoshi; const changeUtxoNeedAmount = needForChange ? this.minUtxoSatoshi - changeAmount : 0; if (needForChange) { await _collect(changeUtxoNeedAmount); } - // If not collected enough satoshi, throw error + // 4. If not collected enough satoshi, throw an error const insufficientBalance = collected < targetAmount; if (insufficientBalance) { const recommendedDeposit = targetAmount - collected + this.minUtxoSatoshi; @@ -325,7 +334,9 @@ export class TxBuilder { ); } - // Return change + // 5. Return change: + // - If changeAmount=0, no need to create a change output, and the changeIndex=-1 + // - If changeAmount>0, return change to an output or create a change output let changeIndex: number = -1; if (changeAmount > 0) { changeIndex = this.outputs.length; @@ -348,6 +359,8 @@ export class TxBuilder { async injectChange(props: { amount: number; address: string; fromAddress: string; fromPublicKey?: string }) { const { address, fromAddress, fromPublicKey, amount } = props; + // If any (output.fixed != true) is found in the outputs (search in ASC order), + // return the change value to the first matched output. for (let i = 0; i < this.outputs.length; i++) { const output = this.outputs[i]; if (output.fixed) { @@ -362,6 +375,13 @@ export class TxBuilder { } if (amount < this.minUtxoSatoshi) { + // If the change is not enough to create a non-dust output, try collect more. + // - injectCollected=true, expect to put all (collected + amount) of satoshi as change + // - deductFromOutputs=false, do not collect satoshi from the outputs + // An example: + // 1. Expected to return change of 500 satoshi, amount=500 + // 2. Collected 2000 satoshi from the "fromAddress", collected=2000 + // 3. Create a change output and return (collected + amount), output.value=2000+500=2500 const { collected } = await this.injectSatoshi({ address: fromAddress, publicKey: fromPublicKey, From 1d5a952279595e963d6e3c76c665a6086088a64a Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Wed, 15 May 2024 13:27:11 +0800 Subject: [PATCH 45/78] feat: Build ckb raw tx for spore creation --- packages/ckb/README.md | 2 -- packages/ckb/src/spore/spore.ts | 55 ++++++++++++++++++++++++++------- packages/ckb/src/types/spore.ts | 15 +++++++++ 3 files changed, 58 insertions(+), 14 deletions(-) diff --git a/packages/ckb/README.md b/packages/ckb/README.md index 632d4e8c..a94cf28e 100644 --- a/packages/ckb/README.md +++ b/packages/ckb/README.md @@ -147,8 +147,6 @@ export interface SporeCreateVirtualTxResult { * @param collector The collector that collects CKB live cells and transactions * @param clusterRgbppLockArgs The cluster rgbpp cell lock script args whose data structure is: out_index | bitcoin_tx_id * @param sporeDataList The spore's data list, including name and description. - * @param witnessLockPlaceholderSize The WitnessArgs.lock placeholder bytes array size and the default value is 5000 - * @param ckbFeeRate The CKB transaction fee rate, default value is 1100 */ export const genCreateSporeCkbVirtualTx = async ({ collector, diff --git a/packages/ckb/src/spore/spore.ts b/packages/ckb/src/spore/spore.ts index a3dd1d79..b301ac6c 100644 --- a/packages/ckb/src/spore/spore.ts +++ b/packages/ckb/src/spore/spore.ts @@ -9,6 +9,7 @@ import { import { buildPreLockArgs, calculateCommitment, genRgbppLockScript } from '../utils/rgbpp'; import { AppendIssuerCellToSporeCreate, + BuildAppendingIssuerCellToSporeCreateTx, CreateSporeCkbVirtualTxParams, Hex, SporeCreateVirtualTxResult, @@ -56,8 +57,6 @@ import signWitnesses from '@nervosnetwork/ckb-sdk-core/lib/signWitnesses'; * @param collector The collector that collects CKB live cells and transactions * @param clusterRgbppLockArgs The cluster rgbpp cell lock script args whose data structure is: out_index | bitcoin_tx_id * @param sporeDataList The spore's data list, including name and description. - * @param witnessLockPlaceholderSize The WitnessArgs.lock placeholder bytes array size and the default value is 5000 - * @param ckbFeeRate The CKB transaction fee rate, default value is 1100 */ export const genCreateSporeCkbVirtualTx = async ({ collector, @@ -156,27 +155,25 @@ export const genCreateSporeCkbVirtualTx = async ({ }; /** - * Append paymaster cell to the ckb transaction inputs and sign the transaction with paymaster cell's secp256k1 private key - * @param secp256k1PrivateKey The Secp256k1 private key of the paymaster cells maintainer + * Append paymaster cell to the ckb transaction inputs and build the raw tx to be signed for spores creation * @param issuerAddress The issuer ckb address * @param collector The collector that collects CKB live cells and transactions * @param ckbRawTx CKB raw transaction * @param sumInputsCapacity The sum capacity of ckb inputs which is to be used to calculate ckb tx fee + * @param witnessLockPlaceholderSize The WitnessArgs.lock placeholder bytes array size and the default value is 65 * @param ckbFeeRate The CKB transaction fee rate, default value is 1100 */ -export const appendIssuerCellToSporesCreate = async ({ - secp256k1PrivateKey, +export const buildAppendingIssuerCellToSporesCreateTx = async ({ issuerAddress, collector, ckbRawTx, sumInputsCapacity, - isMainnet, + witnessLockPlaceholderSize = SECP256K1_WITNESS_LOCK_SIZE, ckbFeeRate, -}: AppendIssuerCellToSporeCreate): Promise => { +}: BuildAppendingIssuerCellToSporeCreateTx): Promise => { + const isMainnet = issuerAddress.startsWith('ckb'); const rawTx = ckbRawTx as CKBComponents.RawTransactionToSign; - const rgbppInputsLength = rawTx.inputs.length; - const sumOutputsCapacity: bigint = rawTx.outputs .map((output) => BigInt(output.capacity)) .reduce((prev, current) => prev + current, BigInt(0)); @@ -205,13 +202,47 @@ export const appendIssuerCellToSporesCreate = async ({ rawTx.outputs = [...rawTx.outputs, changeOutput]; rawTx.outputsData = [...rawTx.outputsData, '0x']; - rawTx.cellDeps = [...rawTx.cellDeps, getSecp256k1CellDep(isMainnet)]; + if (witnessLockPlaceholderSize === SECP256K1_WITNESS_LOCK_SIZE) { + rawTx.cellDeps = [...rawTx.cellDeps, getSecp256k1CellDep(isMainnet)]; + } - const txSize = getTransactionSize(rawTx) + SECP256K1_WITNESS_LOCK_SIZE; + const txSize = getTransactionSize(rawTx) + witnessLockPlaceholderSize; const estimatedTxFee = calculateTransactionFee(txSize, ckbFeeRate); changeCapacity -= estimatedTxFee; rawTx.outputs[rawTx.outputs.length - 1].capacity = append0x(changeCapacity.toString(16)); + return rawTx; +}; + +/** + * Append paymaster cell to the ckb transaction inputs and sign the transaction with paymaster cell's secp256k1 private key + * @param secp256k1PrivateKey The Secp256k1 private key of the paymaster cells maintainer + * @param issuerAddress The issuer ckb address + * @param collector The collector that collects CKB live cells and transactions + * @param ckbRawTx CKB raw transaction + * @param sumInputsCapacity The sum capacity of ckb inputs which is to be used to calculate ckb tx fee + * @param ckbFeeRate The CKB transaction fee rate, default value is 1100 + */ +export const appendIssuerCellToSporesCreate = async ({ + secp256k1PrivateKey, + issuerAddress, + collector, + ckbRawTx, + sumInputsCapacity, + isMainnet, + ckbFeeRate, +}: AppendIssuerCellToSporeCreate): Promise => { + const rawTx = await buildAppendingIssuerCellToSporesCreateTx({ + issuerAddress, + collector, + ckbRawTx, + sumInputsCapacity, + ckbFeeRate, + }); + + const rgbppInputsLength = ckbRawTx.inputs.length; + const issuerLock = addressToScript(issuerAddress); + const keyMap = new Map(); keyMap.set(scriptToHash(issuerLock), secp256k1PrivateKey); keyMap.set(scriptToHash(getRgbppLockScript(isMainnet)), ''); diff --git a/packages/ckb/src/types/spore.ts b/packages/ckb/src/types/spore.ts index 871c6e75..90a7e8b7 100644 --- a/packages/ckb/src/types/spore.ts +++ b/packages/ckb/src/types/spore.ts @@ -51,6 +51,21 @@ export interface SporeCreateVirtualTxResult { clusterCell: IndexerCell; } +export interface BuildAppendingIssuerCellToSporeCreateTx { + // The issuer ckb address + issuerAddress: Address; + // The collector that collects CKB live cells and transactions + collector: Collector; + // CKB raw transaction + ckbRawTx: CKBComponents.RawTransaction; + // The sum capacity of the ckb inputs + sumInputsCapacity: Hex; + // The WitnessArgs.lock placeholder bytes array size and the default value is 5000 + witnessLockPlaceholderSize?: number; + // The CKB transaction fee rate, default value is 1100 + ckbFeeRate?: bigint; +} + export interface AppendIssuerCellToSporeCreate { // The Secp256k1 private key of the issuer cells maintainer secp256k1PrivateKey: Hex; From 1d58dd531947f4078667bb7294d2b3bb9351ead9 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Wed, 15 May 2024 13:47:05 +0800 Subject: [PATCH 46/78] chore: Add changeset --- .changeset/stupid-donuts-grin.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/stupid-donuts-grin.md diff --git a/.changeset/stupid-donuts-grin.md b/.changeset/stupid-donuts-grin.md new file mode 100644 index 00000000..f5a3352b --- /dev/null +++ b/.changeset/stupid-donuts-grin.md @@ -0,0 +1,5 @@ +--- +"@rgbpp-sdk/ckb": minor +--- + +feat: Build ckb raw tx to be signed for spores creation From 2712209906deb50c236c7e8e7a53e40782cf73d7 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Wed, 15 May 2024 15:46:10 +0800 Subject: [PATCH 47/78] refactor: Check spore type for spore transfer and leap --- packages/ckb/src/spore/leap.ts | 2 +- packages/ckb/src/spore/spore.ts | 2 +- packages/ckb/src/utils/ckb-tx.ts | 12 +++++++-- packages/ckb/src/utils/rgbpp.ts | 1 + packages/ckb/src/utils/spore.spec.ts | 39 +++++++++++++++++++++++++--- packages/ckb/src/utils/spore.ts | 12 +++++++-- 6 files changed, 59 insertions(+), 9 deletions(-) diff --git a/packages/ckb/src/spore/leap.ts b/packages/ckb/src/spore/leap.ts index b2e2f64b..612af062 100644 --- a/packages/ckb/src/spore/leap.ts +++ b/packages/ckb/src/spore/leap.ts @@ -61,7 +61,7 @@ export const genLeapSporeFromBtcToCkbVirtualTx = async ({ }; const sporeCells = await collector.getCells({ lock: sporeRgbppLock, isDataMustBeEmpty: false }); - throwErrorWhenSporeCellsInvalid(sporeCells, sporeTypeBytes); + throwErrorWhenSporeCellsInvalid(sporeCells, sporeTypeBytes, isMainnet); const sporeCell = sporeCells![0]; diff --git a/packages/ckb/src/spore/spore.ts b/packages/ckb/src/spore/spore.ts index a3dd1d79..2b18faf4 100644 --- a/packages/ckb/src/spore/spore.ts +++ b/packages/ckb/src/spore/spore.ts @@ -272,7 +272,7 @@ export const genTransferSporeCkbVirtualTx = async ({ }; const sporeCells = await collector.getCells({ lock: sporeRgbppLock, isDataMustBeEmpty: false }); - throwErrorWhenSporeCellsInvalid(sporeCells, sporeTypeBytes); + throwErrorWhenSporeCellsInvalid(sporeCells, sporeTypeBytes, isMainnet); const sporeCell = sporeCells![0]; diff --git a/packages/ckb/src/utils/ckb-tx.ts b/packages/ckb/src/utils/ckb-tx.ts index 3f333185..972bc8e7 100644 --- a/packages/ckb/src/utils/ckb-tx.ts +++ b/packages/ckb/src/utils/ckb-tx.ts @@ -29,14 +29,22 @@ export const isUDTTypeSupported = (type: CKBComponents.Script, isMainnet: boolea return xudtType === typeAsset; }; -export const isClusterSporeTypeSupported = (type: CKBComponents.Script, isMainnet: boolean): boolean => { +export const isSporeTypeSupported = (type: CKBComponents.Script, isMainnet: boolean): boolean => { const sporeType = serializeScript(getSporeTypeScript(isMainnet)); + const typeAsset = serializeScript({ + ...type, + args: '', + }); + return sporeType === typeAsset; +}; + +export const isClusterSporeTypeSupported = (type: CKBComponents.Script, isMainnet: boolean): boolean => { const typeAsset = serializeScript({ ...type, args: '', }); const clusterType = serializeScript(getClusterTypeScript(isMainnet)); - return sporeType === typeAsset || clusterType === typeAsset; + return isSporeTypeSupported(type, isMainnet) || clusterType === typeAsset; }; export const isTypeAssetSupported = (type: CKBComponents.Script, isMainnet: boolean): boolean => { diff --git a/packages/ckb/src/utils/rgbpp.ts b/packages/ckb/src/utils/rgbpp.ts index 2783eed1..19515685 100644 --- a/packages/ckb/src/utils/rgbpp.ts +++ b/packages/ckb/src/utils/rgbpp.ts @@ -240,6 +240,7 @@ export const throwErrorWhenRgbppCellsInvalid = ( if (typeCells.length === 0) { throw new NoRgbppLiveCellError('No rgbpp cells found with the rgbpp lock args'); } + const isUDTTypeNotSupported = typeCells.some( (cell) => cell.output.type && !isUDTTypeSupported(cell.output.type, isMainnet), ); diff --git a/packages/ckb/src/utils/spore.spec.ts b/packages/ckb/src/utils/spore.spec.ts index 9c362fde..9f1dce0e 100644 --- a/packages/ckb/src/utils/spore.spec.ts +++ b/packages/ckb/src/utils/spore.spec.ts @@ -117,7 +117,7 @@ describe('spore utils', () => { }); try { - throwErrorWhenSporeCellsInvalid([], sporeTypeBytes); + throwErrorWhenSporeCellsInvalid([], sporeTypeBytes, false); } catch (error) { if (error instanceof NoRgbppLiveCellError) { expect(104).toBe(error.code); @@ -172,7 +172,7 @@ describe('spore utils', () => { }, ]; try { - throwErrorWhenSporeCellsInvalid(multiSporeCells, sporeTypeBytes); + throwErrorWhenSporeCellsInvalid(multiSporeCells, sporeTypeBytes, false); } catch (error) { if (error instanceof RgbppUtxoBindMultiTypeAssetsError) { expect(110).toBe(error.code); @@ -180,6 +180,39 @@ describe('spore utils', () => { } } + const noSupportedSporeCell: IndexerCell[] = [ + { + blockNumber: '0x0', + outPoint: { + txHash: '0xf2bfcd0ec5f7b2a33577168b7a647e71cc81a731560a7ad23b1c31fc08bbe1bb', + index: '0x1', + }, + output: { + capacity: '0x460913c00', + lock: { + args: '0x0200000050b34b391fd8f8084bf9b6af4368350c1510df4964496b87495ebee4bd8d86d5', + codeHash: '0x61ca7a4796a4eb19ca4f0d065cb9b10ddcf002f10f7cbb810c706cb6bb5c3248', + hashType: 'type', + }, + type: { + args: '0xf2bfcd0ec5f7b2a33577168b7a647e71cc81a731560a7ad23b1c31fc08bbe1bb', + codeHash: '0xf2bfcd0ec5f7b2a33577168b7a647e71cc81a731560a7ad23b1c31fc08bbe1bb', + hashType: 'data1', + }, + }, + outputData: '0x2d000000100000001e0000002d0000000a000000746578742f706c61696e0b00000046697273742053706f7265', + txIndex: '0x0', + }, + ]; + try { + throwErrorWhenSporeCellsInvalid(noSupportedSporeCell, sporeTypeBytes, false); + } catch (error) { + if (error instanceof RgbppSporeTypeMismatchError) { + expect(111).toBe(error.code); + expect('The cell type is not the supported spore type script').toBe(error.message); + } + } + const noTargetCells: IndexerCell[] = [ { blockNumber: '0x0', @@ -205,7 +238,7 @@ describe('spore utils', () => { }, ]; try { - throwErrorWhenSporeCellsInvalid(noTargetCells, sporeTypeBytes); + throwErrorWhenSporeCellsInvalid(noTargetCells, sporeTypeBytes, false); } catch (error) { if (error instanceof RgbppSporeTypeMismatchError) { expect(111).toBe(error.code); diff --git a/packages/ckb/src/utils/spore.ts b/packages/ckb/src/utils/spore.ts index b43145db..471f73e7 100644 --- a/packages/ckb/src/utils/spore.ts +++ b/packages/ckb/src/utils/spore.ts @@ -12,7 +12,7 @@ import { import { u64ToLe } from './hex'; import { Hex, IndexerCell, SporesCreateCobuildParams } from '../types'; import { NoRgbppLiveCellError, RgbppSporeTypeMismatchError, RgbppUtxoBindMultiTypeAssetsError } from '../error'; -import { isScriptEqual } from './ckb-tx'; +import { isScriptEqual, isSporeTypeSupported } from './ckb-tx'; // Generate type id for cluster id export const generateClusterId = (firstInput: CKBComponents.CellInput, firstOutputIndex: number) => { @@ -101,7 +101,11 @@ export const generateSporeTransferCoBuild = ( }; // Check the validity of RGB++ spore cells and throw an exception if the conditions are not met to avoid building invalid CKB TX -export const throwErrorWhenSporeCellsInvalid = (sporeCells: IndexerCell[] | undefined, sporeTypeBytes: Hex) => { +export const throwErrorWhenSporeCellsInvalid = ( + sporeCells: IndexerCell[] | undefined, + sporeTypeBytes: Hex, + isMainnet: boolean, +) => { if (!sporeCells || sporeCells.length === 0) { throw new NoRgbppLiveCellError('No spore rgbpp cells found with the spore rgbpp lock args'); } @@ -114,6 +118,10 @@ export const throwErrorWhenSporeCellsInvalid = (sporeCells: IndexerCell[] | unde throw new RgbppSporeTypeMismatchError('The cell with the rgbpp lock args has no spore asset'); } + if (!isSporeTypeSupported(sporeCell.output.type, isMainnet)) { + throw new RgbppSporeTypeMismatchError('The cell type is not the supported spore type script'); + } + if (!isScriptEqual(sporeCell.output.type, sporeTypeBytes)) { throw new RgbppSporeTypeMismatchError('The spore cell type with the rgbpp lock args does not match'); } From 64c4312768885cb965285d41de99d023a4517ed3 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Wed, 15 May 2024 15:47:52 +0800 Subject: [PATCH 48/78] chore: Add changeset --- .changeset/slimy-eggs-mix.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/slimy-eggs-mix.md diff --git a/.changeset/slimy-eggs-mix.md b/.changeset/slimy-eggs-mix.md new file mode 100644 index 00000000..16d9858d --- /dev/null +++ b/.changeset/slimy-eggs-mix.md @@ -0,0 +1,5 @@ +--- +"@rgbpp-sdk/ckb": minor +--- + +refactor: Check spore type script for spore transfer and leap From ee982b1fa2be1d95106486e44408e5606bf9b9af Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Wed, 15 May 2024 15:59:09 +0800 Subject: [PATCH 49/78] fix example annotation typo --- examples/rgbpp/spore/6-unlock-btc-time-cell.ts | 2 +- examples/rgbpp/xudt/4-unlock-btc-time-cell.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/rgbpp/spore/6-unlock-btc-time-cell.ts b/examples/rgbpp/spore/6-unlock-btc-time-cell.ts index 49b9843a..65153ccb 100644 --- a/examples/rgbpp/spore/6-unlock-btc-time-cell.ts +++ b/examples/rgbpp/spore/6-unlock-btc-time-cell.ts @@ -2,7 +2,7 @@ import { buildSporeBtcTimeCellsSpentTx, signBtcTimeCellSpentTx } from 'rgbpp'; import { CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from '../env'; import { sendCkbTx, getBtcTimeLockScript } from 'rgbpp/ckb'; -// Warning: Wait at least 6 BTC confirmation blocks to spend the BTC time cells after 4-btc-jump-ckb.ts +// Warning: Wait at least 6 BTC confirmation blocks to spend the BTC time cells after 5-leap-spore-to-ckb.ts const unlockSporeBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: string }) => { const btcTimeCells = await collector.getCells({ lock: { diff --git a/examples/rgbpp/xudt/4-unlock-btc-time-cell.ts b/examples/rgbpp/xudt/4-unlock-btc-time-cell.ts index fdf6f87f..6cece8ce 100644 --- a/examples/rgbpp/xudt/4-unlock-btc-time-cell.ts +++ b/examples/rgbpp/xudt/4-unlock-btc-time-cell.ts @@ -2,7 +2,7 @@ import { buildBtcTimeCellsSpentTx, signBtcTimeCellSpentTx } from 'rgbpp'; import { sendCkbTx, getBtcTimeLockScript } from 'rgbpp/ckb'; import { CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from '../env'; -// Warning: Wait at least 6 BTC confirmation blocks to spend the BTC time cells after 4-btc-jump-ckb.ts +// Warning: Wait at least 6 BTC confirmation blocks to spend the BTC time cells after 3-btc-leap-ckb.ts const unlockBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: string }) => { const btcTimeCells = await collector.getCells({ lock: { @@ -34,7 +34,7 @@ const unlockBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: string console.info(`BTC time cell has been spent and tx hash is ${txHash}`); }; -// The btcTimeCellArgs is from the outputs[0].lock.args(BTC Time lock args) of the 4-btc-jump-ckb.ts CKB transaction +// The btcTimeCellArgs is from the outputs[0].lock.args(BTC Time lock args) of the 3-btc-leap-ckb.ts CKB transaction unlockBtcTimeCell({ btcTimeCellArgs: '0x7f000000100000005b0000005f0000004b000000100000003000000031000000d23761b364210735c19c60561d213fb3beae2fd6172743719eff6920e020baac011600000000016c61f984f12d3c8a4f649e60acda5deda0b8837c060000001c95b9d726e4ab337d6a4572680598947954d7b6ff4f1e767e605eeeec49e7ed', From 18a1c387c6a774028f7e9dab15fcdad0e7cc5bbf Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Wed, 15 May 2024 16:26:19 +0800 Subject: [PATCH 50/78] refactor: Rename buildAppendingIssuerCellToSporesCreateTx parameter name --- packages/ckb/src/spore/spore.ts | 4 ++-- packages/ckb/src/types/spore.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ckb/src/spore/spore.ts b/packages/ckb/src/spore/spore.ts index b301ac6c..3ee8450d 100644 --- a/packages/ckb/src/spore/spore.ts +++ b/packages/ckb/src/spore/spore.ts @@ -9,7 +9,7 @@ import { import { buildPreLockArgs, calculateCommitment, genRgbppLockScript } from '../utils/rgbpp'; import { AppendIssuerCellToSporeCreate, - BuildAppendingIssuerCellToSporeCreateTx, + BuildAppendingIssuerCellTxParams, CreateSporeCkbVirtualTxParams, Hex, SporeCreateVirtualTxResult, @@ -170,7 +170,7 @@ export const buildAppendingIssuerCellToSporesCreateTx = async ({ sumInputsCapacity, witnessLockPlaceholderSize = SECP256K1_WITNESS_LOCK_SIZE, ckbFeeRate, -}: BuildAppendingIssuerCellToSporeCreateTx): Promise => { +}: BuildAppendingIssuerCellTxParams): Promise => { const isMainnet = issuerAddress.startsWith('ckb'); const rawTx = ckbRawTx as CKBComponents.RawTransactionToSign; diff --git a/packages/ckb/src/types/spore.ts b/packages/ckb/src/types/spore.ts index 90a7e8b7..56a5afcd 100644 --- a/packages/ckb/src/types/spore.ts +++ b/packages/ckb/src/types/spore.ts @@ -51,7 +51,7 @@ export interface SporeCreateVirtualTxResult { clusterCell: IndexerCell; } -export interface BuildAppendingIssuerCellToSporeCreateTx { +export interface BuildAppendingIssuerCellTxParams { // The issuer ckb address issuerAddress: Address; // The collector that collects CKB live cells and transactions From 752f6232f209e8a65b37c6bb89e193795bb9baba Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Thu, 16 May 2024 09:00:37 +0800 Subject: [PATCH 51/78] chore: Use btc testnet address for example --- examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts b/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts index b1da9a36..2c801113 100644 --- a/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts +++ b/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts @@ -107,7 +107,7 @@ distributeRgbppAssetOnBtc({ xudtTypeArgs: '0x4c1ecf2f14edae73b76ccf115ecfa40ba68ee315c96bd4fcfd771c2fb4c69e8f', receivers: [ { - toBtcAddress: 'bc1p0ey32x7dwhlx569rh0l5qaxetsfnpvezanrezahelr0t02ytyegssdel0h', + toBtcAddress: 'tb1qvt7p9g6mw70sealdewtfp0sekquxuru6j3gwmt', transferAmount: BigInt(1000) * BigInt(10 ** RGBPP_TOKEN_INFO.decimal), }, ], From ce21ad377477b13e3d25c4d52767ebf1c32ed2b1 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Thu, 16 May 2024 12:56:09 +0800 Subject: [PATCH 52/78] refactor: Move secp256k1 cell dep to signing stage --- packages/ckb/src/spore/spore.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/ckb/src/spore/spore.ts b/packages/ckb/src/spore/spore.ts index 3ee8450d..92b7e0b1 100644 --- a/packages/ckb/src/spore/spore.ts +++ b/packages/ckb/src/spore/spore.ts @@ -154,6 +154,8 @@ export const genCreateSporeCkbVirtualTx = async ({ }; }; +const CELL_DEP_SIZE = 32 + 4 + 1; + /** * Append paymaster cell to the ckb transaction inputs and build the raw tx to be signed for spores creation * @param issuerAddress The issuer ckb address @@ -171,7 +173,6 @@ export const buildAppendingIssuerCellToSporesCreateTx = async ({ witnessLockPlaceholderSize = SECP256K1_WITNESS_LOCK_SIZE, ckbFeeRate, }: BuildAppendingIssuerCellTxParams): Promise => { - const isMainnet = issuerAddress.startsWith('ckb'); const rawTx = ckbRawTx as CKBComponents.RawTransactionToSign; const sumOutputsCapacity: bigint = rawTx.outputs @@ -202,11 +203,7 @@ export const buildAppendingIssuerCellToSporesCreateTx = async ({ rawTx.outputs = [...rawTx.outputs, changeOutput]; rawTx.outputsData = [...rawTx.outputsData, '0x']; - if (witnessLockPlaceholderSize === SECP256K1_WITNESS_LOCK_SIZE) { - rawTx.cellDeps = [...rawTx.cellDeps, getSecp256k1CellDep(isMainnet)]; - } - - const txSize = getTransactionSize(rawTx) + witnessLockPlaceholderSize; + const txSize = getTransactionSize(rawTx) + witnessLockPlaceholderSize + CELL_DEP_SIZE; const estimatedTxFee = calculateTransactionFee(txSize, ckbFeeRate); changeCapacity -= estimatedTxFee; rawTx.outputs[rawTx.outputs.length - 1].capacity = append0x(changeCapacity.toString(16)); @@ -240,6 +237,8 @@ export const appendIssuerCellToSporesCreate = async ({ ckbFeeRate, }); + rawTx.cellDeps = [...rawTx.cellDeps, getSecp256k1CellDep(isMainnet)]; + const rgbppInputsLength = ckbRawTx.inputs.length; const issuerLock = addressToScript(issuerAddress); From 8cfc06e449c213868f103d9757f79f24521da280 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Thu, 16 May 2024 17:35:30 +0800 Subject: [PATCH 53/78] refactor(rgbpp-sdk/ckb): Update ckb cell fields size (#174) * refactor: Update ckb cell fields size --- .changeset/sweet-jeans-check.md | 5 +++++ packages/ckb/src/utils/ckb-tx.ts | 18 ++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 .changeset/sweet-jeans-check.md diff --git a/.changeset/sweet-jeans-check.md b/.changeset/sweet-jeans-check.md new file mode 100644 index 00000000..7ecd851d --- /dev/null +++ b/.changeset/sweet-jeans-check.md @@ -0,0 +1,5 @@ +--- +"@rgbpp-sdk/ckb": minor +--- + +refactor: Update ckb cell fields size to make the code more readable diff --git a/packages/ckb/src/utils/ckb-tx.ts b/packages/ckb/src/utils/ckb-tx.ts index 972bc8e7..943e5cd2 100644 --- a/packages/ckb/src/utils/ckb-tx.ts +++ b/packages/ckb/src/utils/ckb-tx.ts @@ -51,6 +51,9 @@ export const isTypeAssetSupported = (type: CKBComponents.Script, isMainnet: bool return isUDTTypeSupported(type, isMainnet) || isClusterSporeTypeSupported(type, isMainnet); }; +const CELL_CAPACITY_SIZE = 8; +const UDT_CELL_DATA_SIZE = 16; + // The BTC_TIME_CELL_INCREASED_SIZE is related to the specific lock script. // We assume that the maximum length of lock script args is 26 bytes. If it exceeds, an error will be thrown. const LOCK_ARGS_HEX_MAX_SIZE = 26 * 2; @@ -71,7 +74,8 @@ const RGBPP_LOCK_SIZE = 32 + 1 + 36; export const calculateRgbppCellCapacity = (xudtType?: CKBComponents.Script): bigint => { const typeArgsSize = xudtType ? remove0x(xudtType.args).length / 2 : 32; const udtTypeSize = 33 + typeArgsSize; - const cellSize = RGBPP_LOCK_SIZE + udtTypeSize + 8 + 16 + BTC_TIME_CELL_INCREASED_SIZE; + const cellSize = + RGBPP_LOCK_SIZE + udtTypeSize + CELL_CAPACITY_SIZE + UDT_CELL_DATA_SIZE + BTC_TIME_CELL_INCREASED_SIZE; return BigInt(cellSize + 1) * CKB_UNIT; }; @@ -82,7 +86,9 @@ const DEFAULT_UDT_ARGS_SIZE = 32; export const calculateUdtCellCapacity = (lock: CKBComponents.Script, udtType?: CKBComponents.Script): bigint => { const lockArgsSize = remove0x(lock.args).length / 2; const typeArgsSize = udtType ? remove0x(udtType.args).length / 2 : DEFAULT_UDT_ARGS_SIZE; - const cellSize = 33 + lockArgsSize + 33 + typeArgsSize + 8 + 16; + const lockSize = 33 + lockArgsSize; + const typeSize = 33 + typeArgsSize; + const cellSize = lockSize + typeSize + CELL_CAPACITY_SIZE + UDT_CELL_DATA_SIZE; return BigInt(cellSize + 1) * CKB_UNIT; }; @@ -91,7 +97,7 @@ export const calculateXudtTokenInfoCellCapacity = (tokenInfo: RgbppTokenInfo, lo const lockSize = remove0x(lock.args).length / 2 + 33; const cellDataSize = remove0x(encodeRgbppTokenInfo(tokenInfo)).length / 2; const uniqueTypeSize = 32 + 1 + 20; - const cellSize = lockSize + uniqueTypeSize + 8 + cellDataSize; + const cellSize = lockSize + uniqueTypeSize + CELL_CAPACITY_SIZE + cellDataSize; return BigInt(cellSize) * CKB_UNIT; }; @@ -101,7 +107,7 @@ export const calculateRgbppTokenInfoCellCapacity = (tokenInfo: RgbppTokenInfo, i const lockSize = remove0x(btcTimeLock.args).length / 2 + 33; const cellDataSize = remove0x(encodeRgbppTokenInfo(tokenInfo)).length / 2; const typeSize = 32 + 1 + 20; - const cellSize = lockSize + typeSize + 8 + cellDataSize; + const cellSize = lockSize + typeSize + CELL_CAPACITY_SIZE + cellDataSize; return BigInt(cellSize) * CKB_UNIT; }; @@ -119,7 +125,7 @@ export const generateUniqueTypeArgs = (firstInput: CKBComponents.CellInput, firs export const calculateRgbppClusterCellCapacity = (clusterData: RawClusterData): bigint => { const clusterDataSize = packRawClusterData(clusterData).length; const clusterTypeSize = 32 + 1 + 32; - const cellSize = RGBPP_LOCK_SIZE + clusterTypeSize + 8 + clusterDataSize; + const cellSize = RGBPP_LOCK_SIZE + clusterTypeSize + CELL_CAPACITY_SIZE + clusterDataSize; return BigInt(cellSize + 1) * CKB_UNIT; }; @@ -135,7 +141,7 @@ export const calculateRgbppClusterCellCapacity = (clusterData: RawClusterData): export const calculateRgbppSporeCellCapacity = (sporeData: SporeDataProps): bigint => { const sporeDataSize = packRawSporeData(sporeData).length; const sporeTypeSize = 32 + 1 + 32; - const cellSize = RGBPP_LOCK_SIZE + sporeTypeSize + 8 + sporeDataSize + BTC_TIME_CELL_INCREASED_SIZE; + const cellSize = RGBPP_LOCK_SIZE + sporeTypeSize + CELL_CAPACITY_SIZE + sporeDataSize + BTC_TIME_CELL_INCREASED_SIZE; return BigInt(cellSize + 1) * CKB_UNIT; }; From 49870225346f16405a90a7af05b63242febde769 Mon Sep 17 00:00:00 2001 From: Shook Date: Fri, 17 May 2024 00:13:10 +0800 Subject: [PATCH 54/78] fix: export NetworkType/AddressType as enums instead of types in rgbpp --- .changeset/clean-chairs-nail.md | 5 +++++ packages/rgbpp/src/index.ts | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 .changeset/clean-chairs-nail.md diff --git a/.changeset/clean-chairs-nail.md b/.changeset/clean-chairs-nail.md new file mode 100644 index 00000000..540a9ebd --- /dev/null +++ b/.changeset/clean-chairs-nail.md @@ -0,0 +1,5 @@ +--- +"rgbpp": patch +--- + +Fix the export of NetworkType/AddressType in the rgbpp lib diff --git a/packages/rgbpp/src/index.ts b/packages/rgbpp/src/index.ts index fb5988ce..b7836861 100644 --- a/packages/rgbpp/src/index.ts +++ b/packages/rgbpp/src/index.ts @@ -44,6 +44,8 @@ export { BtcAssetsApi, BtcAssetsApiError } from '@rgbpp-sdk/service'; */ export { DataSource, + NetworkType, + AddressType, sendBtc, sendUtxos, sendRgbppUtxos, @@ -51,4 +53,4 @@ export { createSendUtxosBuilder, createSendRgbppUtxosBuilder, } from '@rgbpp-sdk/btc'; -export type { NetworkType, AddressType, SendBtcProps, SendUtxosProps, SendRgbppUtxosProps } from '@rgbpp-sdk/btc'; +export type { SendBtcProps, SendUtxosProps, SendRgbppUtxosProps } from '@rgbpp-sdk/btc'; From 3afadc8c3b792c3fc41a6b2648f6de3e1ef30e4a Mon Sep 17 00:00:00 2001 From: Flouse <1297478+Flouse@users.noreply.github.com> Date: Fri, 17 May 2024 15:23:43 +0800 Subject: [PATCH 55/78] docs(FAQ): no protocol prefix and port suffix in the access token's `domain` (#178) --- README.md | 8 +++++++- packages/service/README.md | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b620175e..8a342530 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,13 @@ This repository offers utilities for Bitcoin and RGB++ asset integration. ### Notes -- The RGB++ CKB transaction Queue is designed to streamline the transaction workflow. Developers have the option to implement its features by themselves without limitation. +- `Bitcoin/RGB++ Assets Service` is designed to streamline the transaction workflow. Developers have the option to implement its features by themselves without limitation. + + +## FAQ + +### How to get an access token of Bitcoin/RGB++ Assets Service? +See [Generate a JSON Web Token (JWT) for Bitcoin/RGB++ Assets Service](./packages/service/README.md#get-an-access-token) ## License diff --git a/packages/service/README.md b/packages/service/README.md index 3fef78cd..34a926ec 100644 --- a/packages/service/README.md +++ b/packages/service/README.md @@ -42,7 +42,7 @@ please email us at f@cell.studio to request a mainnet JWT token. In the email, please provide the following information about your app: - `name`: Your app name, e.g. "rgbpp-app" -- `domain`: Your app domain, e.g. "rgbpp.app" (without protocol prefix) +- `domain`: Your app domain, e.g. "rgbpp.app" (without protocol prefix and port suffix) ### Initialize the service From 2b63c0fc6cd694e86e58d22fb63ccd2f8714d13b Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Fri, 17 May 2024 17:09:30 +0800 Subject: [PATCH 56/78] feat: Increase the max length of rgbpp inputs to 40 --- packages/ckb/src/constants/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ckb/src/constants/index.ts b/packages/ckb/src/constants/index.ts index 5430a88b..cf92757a 100644 --- a/packages/ckb/src/constants/index.ts +++ b/packages/ckb/src/constants/index.ts @@ -4,7 +4,7 @@ export const MIN_CAPACITY = BigInt(61) * BigInt(10000_0000); export const SECP256K1_WITNESS_LOCK_SIZE = 65; export const BTC_JUMP_CONFIRMATION_BLOCKS = 6; export const RGBPP_TX_WITNESS_MAX_SIZE = 5000; -export const RGBPP_TX_INPUTS_MAX_LENGTH = 10; +export const RGBPP_TX_INPUTS_MAX_LENGTH = 40; export const RGBPP_WITNESS_PLACEHOLDER = '0xFF'; export const RGBPP_TX_ID_PLACEHOLDER = '0000000000000000000000000000000000000000000000000000000000000000'; From 5e0e8175a4c195e6491a37abedc755728c91cbed Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Fri, 17 May 2024 17:13:21 +0800 Subject: [PATCH 57/78] chore: Add changeset --- .changeset/fast-mice-smash.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fast-mice-smash.md diff --git a/.changeset/fast-mice-smash.md b/.changeset/fast-mice-smash.md new file mode 100644 index 00000000..c84cc96f --- /dev/null +++ b/.changeset/fast-mice-smash.md @@ -0,0 +1,5 @@ +--- +"@rgbpp-sdk/ckb": minor +--- + +feat: Increase the max length of RGB++ inputs to 40 From f4776ea4796b0070cbcaa9f036d3663aabc0bf0b Mon Sep 17 00:00:00 2001 From: Shook Date: Fri, 17 May 2024 17:24:08 +0800 Subject: [PATCH 58/78] chore: update changelog format --- .changeset/changelog-format.cjs | 130 ++++++++++++++++++++++++++++++++ .changeset/config.json | 4 +- package.json | 3 +- pnpm-lock.yaml | 24 ++---- 4 files changed, 140 insertions(+), 21 deletions(-) create mode 100644 .changeset/changelog-format.cjs diff --git a/.changeset/changelog-format.cjs b/.changeset/changelog-format.cjs new file mode 100644 index 00000000..c49e0d2d --- /dev/null +++ b/.changeset/changelog-format.cjs @@ -0,0 +1,130 @@ +// @ts-check +/** + * Based on the following format: + * - https://github.com/changesets/changesets/blob/main/packages/changelog-github/src/index.ts + * - https://github.com/stylelint/stylelint/blob/main/.changeset/changelog-stylelint.cjs + */ + +const { getInfo, getInfoFromPullRequest } = require('@changesets/get-github-info'); + +/** + * @type {import('@changesets/types').ChangelogFunctions} + */ +const changelogFunctions = { + async getReleaseLine(changeset, _type, options) { + if (!options || !options.repo) { + throw new Error( + 'Please provide a repo to this changelog generator like this:\n"changelog": ["@changesets/changelog-github", { "repo": "org/repo" }]', + ); + } + + /** + * @type {number | undefined} + */ + let prFromSummary; + /** + * @type {string | undefined} + */ + let commitFromSummary; + /** + * @type {string[]} + */ + let usersFromSummary = []; + + const replacedChangelog = changeset.summary + .replace(/^\s*(?:pr|pull|pull\s+request):\s*#?(\d+)/im, (_, pr) => { + let num = Number(pr); + if (!isNaN(num)) { + prFromSummary = num; + } + return ''; + }) + .replace(/^\s*commit:\s*([^\s]+)/im, (_, commit) => { + commitFromSummary = commit; + return ''; + }) + .replace(/^\s*(?:author|user):\s*@?([^\s]+)/gim, (_, user) => { + usersFromSummary.push(user); + return ''; + }) + .trim(); + + const [firstLine, ...futureLines] = replacedChangelog + .split('\n') + .map((l) => l.trimRight()); + + const links = await (async () => { + if (prFromSummary !== undefined) { + let { links } = await getInfoFromPullRequest({ + repo: options.repo, + pull: prFromSummary, + }); + if (commitFromSummary) { + const shortCommitId = commitFromSummary.slice(0, 7); + links = { + ...links, + commit: `[\`${shortCommitId}\`](https://github.com/${options.repo}/commit/${commitFromSummary})`, + }; + } + return links; + } + const commitToFetchFrom = commitFromSummary || changeset.commit; + if (commitToFetchFrom) { + let { links } = await getInfo({ + repo: options.repo, + commit: commitToFetchFrom, + }); + return links; + } + return { + commit: null, + pull: null, + user: null, + }; + })(); + + const users = usersFromSummary.length + ? usersFromSummary + .map((userFromSummary) => `[@${userFromSummary}](https://github.com/${userFromSummary})`) + .join(', ') + : links.user; + + const pull = links.pull !== null ? links.pull : ''; + const commit = links.commit !== null ? links.commit : ''; + const prefix = pull || commit ? `${pull || commit}:` : ''; + const mention = users !== null ? `(${users})` : users; + const fullFirstLine = `${prefix} ${firstLine} ${mention}`; + const futureLinesText = futureLines.map((l) => ` ${l}`).join('\n'); + + return `\n\n - ${fullFirstLine}\n${futureLinesText}`; + }, + async getDependencyReleaseLine(changesets, deps, options) { + if (!options.repo) { + throw new Error( + 'Please provide a repo to this changelog generator like this:\n"changelog": ["@changesets/changelog-github", { "repo": "org/repo" }]', + ); + } + if (deps.length === 0) { + return ''; + } + + const commits = Promise.all( + changesets.map(async (cs) => { + if (cs.commit) { + let { links } = await getInfo({ + repo: options.repo, + commit: cs.commit, + }); + return links.commit; + } + }), + ); + + const changesetLink = `- Updated dependencies [${commits.join(', ')}]:`; + const updatedDeps = deps.map((dep) => ` - ${dep.name}@${dep.newVersion}`); + + return [changesetLink, ...updatedDeps].join('\n'); + }, +}; + +module.exports = changelogFunctions; diff --git a/.changeset/config.json b/.changeset/config.json index d0a8cd83..ad84d74d 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -1,11 +1,11 @@ { "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json", - "changelog": ["@changesets/changelog-github", { "repo": "ckb-cell/rgbpp-sdk" }], + "changelog": ["./changelog-format.cjs", { "repo": "ckb-cell/rgbpp-sdk" }], "commit": false, "fixed": [["@rgbpp-sdk/*", "rgbpp"]], "linked": [], "access": "public", - "baseBranch": "main", + "baseBranch": "origin/main", "updateInternalDependencies": "patch", "ignore": [] } diff --git a/package.json b/package.json index 72764c09..cd5e96f5 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,9 @@ "release:packages": "pnpm run clean:packages && pnpm run build:packages && changeset publish" }, "devDependencies": { - "@changesets/changelog-github": "^0.5.0", "@changesets/cli": "^2.27.1", + "@changesets/types": "^6.0.0", + "@changesets/get-github-info": "^0.6.0", "@typescript-eslint/eslint-plugin": "^7.8.0", "@typescript-eslint/parser": "^7.8.0", "eslint": "^8.56.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a22cbfef..3dd4ecbd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,12 +8,15 @@ importers: .: devDependencies: - '@changesets/changelog-github': - specifier: ^0.5.0 - version: 0.5.0 '@changesets/cli': specifier: ^2.27.1 version: 2.27.1 + '@changesets/get-github-info': + specifier: ^0.6.0 + version: 0.6.0 + '@changesets/types': + specifier: ^6.0.0 + version: 6.0.0 '@typescript-eslint/eslint-plugin': specifier: ^7.8.0 version: 7.8.0(@typescript-eslint/parser@7.8.0)(eslint@8.56.0)(typescript@5.4.3) @@ -587,16 +590,6 @@ packages: '@changesets/types': 6.0.0 dev: true - /@changesets/changelog-github@0.5.0: - resolution: {integrity: sha512-zoeq2LJJVcPJcIotHRJEEA2qCqX0AQIeFE+L21L8sRLPVqDhSXY8ZWAt2sohtBpFZkBwu+LUwMSKRr2lMy3LJA==} - dependencies: - '@changesets/get-github-info': 0.6.0 - '@changesets/types': 6.0.0 - dotenv: 8.6.0 - transitivePeerDependencies: - - encoding - dev: true - /@changesets/cli@2.27.1: resolution: {integrity: sha512-iJ91xlvRnnrJnELTp4eJJEOPjgpF3NOh4qeQehM6Ugiz9gJPRZ2t+TsXun6E3AMN4hScZKjqVXl0TX+C7AB3ZQ==} hasBin: true @@ -3004,11 +2997,6 @@ packages: engines: {node: '>=12'} dev: true - /dotenv@8.6.0: - resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} - engines: {node: '>=10'} - dev: true - /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true From b09f30d830782884381179898bf5e9322f691215 Mon Sep 17 00:00:00 2001 From: ahonn Date: Mon, 20 May 2024 17:13:49 +1000 Subject: [PATCH 59/78] feat: add no_cache params to btc/rgbpp service api --- packages/service/src/types/btc.ts | 2 ++ packages/service/src/types/rgbpp.ts | 1 + packages/service/tests/Service.test.ts | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+) diff --git a/packages/service/src/types/btc.ts b/packages/service/src/types/btc.ts index 1b320bcd..d5bbd031 100644 --- a/packages/service/src/types/btc.ts +++ b/packages/service/src/types/btc.ts @@ -58,6 +58,7 @@ export interface BtcApiRecommendedFeeRates { export interface BtcApiBalanceParams { min_satoshi?: number; + no_cache?: boolean; } export interface BtcApiBalance { address: string; @@ -70,6 +71,7 @@ export interface BtcApiBalance { export interface BtcApiUtxoParams { only_confirmed?: boolean; min_satoshi?: number; + no_cache?: boolean; } export interface BtcApiUtxo { txid: string; diff --git a/packages/service/src/types/rgbpp.ts b/packages/service/src/types/rgbpp.ts index 2a6b39b1..3f42bb5a 100644 --- a/packages/service/src/types/rgbpp.ts +++ b/packages/service/src/types/rgbpp.ts @@ -44,6 +44,7 @@ export interface RgbppApiTransactionState { export interface RgbppApiAssetsByAddressParams { type_script?: string; + no_cache?: boolean; } export interface RgbppApiSpvProof { diff --git a/packages/service/tests/Service.test.ts b/packages/service/tests/Service.test.ts index 1bb509cf..a6acd70b 100644 --- a/packages/service/tests/Service.test.ts +++ b/packages/service/tests/Service.test.ts @@ -92,6 +92,12 @@ describe( expect(filteredBalance.satoshi).toEqual(0); expect(filteredBalance.dust_satoshi).toEqual(originalBalance.satoshi + originalBalance.dust_satoshi); }); + it('getBtcBalance() with no_cache', async () => { + const res = await service.getBtcBalance(btcAddress, { + no_cache: true, + }); + expect(res.address).toEqual(btcAddress); + }); it('getBtcUtxos()', async () => { const res = await service.getBtcUtxos(btcAddress); expect(Array.isArray(res)).toBe(true); @@ -131,6 +137,12 @@ describe( expect(utxo.status.confirmed).toBe(true); } }); + it('getBtcUtxos() with no_cache', async () => { + const utxos = await service.getBtcUtxos(btcAddress, { + no_cache: true, + }); + expect(Array.isArray(utxos)).toBe(true); + }); it('getBtcTransactions()', async () => { const res = await service.getBtcTransactions(btcAddress); console.log(res.map((tx) => tx.txid)); @@ -248,6 +260,13 @@ describe( expectCell(cell); } }); + it('getRgbppAssetsByBtcAddress() with no_cache', async () => { + const res = await service.getRgbppAssetsByBtcAddress(rgbppBtcAddress, { + no_cache: true, + }); + expect(res).toBeDefined(); + expect(res.length).toBeGreaterThan(0); + }); it('getRgbppSpvProof()', async () => { const res = await service.getRgbppSpvProof(rgbppBtcTxId, 6); expect(res).toBeDefined(); From 9f9daa91486ca0cc1015713bd2648aa606da8717 Mon Sep 17 00:00:00 2001 From: ahonn Date: Mon, 20 May 2024 17:24:25 +1000 Subject: [PATCH 60/78] chore: add changeset --- .changeset/rude-feet-love.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/rude-feet-love.md diff --git a/.changeset/rude-feet-love.md b/.changeset/rude-feet-love.md new file mode 100644 index 00000000..f741593d --- /dev/null +++ b/.changeset/rude-feet-love.md @@ -0,0 +1,5 @@ +--- +'@rgbpp-sdk/service': patch +--- + +add no_cache params to btc/rgbpp service api From d1df59a2da8def730d030eced2f9516de893b098 Mon Sep 17 00:00:00 2001 From: ahonn Date: Mon, 20 May 2024 17:41:56 +1000 Subject: [PATCH 61/78] test: update getBtcTransactions() with after_txid test --- packages/service/tests/Service.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/service/tests/Service.test.ts b/packages/service/tests/Service.test.ts index a6acd70b..e2205335 100644 --- a/packages/service/tests/Service.test.ts +++ b/packages/service/tests/Service.test.ts @@ -164,13 +164,13 @@ describe( expect(txs.length).toBeGreaterThan(0); const filteredTxs = await service.getBtcTransactions(btcAddress, { - after_txid: txs[0].txid, + after_txid: txs[txs.length - 2].txid, }); expect(Array.isArray(filteredTxs)).toBe(true); if (txs.length > 1) { expect(txs.length).toBeGreaterThan(0); - expect(filteredTxs[0].txid).toEqual(txs[1].txid); + expect(filteredTxs[0].txid).toEqual(txs[txs.length - 1].txid); } else { expect(filteredTxs).toHaveLength(0); } From f5e66f78892b8c46dfa203fcec6a63cec873c7a3 Mon Sep 17 00:00:00 2001 From: Shook Date: Tue, 21 May 2024 16:34:27 +0800 Subject: [PATCH 62/78] fix: missing await in the changelog format file --- .changeset/changelog-format.cjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/changelog-format.cjs b/.changeset/changelog-format.cjs index c49e0d2d..3bbdb0df 100644 --- a/.changeset/changelog-format.cjs +++ b/.changeset/changelog-format.cjs @@ -108,7 +108,7 @@ const changelogFunctions = { return ''; } - const commits = Promise.all( + const commits = await Promise.all( changesets.map(async (cs) => { if (cs.commit) { let { links } = await getInfo({ From 685cf34896a3da312786f7b2168d7970ac06c5c2 Mon Sep 17 00:00:00 2001 From: Shook Date: Tue, 21 May 2024 12:00:39 +0800 Subject: [PATCH 63/78] docs: add no_cache param to service readme --- packages/service/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/service/README.md b/packages/service/README.md index 34a926ec..a6bb4898 100644 --- a/packages/service/README.md +++ b/packages/service/README.md @@ -223,6 +223,7 @@ interface BtcApiBlockTransactionIds { interface BtcApiBalanceParams { min_satoshi?: number; + no_cache?: boolean; } interface BtcApiBalance { @@ -236,6 +237,7 @@ interface BtcApiBalance { interface BtcApiUtxoParams { only_confirmed?: boolean; min_satoshi?: number; + no_cache?: boolean; } interface BtcApiUtxo { @@ -329,6 +331,7 @@ interface RgbppApiTransactionState { interface RgbppApiAssetsByAddressParams { type_script?: string; + no_cache?: boolean; } interface RgbppApiSpvProof { From 8a8e11bdca4d3fb8b8d20c771e116bb1684bb1c6 Mon Sep 17 00:00:00 2001 From: Shook Date: Tue, 21 May 2024 13:56:23 +0800 Subject: [PATCH 64/78] feat: support internal query data caching in TxBuilder.payFee() --- .changeset/afraid-pianos-do.md | 5 +++ packages/btc/README.md | 2 + packages/btc/src/query/cache.ts | 62 +++++++++++++++++++++++++++ packages/btc/src/query/source.ts | 29 ++++++++++--- packages/btc/src/transaction/build.ts | 31 ++++++++++++-- 5 files changed, 121 insertions(+), 8 deletions(-) create mode 100644 .changeset/afraid-pianos-do.md create mode 100644 packages/btc/src/query/cache.ts diff --git a/.changeset/afraid-pianos-do.md b/.changeset/afraid-pianos-do.md new file mode 100644 index 00000000..dfac1ff1 --- /dev/null +++ b/.changeset/afraid-pianos-do.md @@ -0,0 +1,5 @@ +--- +"@rgbpp-sdk/btc": minor +--- + +Support query data caching internally in TxBuilder/DataSource, preventing query from the BtcAssetsApi too often when paying fee diff --git a/packages/btc/README.md b/packages/btc/README.md index 6866c30e..db62850f 100644 --- a/packages/btc/README.md +++ b/packages/btc/README.md @@ -372,6 +372,8 @@ interface DataSource { allowInsufficient?: boolean; onlyNonRgbppUtxos?: boolean; onlyConfirmedUtxos?: boolean; + noUtxosCache?: boolean; + cacheKey?: string; excludeUtxos?: { txid: string; vout: number; diff --git a/packages/btc/src/query/cache.ts b/packages/btc/src/query/cache.ts new file mode 100644 index 00000000..046b2c8e --- /dev/null +++ b/packages/btc/src/query/cache.ts @@ -0,0 +1,62 @@ +import { Utxo } from '../transaction/utxo'; + +export class DataCache { + private utxos: Map; // Map + private hasRgbppAssets: Map; // Map<`{txid}:{vout}`, HasAssets> + + constructor() { + this.utxos = new Map(); + this.hasRgbppAssets = new Map(); + } + + setUtxos(key: string, utxos: Utxo[]) { + this.utxos.set(key, utxos); + } + getUtxos(key: string): Utxo[] | undefined { + return this.utxos.get(key); + } + cleanUtxos(key: string) { + if (this.utxos.has(key)) { + this.utxos.delete(key); + } + } + async optionalCacheUtxos(props: { key?: string; getter: () => Promise | Utxo[] }): Promise { + if (props.key && this.utxos.has(props.key)) { + return this.getUtxos(props.key) as Utxo[]; + } + + const utxos = await props.getter(); + if (props.key) { + this.setUtxos(props.key, utxos); + } + + return utxos; + } + + setHasRgbppAssets(key: string, hasAssets: boolean) { + this.hasRgbppAssets.set(key, hasAssets); + } + getHasRgbppAssets(key: string): boolean | undefined { + return this.hasRgbppAssets.get(key); + } + cleanHasRgbppAssets(key: string) { + if (this.hasRgbppAssets.has(key)) { + this.hasRgbppAssets.delete(key); + } + } + async optionalCacheHasRgbppAssets(props: { + key?: string; + getter: () => Promise | boolean; + }): Promise { + if (props.key && this.hasRgbppAssets.has(props.key)) { + return this.getHasRgbppAssets(props.key) as boolean; + } + + const hasRgbppAssets = await props.getter(); + if (props.key) { + this.setHasRgbppAssets(props.key, hasRgbppAssets); + } + + return hasRgbppAssets; + } +} diff --git a/packages/btc/src/query/source.ts b/packages/btc/src/query/source.ts index d350afc1..9d332c45 100644 --- a/packages/btc/src/query/source.ts +++ b/packages/btc/src/query/source.ts @@ -6,14 +6,17 @@ import { TxAddressOutput } from '../transaction/build'; import { isOpReturnScriptPubkey } from '../transaction/embed'; import { addressToScriptPublicKeyHex, getAddressType } from '../address'; import { remove0x } from '../utils'; +import { DataCache } from './cache'; export class DataSource { + public cache: DataCache; public service: BtcAssetsApi; public networkType: NetworkType; constructor(service: BtcAssetsApi, networkType: NetworkType) { this.service = service; this.networkType = networkType; + this.cache = new DataCache(); } // Query a UTXO from the service. @@ -102,6 +105,8 @@ export class DataSource { allowInsufficient?: boolean; onlyNonRgbppUtxos?: boolean; onlyConfirmedUtxos?: boolean; + noUtxosCache?: boolean; + cacheKey?: string; excludeUtxos?: { txid: string; vout: number; @@ -117,12 +122,20 @@ export class DataSource { minUtxoSatoshi, onlyConfirmedUtxos, onlyNonRgbppUtxos, + noUtxosCache, + cacheKey, allowInsufficient = false, excludeUtxos = [], } = props; - const utxos = await this.getUtxos(address, { - only_confirmed: onlyConfirmedUtxos, - min_satoshi: minUtxoSatoshi, + + const utxos = await this.cache.optionalCacheUtxos({ + key: cacheKey, + getter: () => + this.getUtxos(address, { + only_confirmed: onlyConfirmedUtxos, + min_satoshi: minUtxoSatoshi, + no_cache: noUtxosCache, + }), }); const collected = []; @@ -140,8 +153,14 @@ export class DataSource { } } if (onlyNonRgbppUtxos) { - const ckbRgbppAssets = await this.service.getRgbppAssetsByBtcUtxo(utxo.txid, utxo.vout); - if (ckbRgbppAssets && ckbRgbppAssets.length > 0) { + const hasRgbppAssets = await this.cache.optionalCacheHasRgbppAssets({ + key: `${utxo.txid}:${utxo.vout}`, + getter: async () => { + const ckbRgbppAssets = await this.service.getRgbppAssetsByBtcUtxo(utxo.txid, utxo.vout); + return Array.isArray(ckbRgbppAssets) && ckbRgbppAssets.length > 0; + }, + }); + if (hasRgbppAssets) { continue; } } diff --git a/packages/btc/src/transaction/build.ts b/packages/btc/src/transaction/build.ts index 6039c75b..f5e239d9 100644 --- a/packages/btc/src/transaction/build.ts +++ b/packages/btc/src/transaction/build.ts @@ -136,15 +136,20 @@ export class TxBuilder { publicKey?: string; changeAddress?: string; deductFromOutputs?: boolean; + noUtxosCache?: boolean; feeRate?: number; }): Promise<{ fee: number; feeRate: number; }> { - const { address, publicKey, feeRate, changeAddress, deductFromOutputs } = props; + const { address, publicKey, feeRate, changeAddress, deductFromOutputs, noUtxosCache } = props; const originalInputs = clone(this.inputs); const originalOutputs = clone(this.outputs); + // Create a cache key to prevent querying the Utxo[] too often + // TODO: consider provide an option to disable the cache + const cacheKey = `${Date.now()}`; + // Fill a default recommended fee rate if props.feeRate is not provided let defaultFeeRate: number | undefined; if (!feeRate && !this.feeRate) { @@ -177,6 +182,8 @@ export class TxBuilder { amount: returnAmount, fromAddress: address, fromPublicKey: publicKey, + noUtxosCache, + cacheKey, }); } else { // If the inputs have insufficient satoshi, a satoshi collection is required. @@ -189,6 +196,8 @@ export class TxBuilder { targetAmount, changeAddress, deductFromOutputs, + noUtxosCache, + cacheKey, }); } @@ -203,6 +212,9 @@ export class TxBuilder { } } + // Clear cache for the Utxo[] list + this.source.cache.cleanUtxos(cacheKey); + return { fee: currentFee, feeRate: currentFeeRate, @@ -216,6 +228,8 @@ export class TxBuilder { changeAddress?: string; injectCollected?: boolean; deductFromOutputs?: boolean; + noUtxosCache?: boolean; + cacheKey?: string; }) { if (!isSupportedFromAddress(props.address)) { throw TxBuildError.withComment(ErrorCodes.UNSUPPORTED_ADDRESS_TYPE, props.address); @@ -237,6 +251,8 @@ export class TxBuilder { address: props.address, targetAmount: _targetAmount, allowInsufficient: true, + cacheKey: props.cacheKey, + noUtxosCache: props.noUtxosCache, minUtxoSatoshi: this.minUtxoSatoshi, onlyNonRgbppUtxos: this.onlyNonRgbppUtxos, onlyConfirmedUtxos: this.onlyConfirmedUtxos, @@ -356,8 +372,15 @@ export class TxBuilder { }; } - async injectChange(props: { amount: number; address: string; fromAddress: string; fromPublicKey?: string }) { - const { address, fromAddress, fromPublicKey, amount } = props; + async injectChange(props: { + amount: number; + address: string; + fromAddress: string; + fromPublicKey?: string; + noUtxosCache?: boolean; + cacheKey?: string; + }) { + const { address, fromAddress, fromPublicKey, amount, noUtxosCache, cacheKey } = props; // If any (output.fixed != true) is found in the outputs (search in ASC order), // return the change value to the first matched output. @@ -389,6 +412,8 @@ export class TxBuilder { changeAddress: address, injectCollected: true, deductFromOutputs: false, + noUtxosCache, + cacheKey, }); if (collected < amount) { throw TxBuildError.withComment(ErrorCodes.INSUFFICIENT_UTXO, `expected: ${amount}, actual: ${collected}`); From 64857f4a06f2c7eca0ca494d98af5748515b1f9d Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Thu, 23 May 2024 16:18:05 +0800 Subject: [PATCH 65/78] fix: Update spore creation tx rgbpp inputs length --- packages/ckb/src/spore/spore.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ckb/src/spore/spore.ts b/packages/ckb/src/spore/spore.ts index ee51187b..0ff01f31 100644 --- a/packages/ckb/src/spore/spore.ts +++ b/packages/ckb/src/spore/spore.ts @@ -229,6 +229,8 @@ export const appendIssuerCellToSporesCreate = async ({ isMainnet, ckbFeeRate, }: AppendIssuerCellToSporeCreate): Promise => { + const rgbppInputsLength = ckbRawTx.inputs.length; + const rawTx = await buildAppendingIssuerCellToSporesCreateTx({ issuerAddress, collector, @@ -239,7 +241,6 @@ export const appendIssuerCellToSporesCreate = async ({ rawTx.cellDeps = [...rawTx.cellDeps, getSecp256k1CellDep(isMainnet)]; - const rgbppInputsLength = ckbRawTx.inputs.length; const issuerLock = addressToScript(issuerAddress); const keyMap = new Map(); From 7f928ec3e04d70b73d4e2b198caab339131e1a66 Mon Sep 17 00:00:00 2001 From: Shook Date: Thu, 23 May 2024 19:20:11 +0800 Subject: [PATCH 66/78] refactor: remove "noUtxosCache" in pay fee related methods, and set to true by default when paying fee --- packages/btc/src/transaction/build.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/btc/src/transaction/build.ts b/packages/btc/src/transaction/build.ts index f5e239d9..724ef9ad 100644 --- a/packages/btc/src/transaction/build.ts +++ b/packages/btc/src/transaction/build.ts @@ -136,13 +136,12 @@ export class TxBuilder { publicKey?: string; changeAddress?: string; deductFromOutputs?: boolean; - noUtxosCache?: boolean; feeRate?: number; }): Promise<{ fee: number; feeRate: number; }> { - const { address, publicKey, feeRate, changeAddress, deductFromOutputs, noUtxosCache } = props; + const { address, publicKey, feeRate, changeAddress, deductFromOutputs } = props; const originalInputs = clone(this.inputs); const originalOutputs = clone(this.outputs); @@ -182,7 +181,6 @@ export class TxBuilder { amount: returnAmount, fromAddress: address, fromPublicKey: publicKey, - noUtxosCache, cacheKey, }); } else { @@ -196,7 +194,6 @@ export class TxBuilder { targetAmount, changeAddress, deductFromOutputs, - noUtxosCache, cacheKey, }); } @@ -228,7 +225,6 @@ export class TxBuilder { changeAddress?: string; injectCollected?: boolean; deductFromOutputs?: boolean; - noUtxosCache?: boolean; cacheKey?: string; }) { if (!isSupportedFromAddress(props.address)) { @@ -251,8 +247,8 @@ export class TxBuilder { address: props.address, targetAmount: _targetAmount, allowInsufficient: true, + noUtxosCache: true, cacheKey: props.cacheKey, - noUtxosCache: props.noUtxosCache, minUtxoSatoshi: this.minUtxoSatoshi, onlyNonRgbppUtxos: this.onlyNonRgbppUtxos, onlyConfirmedUtxos: this.onlyConfirmedUtxos, @@ -377,10 +373,9 @@ export class TxBuilder { address: string; fromAddress: string; fromPublicKey?: string; - noUtxosCache?: boolean; cacheKey?: string; }) { - const { address, fromAddress, fromPublicKey, amount, noUtxosCache, cacheKey } = props; + const { address, fromAddress, fromPublicKey, amount, cacheKey } = props; // If any (output.fixed != true) is found in the outputs (search in ASC order), // return the change value to the first matched output. @@ -412,7 +407,6 @@ export class TxBuilder { changeAddress: address, injectCollected: true, deductFromOutputs: false, - noUtxosCache, cacheKey, }); if (collected < amount) { From 4fcf4fa6c0b20cf2fa957664a320f66601991817 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Thu, 23 May 2024 20:59:43 +0800 Subject: [PATCH 67/78] fix(rgbpp-sdk/ckb): Update rgbpp witnesses for btc batch transfer tx (#187) * fix: Update rgbpp witnesses for batch transfer tx --- .changeset/young-students-own.md | 5 +++++ packages/ckb/src/rgbpp/btc-transfer.ts | 12 +++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 .changeset/young-students-own.md diff --git a/.changeset/young-students-own.md b/.changeset/young-students-own.md new file mode 100644 index 00000000..576432b3 --- /dev/null +++ b/.changeset/young-students-own.md @@ -0,0 +1,5 @@ +--- +"@rgbpp-sdk/ckb": minor +--- + +fix: Update RRB++ witnesses for BTC batch transfer TX diff --git a/packages/ckb/src/rgbpp/btc-transfer.ts b/packages/ckb/src/rgbpp/btc-transfer.ts index dd53fbaf..4bc38ada 100644 --- a/packages/ckb/src/rgbpp/btc-transfer.ts +++ b/packages/ckb/src/rgbpp/btc-transfer.ts @@ -292,7 +292,17 @@ export const genBtcBatchTransferCkbVirtualTx = async ({ getRgbppLockConfigDep(isMainnet), getSecp256k1CellDep(isMainnet), ]; - const witnesses: Hex[] = inputs.map((_, index) => (index === 0 ? RGBPP_WITNESS_PLACEHOLDER : '0x')); + + const witnesses: Hex[] = []; + const lockArgsSet: Set = new Set(); + for (const cell of rgbppCells) { + if (lockArgsSet.has(cell.output.lock.args)) { + witnesses.push('0x'); + } else { + lockArgsSet.add(cell.output.lock.args); + witnesses.push(RGBPP_WITNESS_PLACEHOLDER); + } + } const ckbRawTx: CKBComponents.RawTransaction = { version: '0x0', From 22a0a27e76a8b5d9aac916f4dab71becddb05743 Mon Sep 17 00:00:00 2001 From: Shook <44739165+ShookLyngs@users.noreply.github.com> Date: Thu, 23 May 2024 22:10:53 +0800 Subject: [PATCH 68/78] chore: simplify snapshot/release workflow and trigger branches (#186) --- .github/workflows/snapshot.yml | 10 +--------- package.json | 2 +- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index fb82303c..67580d6d 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -6,7 +6,6 @@ on: workflow_dispatch: push: branches: - - main - develop concurrency: ${{ github.workflow }}-${{ github.ref }} @@ -47,21 +46,14 @@ jobs: - name: Install dependencies run: pnpm i - - name: Clear cache - run: pnpm run clean:packages - - name: Build packages run: pnpm run build:packages - - name: Version packages - run: npx changeset version --snapshot snap - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Publish to npm (ignore GitHub) id: changesets uses: changesets/action@v1 with: + version: npx changeset version --snapshot snap publish: npx changeset publish --snapshot --tag snap createGithubReleases: false env: diff --git a/package.json b/package.json index cd5e96f5..e9eb6282 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "clean:packages": "turbo run clean --filter=./packages/*", "clean:dependencies": "pnpm clean:sub-dependencies && rimraf node_modules", "clean:sub-dependencies": "rimraf packages/**/node_modules apps/**/node_modules", - "release:packages": "pnpm run clean:packages && pnpm run build:packages && changeset publish" + "release:packages": "pnpm run build:packages && changeset publish" }, "devDependencies": { "@changesets/cli": "^2.27.1", From f0c8d491fa64668e7af4c253494b5508ed0979f4 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Thu, 23 May 2024 22:14:15 +0800 Subject: [PATCH 69/78] docs: Add more annotations and logs for spore examples (#188) --- examples/rgbpp/spore/launch/2-create-cluster.ts | 5 ++++- examples/rgbpp/spore/launch/3-create-spores.ts | 8 +++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/examples/rgbpp/spore/launch/2-create-cluster.ts b/examples/rgbpp/spore/launch/2-create-cluster.ts index 2b2d09a3..5fefc541 100644 --- a/examples/rgbpp/spore/launch/2-create-cluster.ts +++ b/examples/rgbpp/spore/launch/2-create-cluster.ts @@ -16,7 +16,7 @@ const createCluster = async ({ ownerRgbppLockArgs }: { ownerRgbppLockArgs: strin rgbppLockArgs: ownerRgbppLockArgs, clusterData: CLUSTER_DATA, isMainnet, - ckbFeeRate: BigInt(5000), + ckbFeeRate: BigInt(2000), }); const { commitment, ckbRawTx, clusterId } = ckbVirtualTxResult; @@ -49,6 +49,9 @@ const createCluster = async ({ ownerRgbppLockArgs }: { ownerRgbppLockArgs: strin clearInterval(interval); // Update CKB transaction with the real BTC txId const newCkbRawTx = updateCkbTxWithRealBtcTxId({ ckbRawTx, btcTxId, isMainnet }); + + console.log('The cluster rgbpp lock args: ', newCkbRawTx.outputs[0].lock.args); + const ckbTx = await appendCkbTxWitnesses({ ckbRawTx: newCkbRawTx, btcTxBytes, diff --git a/examples/rgbpp/spore/launch/3-create-spores.ts b/examples/rgbpp/spore/launch/3-create-spores.ts index b30e5725..b073b067 100644 --- a/examples/rgbpp/spore/launch/3-create-spores.ts +++ b/examples/rgbpp/spore/launch/3-create-spores.ts @@ -35,7 +35,7 @@ const createSpores = async ({ clusterRgbppLockArgs, receivers }: SporeCreatePara sporeDataList: receivers.map((receiver) => receiver.sporeData), clusterRgbppLockArgs, isMainnet, - ckbFeeRate: BigInt(5000), + ckbFeeRate: BigInt(2000), }); const { commitment, ckbRawTx, sumInputsCapacity, clusterCell } = ckbVirtualTxResult; @@ -68,7 +68,7 @@ const createSpores = async ({ clusterRgbppLockArgs, receivers }: SporeCreatePara clearInterval(interval); // Update CKB transaction with the real BTC txId const newCkbRawTx = updateCkbTxWithRealBtcTxId({ ckbRawTx, btcTxId, isMainnet }); - console.log('The new cluster cell lock script args: ', newCkbRawTx.outputs[0].lock.args); + console.log('The new cluster rgbpp lock args: ', newCkbRawTx.outputs[0].lock.args); const ckbTx = await appendCkbTxWitnesses({ ckbRawTx: newCkbRawTx, @@ -113,7 +113,9 @@ const createSpores = async ({ clusterRgbppLockArgs, receivers }: SporeCreatePara // Use your real BTC UTXO information on the BTC Testnet // rgbppLockArgs: outIndexU32 + btcTxId createSpores({ - // The cluster rgbpp lock args is from 2-create-cluster.ts + // The cluster cell will be spent and the new cluster cell will be created in each spore creation tx, + // so the cluster rgbpp lock args should be updated after each spore creation tx is completed. + // The first cluster rgbpp lock args is from 2-create-cluster.ts and the new cluster rgbpp lock args can be found from the log in the line 71 of this file clusterRgbppLockArgs: buildRgbppLockArgs(1, '96bccaadd3c8f59b2411e3d64ae4c1743532415f953fc4f9741a5fd7a0a34483'), receivers: [ { From d89682929b14a1b58f6a1e6ce0f2c7235a6fa047 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Fri, 24 May 2024 10:30:33 +0800 Subject: [PATCH 70/78] fix: Remove xudt type from ckb change cell --- examples/rgbpp/test.ts | 11 +++++++++++ examples/xudt-on-ckb/2-transfer-xudt.ts | 1 - 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 examples/rgbpp/test.ts diff --git a/examples/rgbpp/test.ts b/examples/rgbpp/test.ts new file mode 100644 index 00000000..00b1a32e --- /dev/null +++ b/examples/rgbpp/test.ts @@ -0,0 +1,11 @@ +import { btcService } from './env'; + +const run = async () => { + const response = await btcService.getRgbppSpvProof( + 'a532f9f9f37f44be66d08faf3a27f0cc4dd5dd169780f9e54f902a1579bac2b1', + 0, + ); + console.log(JSON.stringify(response)); +}; + +run(); diff --git a/examples/xudt-on-ckb/2-transfer-xudt.ts b/examples/xudt-on-ckb/2-transfer-xudt.ts index 65a20cb5..e9f8ede4 100644 --- a/examples/xudt-on-ckb/2-transfer-xudt.ts +++ b/examples/xudt-on-ckb/2-transfer-xudt.ts @@ -97,7 +97,6 @@ const transferXudt = async ({ xudtType, receivers }: XudtTransferParams) => { outputs.push({ lock: fromLock, - type: xudtType, capacity: append0x(changeCapacity.toString(16)), }); outputsData.push('0x'); From 994be058a95bfcc56b10010f659c62b9dd6e5c90 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Fri, 24 May 2024 10:48:20 +0800 Subject: [PATCH 71/78] refactor: Remove xudt cell without amount data --- packages/ckb/src/collector/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/ckb/src/collector/index.ts b/packages/ckb/src/collector/index.ts index 89a2641b..032e2290 100644 --- a/packages/ckb/src/collector/index.ts +++ b/packages/ckb/src/collector/index.ts @@ -137,6 +137,9 @@ export class Collector { let sumAmount = BigInt(0); const isRgbppLock = liveCells.length > 0 && isRgbppLockCellIgnoreChain(liveCells[0].output); for (const cell of liveCells) { + if (cell.outputData === '0x') { + continue; + } inputs.push({ previousOutput: { txHash: cell.outPoint.txHash, From 299b404217036feab409956d8888bfdc8fa820f4 Mon Sep 17 00:00:00 2001 From: Dylan Duan Date: Fri, 24 May 2024 10:50:08 +0800 Subject: [PATCH 72/78] chore: Add changeset --- .changeset/selfish-lions-trade.md | 5 +++++ examples/rgbpp/test.ts | 11 ----------- 2 files changed, 5 insertions(+), 11 deletions(-) create mode 100644 .changeset/selfish-lions-trade.md delete mode 100644 examples/rgbpp/test.ts diff --git a/.changeset/selfish-lions-trade.md b/.changeset/selfish-lions-trade.md new file mode 100644 index 00000000..700344eb --- /dev/null +++ b/.changeset/selfish-lions-trade.md @@ -0,0 +1,5 @@ +--- +"@rgbpp-sdk/ckb": minor +--- + +refactor: Filter xudt cell whose amount is valid for collector diff --git a/examples/rgbpp/test.ts b/examples/rgbpp/test.ts deleted file mode 100644 index 00b1a32e..00000000 --- a/examples/rgbpp/test.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { btcService } from './env'; - -const run = async () => { - const response = await btcService.getRgbppSpvProof( - 'a532f9f9f37f44be66d08faf3a27f0cc4dd5dd169780f9e54f902a1579bac2b1', - 0, - ); - console.log(JSON.stringify(response)); -}; - -run(); From f247319f3448b3be059d68728277303538d4a532 Mon Sep 17 00:00:00 2001 From: Shook <44739165+ShookLyngs@users.noreply.github.com> Date: Fri, 24 May 2024 11:23:12 +0800 Subject: [PATCH 73/78] chore: fix snapshot versioning and always add a temp changeset to prevent non-snapshot releases (#189) --- .github/workflows/snapshot.yml | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 67580d6d..948394c8 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -49,12 +49,25 @@ jobs: - name: Build packages run: pnpm run build:packages - - name: Publish to npm (ignore GitHub) + - name: Add snapshot changeset (ensure at least has a changeset) + run: | + cat << EOF > ".changeset/snap-release-changeset.md" + --- + "@rgbpp-sdk/btc": patch + --- + Add temp changeset for snapshot releases + EOF + + - name: Version packages to "0.0.0-snap-{timestamp}" + run: npx changeset version --snapshot snap + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Publish to npm id: changesets uses: changesets/action@v1 with: - version: npx changeset version --snapshot snap - publish: npx changeset publish --snapshot --tag snap + publish: npx changeset publish --no-git-tag --snapshot --tag snap createGithubReleases: false env: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} From 092e3166195a38c064145f14d46f3697919a6e8b Mon Sep 17 00:00:00 2001 From: Shook Date: Fri, 24 May 2024 17:31:43 +0800 Subject: [PATCH 74/78] refactor: "noUtxosCache" -> "noAssetsApiCache", "cacheKey" -> "internalCacheKey" --- packages/btc/README.md | 4 ++-- packages/btc/src/query/source.ts | 12 ++++++------ packages/btc/src/transaction/build.ts | 26 +++++++++++++++----------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/packages/btc/README.md b/packages/btc/README.md index db62850f..e92232f7 100644 --- a/packages/btc/README.md +++ b/packages/btc/README.md @@ -372,8 +372,8 @@ interface DataSource { allowInsufficient?: boolean; onlyNonRgbppUtxos?: boolean; onlyConfirmedUtxos?: boolean; - noUtxosCache?: boolean; - cacheKey?: string; + noAssetsApiCache?: boolean; + internalCacheKey?: string; excludeUtxos?: { txid: string; vout: number; diff --git a/packages/btc/src/query/source.ts b/packages/btc/src/query/source.ts index 9d332c45..d7dcff0a 100644 --- a/packages/btc/src/query/source.ts +++ b/packages/btc/src/query/source.ts @@ -105,8 +105,8 @@ export class DataSource { allowInsufficient?: boolean; onlyNonRgbppUtxos?: boolean; onlyConfirmedUtxos?: boolean; - noUtxosCache?: boolean; - cacheKey?: string; + noAssetsApiCache?: boolean; + internalCacheKey?: string; excludeUtxos?: { txid: string; vout: number; @@ -122,19 +122,19 @@ export class DataSource { minUtxoSatoshi, onlyConfirmedUtxos, onlyNonRgbppUtxos, - noUtxosCache, - cacheKey, + noAssetsApiCache, + internalCacheKey, allowInsufficient = false, excludeUtxos = [], } = props; const utxos = await this.cache.optionalCacheUtxos({ - key: cacheKey, + key: internalCacheKey, getter: () => this.getUtxos(address, { only_confirmed: onlyConfirmedUtxos, min_satoshi: minUtxoSatoshi, - no_cache: noUtxosCache, + no_cache: noAssetsApiCache, }), }); diff --git a/packages/btc/src/transaction/build.ts b/packages/btc/src/transaction/build.ts index 724ef9ad..3c54b5aa 100644 --- a/packages/btc/src/transaction/build.ts +++ b/packages/btc/src/transaction/build.ts @@ -145,9 +145,9 @@ export class TxBuilder { const originalInputs = clone(this.inputs); const originalOutputs = clone(this.outputs); - // Create a cache key to prevent querying the Utxo[] too often + // Create a cache key to enable the internal caching, prevent querying the Utxo[] too often // TODO: consider provide an option to disable the cache - const cacheKey = `${Date.now()}`; + const internalCacheKey = `${Date.now()}`; // Fill a default recommended fee rate if props.feeRate is not provided let defaultFeeRate: number | undefined; @@ -181,7 +181,7 @@ export class TxBuilder { amount: returnAmount, fromAddress: address, fromPublicKey: publicKey, - cacheKey, + internalCacheKey, }); } else { // If the inputs have insufficient satoshi, a satoshi collection is required. @@ -194,7 +194,7 @@ export class TxBuilder { targetAmount, changeAddress, deductFromOutputs, - cacheKey, + internalCacheKey, }); } @@ -210,7 +210,7 @@ export class TxBuilder { } // Clear cache for the Utxo[] list - this.source.cache.cleanUtxos(cacheKey); + this.source.cache.cleanUtxos(internalCacheKey); return { fee: currentFee, @@ -225,7 +225,7 @@ export class TxBuilder { changeAddress?: string; injectCollected?: boolean; deductFromOutputs?: boolean; - cacheKey?: string; + internalCacheKey?: string; }) { if (!isSupportedFromAddress(props.address)) { throw TxBuildError.withComment(ErrorCodes.UNSUPPORTED_ADDRESS_TYPE, props.address); @@ -241,14 +241,18 @@ export class TxBuilder { /** * Collect from the "from" address via DataSource. * Will update the value of inputs/collected/changeAmount. + * + * The API has two layers of data caching: + * - noAssetsApiCache: BtcAssetsApi cache, can be disabled if the set to true + * - internalCacheKey: Internal cache, enabled if the key is provided */ const _collect = async (_targetAmount: number) => { const { utxos, satoshi } = await this.source.collectSatoshi({ address: props.address, targetAmount: _targetAmount, allowInsufficient: true, - noUtxosCache: true, - cacheKey: props.cacheKey, + noAssetsApiCache: true, + internalCacheKey: props.internalCacheKey, minUtxoSatoshi: this.minUtxoSatoshi, onlyNonRgbppUtxos: this.onlyNonRgbppUtxos, onlyConfirmedUtxos: this.onlyConfirmedUtxos, @@ -373,9 +377,9 @@ export class TxBuilder { address: string; fromAddress: string; fromPublicKey?: string; - cacheKey?: string; + internalCacheKey?: string; }) { - const { address, fromAddress, fromPublicKey, amount, cacheKey } = props; + const { address, fromAddress, fromPublicKey, amount, internalCacheKey } = props; // If any (output.fixed != true) is found in the outputs (search in ASC order), // return the change value to the first matched output. @@ -407,7 +411,7 @@ export class TxBuilder { changeAddress: address, injectCollected: true, deductFromOutputs: false, - cacheKey, + internalCacheKey, }); if (collected < amount) { throw TxBuildError.withComment(ErrorCodes.INSUFFICIENT_UTXO, `expected: ${amount}, actual: ${collected}`); From a8598e3413ff47d7fbc6d28dcc90b92948b25155 Mon Sep 17 00:00:00 2001 From: Dawn <13477199767@163.com> Date: Sat, 25 May 2024 02:03:22 +0800 Subject: [PATCH 75/78] refactor(examples): Save ckbVirtualTxResult locally --- examples/rgbpp/logs/.gitkeep | 0 examples/rgbpp/shared/utils.ts | 35 +++++++++++++++++++ examples/rgbpp/spore/4-transfer-spore.ts | 4 +++ examples/rgbpp/spore/5-leap-spore-to-ckb.ts | 4 +++ .../rgbpp/spore/launch/2-create-cluster.ts | 4 +++ .../rgbpp/spore/launch/3-create-spores.ts | 4 +++ .../rgbpp/spore/local/4-transfer-spore.ts | 4 +++ .../rgbpp/spore/local/5-leap-spore-to-ckb.ts | 4 +++ examples/rgbpp/xudt/2-btc-transfer.ts | 4 +++ examples/rgbpp/xudt/3-btc-leap-ckb.ts | 4 +++ examples/rgbpp/xudt/launch/2-launch-rgbpp.ts | 4 +++ .../rgbpp/xudt/launch/3-distribute-rgbpp.ts | 4 +++ examples/rgbpp/xudt/local/2-btc-transfer.ts | 4 +++ examples/rgbpp/xudt/local/3-btc-leap-ckb.ts | 4 +++ 14 files changed, 83 insertions(+) create mode 100644 examples/rgbpp/logs/.gitkeep create mode 100644 examples/rgbpp/shared/utils.ts diff --git a/examples/rgbpp/logs/.gitkeep b/examples/rgbpp/logs/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/examples/rgbpp/shared/utils.ts b/examples/rgbpp/shared/utils.ts new file mode 100644 index 00000000..57cdabca --- /dev/null +++ b/examples/rgbpp/shared/utils.ts @@ -0,0 +1,35 @@ +import * as fs from 'fs'; +import * as path from 'path'; + +/** + * Save ckbVirtualTxResult to a log file + * @param ckbVirtualTxResult - The ckbVirtualTxResult to save + * @param exampleName - Example name used to distinguish different log files + */ +export const saveCkbVirtualTxResult = (ckbVirtualTxResult: unknown, exampleName: string) => { + try { + // Define log file path + const logDir = path.resolve(__dirname, '../logs'); + const logFilePath = path.join(logDir, `${exampleName}-ckbVirtualTxResult.log`); + + // Ensure the log directory exists + if (!fs.existsSync(logDir)) { + fs.mkdirSync(logDir); + } + + // Validate and save ckbVirtualTxResult to log file + if (typeof ckbVirtualTxResult === 'object' && ckbVirtualTxResult !== null) { + fs.writeFileSync(logFilePath, JSON.stringify(ckbVirtualTxResult, null, 2)); + console.info(`Saved ckbVirtualTxResult to ${logFilePath}`); + } else { + console.error('Invalid ckbVirtualTxResult format'); + } + + // Remind developers to save the transaction result + console.info( + `Important: It's recommended to save the rgbpp_ckb_tx_virtual locally before the isomorphic transactions are finalized.`, + ); + } catch (error) { + console.error('Failed to save ckbVirtualTxResult:', error); + } +}; diff --git a/examples/rgbpp/spore/4-transfer-spore.ts b/examples/rgbpp/spore/4-transfer-spore.ts index 3a7738a0..7646f4fe 100644 --- a/examples/rgbpp/spore/4-transfer-spore.ts +++ b/examples/rgbpp/spore/4-transfer-spore.ts @@ -3,6 +3,7 @@ import { genTransferSporeCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; import { getSporeTypeScript, Hex } from 'rgbpp/ckb'; import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../env'; +import { saveCkbVirtualTxResult } from '../shared/utils'; interface SporeTransferParams { sporeRgbppLockArgs: Hex; @@ -23,6 +24,9 @@ const transferSpore = async ({ sporeRgbppLockArgs, toBtcAddress, sporeTypeArgs } isMainnet, }); + // Save ckbVirtualTxResult + saveCkbVirtualTxResult(ckbVirtualTxResult, '4-transfer-spore'); + const { commitment, ckbRawTx } = ckbVirtualTxResult; // Send BTC tx diff --git a/examples/rgbpp/spore/5-leap-spore-to-ckb.ts b/examples/rgbpp/spore/5-leap-spore-to-ckb.ts index c4af4cde..1f0ae59e 100644 --- a/examples/rgbpp/spore/5-leap-spore-to-ckb.ts +++ b/examples/rgbpp/spore/5-leap-spore-to-ckb.ts @@ -3,6 +3,7 @@ import { genLeapSporeFromBtcToCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; import { getSporeTypeScript, Hex } from 'rgbpp/ckb'; import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../env'; +import { saveCkbVirtualTxResult } from '../shared/utils'; interface SporeLeapParams { sporeRgbppLockArgs: Hex; @@ -24,6 +25,9 @@ const leapSporeFromBtcToCkb = async ({ sporeRgbppLockArgs, toCkbAddress, sporeTy isMainnet, }); + // Save ckbVirtualTxResult + saveCkbVirtualTxResult(ckbVirtualTxResult, '5-leap-spore-to-ckb'); + const { commitment, ckbRawTx } = ckbVirtualTxResult; // Send BTC tx diff --git a/examples/rgbpp/spore/launch/2-create-cluster.ts b/examples/rgbpp/spore/launch/2-create-cluster.ts index 5fefc541..97e3cdd1 100644 --- a/examples/rgbpp/spore/launch/2-create-cluster.ts +++ b/examples/rgbpp/spore/launch/2-create-cluster.ts @@ -9,6 +9,7 @@ import { sendCkbTx, updateCkbTxWithRealBtcTxId, } from 'rgbpp/ckb'; +import { saveCkbVirtualTxResult } from '../../shared/utils'; const createCluster = async ({ ownerRgbppLockArgs }: { ownerRgbppLockArgs: string }) => { const ckbVirtualTxResult = await genCreateClusterCkbVirtualTx({ @@ -19,6 +20,9 @@ const createCluster = async ({ ownerRgbppLockArgs }: { ownerRgbppLockArgs: strin ckbFeeRate: BigInt(2000), }); + // Save ckbVirtualTxResult + saveCkbVirtualTxResult(ckbVirtualTxResult, '2-create-cluster'); + const { commitment, ckbRawTx, clusterId } = ckbVirtualTxResult; console.log('clusterId: ', clusterId); diff --git a/examples/rgbpp/spore/launch/3-create-spores.ts b/examples/rgbpp/spore/launch/3-create-spores.ts index b073b067..342b8e6a 100644 --- a/examples/rgbpp/spore/launch/3-create-spores.ts +++ b/examples/rgbpp/spore/launch/3-create-spores.ts @@ -20,6 +20,7 @@ import { RawSporeData, } from 'rgbpp/ckb'; import { transactionToHex, utf8ToBuffer } from 'rgbpp/btc'; +import { saveCkbVirtualTxResult } from '../../shared/utils'; interface SporeCreateParams { clusterRgbppLockArgs: Hex; @@ -38,6 +39,9 @@ const createSpores = async ({ clusterRgbppLockArgs, receivers }: SporeCreatePara ckbFeeRate: BigInt(2000), }); + // Save ckbVirtualTxResult + saveCkbVirtualTxResult(ckbVirtualTxResult, '3-create-spores'); + const { commitment, ckbRawTx, sumInputsCapacity, clusterCell } = ckbVirtualTxResult; // Send BTC tx diff --git a/examples/rgbpp/spore/local/4-transfer-spore.ts b/examples/rgbpp/spore/local/4-transfer-spore.ts index 369a0a9f..28e89046 100644 --- a/examples/rgbpp/spore/local/4-transfer-spore.ts +++ b/examples/rgbpp/spore/local/4-transfer-spore.ts @@ -12,6 +12,7 @@ import { sendRgbppUtxos, transactionToHex } from 'rgbpp/btc'; import { BtcAssetsApiError } from 'rgbpp'; import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../env'; +import { saveCkbVirtualTxResult } from '../../shared/utils'; interface SporeTransferParams { sporeRgbppLockArgs: Hex; @@ -35,6 +36,9 @@ const transferSpore = async ({ sporeRgbppLockArgs, toBtcAddress, sporeTypeArgs } ckbFeeRate: BigInt(5000), }); + // Save ckbVirtualTxResult + saveCkbVirtualTxResult(ckbVirtualTxResult, '4-transfer-spore'); + const { commitment, ckbRawTx, sporeCell } = ckbVirtualTxResult; // console.log(JSON.stringify(ckbRawTx)) diff --git a/examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts b/examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts index 5d4cc7a3..c5eb3bf2 100644 --- a/examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts +++ b/examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts @@ -12,6 +12,7 @@ import { sendRgbppUtxos, transactionToHex } from 'rgbpp/btc'; import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../env'; import { BtcAssetsApiError } from 'rgbpp'; +import { saveCkbVirtualTxResult } from '../../shared/utils'; interface SporeLeapParams { sporeRgbppLockArgs: Hex; @@ -35,6 +36,9 @@ const leapSpore = async ({ sporeRgbppLockArgs, toCkbAddress, sporeTypeArgs }: Sp isMainnet, }); + // Save ckbVirtualTxResult + saveCkbVirtualTxResult(ckbVirtualTxResult, '5-leap-spore-to-ckb'); + const { commitment, ckbRawTx, sporeCell } = ckbVirtualTxResult; // console.log(JSON.stringify(ckbRawTx)) diff --git a/examples/rgbpp/xudt/2-btc-transfer.ts b/examples/rgbpp/xudt/2-btc-transfer.ts index 047d8822..0fdd274a 100644 --- a/examples/rgbpp/xudt/2-btc-transfer.ts +++ b/examples/rgbpp/xudt/2-btc-transfer.ts @@ -2,6 +2,7 @@ import { buildRgbppLockArgs, getXudtTypeScript } from 'rgbpp/ckb'; import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; import { genBtcTransferCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; import { isMainnet, collector, btcAddress, btcKeyPair, btcService, btcDataSource } from '../env'; +import { saveCkbVirtualTxResult } from '../shared/utils'; interface RgbppTransferParams { rgbppLockArgsList: string[]; @@ -24,6 +25,9 @@ const transfer = async ({ rgbppLockArgsList, toBtcAddress, xudtTypeArgs, transfe isMainnet, }); + // Save ckbVirtualTxResult + saveCkbVirtualTxResult(ckbVirtualTxResult, '2-btc-transfer'); + const { commitment, ckbRawTx } = ckbVirtualTxResult; // Send BTC tx diff --git a/examples/rgbpp/xudt/3-btc-leap-ckb.ts b/examples/rgbpp/xudt/3-btc-leap-ckb.ts index 406058b3..0f54b137 100644 --- a/examples/rgbpp/xudt/3-btc-leap-ckb.ts +++ b/examples/rgbpp/xudt/3-btc-leap-ckb.ts @@ -2,6 +2,7 @@ import { buildRgbppLockArgs, getXudtTypeScript } from 'rgbpp/ckb'; import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; import { genBtcJumpCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; import { isMainnet, collector, btcAddress, btcKeyPair, btcService, btcDataSource } from '../env'; +import { saveCkbVirtualTxResult } from '../shared/utils'; interface LeapToCkbParams { rgbppLockArgsList: string[]; @@ -25,6 +26,9 @@ const leapFromBtcToCKB = async ({ rgbppLockArgsList, toCkbAddress, xudtTypeArgs, isMainnet, }); + // Save ckbVirtualTxResult + saveCkbVirtualTxResult(ckbVirtualTxResult, '3-btc-leap-ckb'); + const { commitment, ckbRawTx } = ckbVirtualTxResult; // Send BTC tx diff --git a/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts b/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts index 50d751f5..d7708bcf 100644 --- a/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts +++ b/examples/rgbpp/xudt/launch/2-launch-rgbpp.ts @@ -9,6 +9,7 @@ import { import { RGBPP_TOKEN_INFO } from './0-rgbpp-token-info'; import { btcAddress, btcDataSource, btcKeyPair, btcService, collector, isMainnet } from '../../env'; import { transactionToHex } from 'rgbpp/btc'; +import { saveCkbVirtualTxResult } from '../../shared/utils'; interface Params { ownerRgbppLockArgs: string; @@ -24,6 +25,9 @@ const launchRgppAsset = async ({ ownerRgbppLockArgs, launchAmount, rgbppTokenInf isMainnet, }); + // Save ckbVirtualTxResult + saveCkbVirtualTxResult(ckbVirtualTxResult, '2-launch-rgbpp'); + const { commitment, ckbRawTx } = ckbVirtualTxResult; console.log('RGB++ Asset type script args: ', ckbRawTx.outputs[0].type?.args); diff --git a/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts b/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts index 2c801113..e9c25300 100644 --- a/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts +++ b/examples/rgbpp/xudt/launch/3-distribute-rgbpp.ts @@ -21,6 +21,7 @@ import { updateCkbTxWithRealBtcTxId, } from 'rgbpp/ckb'; import { transactionToHex } from 'rgbpp/btc'; +import { saveCkbVirtualTxResult } from '../../shared/utils'; interface Params { rgbppLockArgsList: string[]; @@ -43,6 +44,9 @@ const distributeRgbppAssetOnBtc = async ({ rgbppLockArgsList, receivers, xudtTyp isMainnet, }); + // Save ckbVirtualTxResult + saveCkbVirtualTxResult(ckbVirtualTxResult, '3-distribute-rgbpp'); + const { commitment, ckbRawTx, sumInputsCapacity, rgbppChangeOutIndex } = ckbVirtualTxResult; // The first output utxo is OP_RETURN diff --git a/examples/rgbpp/xudt/local/2-btc-transfer.ts b/examples/rgbpp/xudt/local/2-btc-transfer.ts index 4de9ab89..f70c7e7b 100644 --- a/examples/rgbpp/xudt/local/2-btc-transfer.ts +++ b/examples/rgbpp/xudt/local/2-btc-transfer.ts @@ -9,6 +9,7 @@ import { } from 'rgbpp/ckb'; import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../env'; import { transactionToHex } from 'rgbpp/btc'; +import { saveCkbVirtualTxResult } from '../../shared/utils'; interface RgbppTransferParams { rgbppLockArgsList: string[]; @@ -32,6 +33,9 @@ const transfer = async ({ rgbppLockArgsList, toBtcAddress, xudtTypeArgs, transfe isMainnet, }); + // Save ckbVirtualTxResult + saveCkbVirtualTxResult(ckbVirtualTxResult, '2-btc-transfer'); + const { commitment, ckbRawTx } = ckbVirtualTxResult; // Send BTC tx diff --git a/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts b/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts index 877015ed..45ba39d0 100644 --- a/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts +++ b/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts @@ -9,6 +9,7 @@ import { } from 'rgbpp/ckb'; import { isMainnet, collector, btcAddress, btcDataSource, btcKeyPair, btcService } from '../../env'; import { transactionToHex } from 'rgbpp/btc'; +import { saveCkbVirtualTxResult } from '../../shared/utils'; interface LeapToCkbParams { rgbppLockArgsList: string[]; @@ -33,6 +34,9 @@ const leapFromBtcToCkb = async ({ rgbppLockArgsList, toCkbAddress, xudtTypeArgs, isMainnet, }); + // Save ckbVirtualTxResult + saveCkbVirtualTxResult(ckbVirtualTxResult, '3-btc-leap-ckb'); + const { commitment, ckbRawTx } = ckbVirtualTxResult; // Send BTC tx From 6e1b54b7e60e1ab308dcba23e724f946026c3f70 Mon Sep 17 00:00:00 2001 From: Dawn <77844990+Dawn-githup@users.noreply.github.com> Date: Sat, 25 May 2024 20:38:25 +0800 Subject: [PATCH 76/78] test: Create integration tests for xUDT workflow (#169) * test: Create integration tests * chore: update dependencies * fix: Modify env secrets name to resolve ci errors * chore: Update configuration information in workflows * fix: Fix xudtTypeArgs reading error * chore: Update the description of integration tests * chore: Add empty 'testnet' folder with .gitkeep file * refactor: move integration test commands to package.json script for clarity * chore: rename issuexudt to xudt-on-ckb. * chore: remove duplicate 'pnpm i' command in CI --- .github/workflows/integration-test.yaml | 44 +++++++ package.json | 6 +- pnpm-lock.yaml | 92 ++++++++++---- pnpm-workspace.yaml | 1 + tests/rgbpp/env.ts | 34 ++++++ tests/rgbpp/package.json | 24 ++++ tests/rgbpp/shared/prepare-utxo.ts | 57 +++++++++ tests/rgbpp/shared/utils.ts | 25 ++++ tests/rgbpp/testnet/.gitkeep | 0 tests/rgbpp/tsconfig.json | 25 ++++ tests/rgbpp/xudt/1-ckb-leap-btc.ts | 54 +++++++++ tests/rgbpp/xudt/2-btc-transfer.ts | 85 +++++++++++++ tests/rgbpp/xudt/3-btc-leap-ckb.ts | 80 +++++++++++++ tests/rgbpp/xudt/xudt-on-ckb/1-issue-xudt.ts | 119 +++++++++++++++++++ 14 files changed, 622 insertions(+), 24 deletions(-) create mode 100644 .github/workflows/integration-test.yaml create mode 100644 tests/rgbpp/env.ts create mode 100644 tests/rgbpp/package.json create mode 100644 tests/rgbpp/shared/prepare-utxo.ts create mode 100644 tests/rgbpp/shared/utils.ts create mode 100644 tests/rgbpp/testnet/.gitkeep create mode 100644 tests/rgbpp/tsconfig.json create mode 100644 tests/rgbpp/xudt/1-ckb-leap-btc.ts create mode 100644 tests/rgbpp/xudt/2-btc-transfer.ts create mode 100644 tests/rgbpp/xudt/3-btc-leap-ckb.ts create mode 100644 tests/rgbpp/xudt/xudt-on-ckb/1-issue-xudt.ts diff --git a/.github/workflows/integration-test.yaml b/.github/workflows/integration-test.yaml new file mode 100644 index 00000000..e70dfaad --- /dev/null +++ b/.github/workflows/integration-test.yaml @@ -0,0 +1,44 @@ +# Test the entire process of RGBPP to ensure the proper functioning of the rgbpp-sdk package. + +name: Integration Tests + +on: + workflow_dispatch: + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout rgbpp-sdk + uses: actions/checkout@v4 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: 20.x + + - uses: pnpm/action-setup@v3 + name: Install -g pnpm + with: + version: 8 + run_install: false + + - name: Install dependencies + run: pnpm i + + - name: Build packages + run: pnpm run build:packages + + - name: Run integration:xudt script + working-directory: ./tests/rgbpp + run: pnpm run integration:xudt + env: + VITE_SERVICE_URL: ${{ secrets.SERVICE_URL }} + VITE_SERVICE_TOKEN: ${{ secrets.SERVICE_TOKEN }} + VITE_SERVICE_ORIGIN: ${{ secrets.SERVICE_ORIGIN }} + INTEGRATION_CKB_PRIVATE_KEY: ${{ secrets.INTEGRATION_CKB_PRIVATE_KEY }} + INTEGRATION_BTC_PRIVATE_KEY: ${{ secrets.INTEGRATION_BTC_PRIVATE_KEY }} diff --git a/package.json b/package.json index e9eb6282..f9543082 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,8 @@ "test:packages": "turbo run test --filter=./packages/*", "build:packages": "turbo run build --filter=./packages/*", "lint:fix": "turbo run lint:fix", - "lint:packages": "turbo run lint --filter=./{packages,examples}/*", - "format": "prettier --write '{packages,apps,examples}/**/*.{js,jsx,ts,tsx}'", + "lint:packages": "turbo run lint --filter=./{packages,examples,tests}/*", + "format": "prettier --write '{packages,apps,examples,tests}/**/*.{js,jsx,ts,tsx}'", "clean": "turbo run clean", "clean:packages": "turbo run clean --filter=./packages/*", "clean:dependencies": "pnpm clean:sub-dependencies && rimraf node_modules", @@ -33,7 +33,7 @@ "typescript": "^5.4.3" }, "lint-staged": { - "{packages,apps,examples}/**/*.{js,jsx,ts,tsx}": [ + "{packages,apps,examples,tests}/**/*.{js,jsx,ts,tsx}": [ "eslint --fix", "prettier --ignore-unknown --write" ] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3dd4ecbd..d58421ea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -40,7 +40,7 @@ importers: version: 5.0.5 ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@20.12.2)(typescript@5.4.3) + version: 10.9.2(@types/node@20.12.12)(typescript@5.4.3) turbo: specifier: ^1.13.0 version: 1.13.0 @@ -132,7 +132,7 @@ importers: version: 5.4.2 vite: specifier: ^5.2.11 - version: 5.2.11(@types/node@20.12.2) + version: 5.2.11(@types/node@20.12.12) vite-plugin-node-polyfills: specifier: ^0.21.0 version: 0.21.0(vite@5.2.11) @@ -210,7 +210,7 @@ importers: version: 4.17.0 vitest: specifier: ^1.4.0 - version: 1.4.0(@types/node@20.12.2) + version: 1.4.0(@types/node@20.12.12) packages/ckb: dependencies: @@ -256,7 +256,7 @@ importers: version: 4.17.0 vitest: specifier: ^1.4.0 - version: 1.4.0(@types/node@20.12.2) + version: 1.4.0(@types/node@20.12.12) packages/rgbpp: dependencies: @@ -290,7 +290,32 @@ importers: version: 4.17.0 vitest: specifier: ^1.4.0 - version: 1.4.0(@types/node@20.12.2) + version: 1.4.0(@types/node@20.12.12) + + tests/rgbpp: + dependencies: + '@nervosnetwork/ckb-sdk-utils': + specifier: ^0.109.1 + version: 0.109.1 + rgbpp: + specifier: workspace:* + version: link:../../packages/rgbpp + zx: + specifier: ^8.0.2 + version: 8.1.0 + devDependencies: + '@types/dotenv': + specifier: ^8.2.0 + version: 8.2.0 + '@types/node': + specifier: ^20.11.28 + version: 20.12.12 + dotenv: + specifier: ^16.4.5 + version: 16.4.5 + typescript: + specifier: ^5.4.2 + version: 5.4.3 packages: @@ -1710,10 +1735,27 @@ packages: resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} dev: true + /@types/fs-extra@11.0.4: + resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} + requiresBuild: true + dependencies: + '@types/jsonfile': 6.1.4 + '@types/node': 20.12.12 + dev: false + optional: true + /@types/json-schema@7.0.15: resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} dev: true + /@types/jsonfile@6.1.4: + resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} + requiresBuild: true + dependencies: + '@types/node': 20.12.12 + dev: false + optional: true + /@types/lodash.isequal@4.5.8: resolution: {integrity: sha512-uput6pg4E/tj2LGxCZo9+y27JNyB2OZuuI/T5F+ylVDYuqICLG2/ktjxx0v6GvVntAf8TvEzeQLcV0ffRirXuA==} dependencies: @@ -1745,11 +1787,11 @@ packages: undici-types: 5.26.5 dev: true - /@types/node@20.12.2: - resolution: {integrity: sha512-zQ0NYO87hyN6Xrclcqp7f8ZbXNbRfoGWNcMvHTPQp9UUrwI0mI7XBz+cu7/W6/VClYo2g63B0cjull/srU7LgQ==} + /@types/node@20.12.12: + resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==} + requiresBuild: true dependencies: undici-types: 5.26.5 - dev: true /@types/normalize-package-data@2.4.4: resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -2060,7 +2102,7 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.23.3(@babel/core@7.24.0) '@types/babel__core': 7.20.5 react-refresh: 0.14.0 - vite: 5.2.11(@types/node@20.12.2) + vite: 5.2.11(@types/node@20.12.12) transitivePeerDependencies: - supports-color dev: true @@ -5664,7 +5706,7 @@ packages: typescript: 5.4.3 dev: true - /ts-node@10.9.2(@types/node@20.12.2)(typescript@5.4.3): + /ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.3): resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true peerDependencies: @@ -5683,7 +5725,7 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.12.2 + '@types/node': 20.12.12 acorn: 8.11.3 acorn-walk: 8.3.2 arg: 4.1.3 @@ -5893,7 +5935,6 @@ packages: /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: true /universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} @@ -5959,7 +6000,7 @@ packages: safe-buffer: 5.2.1 dev: false - /vite-node@1.4.0(@types/node@20.12.2): + /vite-node@1.4.0(@types/node@20.12.12): resolution: {integrity: sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -5968,7 +6009,7 @@ packages: debug: 4.3.4 pathe: 1.1.2 picocolors: 1.0.0 - vite: 5.2.11(@types/node@20.12.2) + vite: 5.2.11(@types/node@20.12.12) transitivePeerDependencies: - '@types/node' - less @@ -5987,12 +6028,12 @@ packages: dependencies: '@rollup/plugin-inject': 5.0.5 node-stdlib-browser: 1.2.0 - vite: 5.2.11(@types/node@20.12.2) + vite: 5.2.11(@types/node@20.12.12) transitivePeerDependencies: - rollup dev: true - /vite@5.2.11(@types/node@20.12.2): + /vite@5.2.11(@types/node@20.12.12): resolution: {integrity: sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -6020,7 +6061,7 @@ packages: terser: optional: true dependencies: - '@types/node': 20.12.2 + '@types/node': 20.12.12 esbuild: 0.20.2 postcss: 8.4.38 rollup: 4.13.2 @@ -6028,7 +6069,7 @@ packages: fsevents: 2.3.3 dev: true - /vitest@1.4.0(@types/node@20.12.2): + /vitest@1.4.0(@types/node@20.12.12): resolution: {integrity: sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -6053,7 +6094,7 @@ packages: jsdom: optional: true dependencies: - '@types/node': 20.12.2 + '@types/node': 20.12.12 '@vitest/expect': 1.4.0 '@vitest/runner': 1.4.0 '@vitest/snapshot': 1.4.0 @@ -6071,8 +6112,8 @@ packages: strip-literal: 2.1.0 tinybench: 2.6.0 tinypool: 0.8.3 - vite: 5.2.11(@types/node@20.12.2) - vite-node: 1.4.0(@types/node@20.12.2) + vite: 5.2.11(@types/node@20.12.12) + vite-node: 1.4.0(@types/node@20.12.12) why-is-node-running: 2.2.2 transitivePeerDependencies: - less @@ -6294,3 +6335,12 @@ packages: resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} engines: {node: '>=12.20'} dev: true + + /zx@8.1.0: + resolution: {integrity: sha512-2BCoOK6JTWikAkwPCV2dFr+1ou29WoY+6XltLu+Ou9dvxrqm/p+HuHCgBtMRMIVFexQzUSGfB5VbYeY8XmGBPQ==} + engines: {node: '>= 12.17.0'} + hasBin: true + optionalDependencies: + '@types/fs-extra': 11.0.4 + '@types/node': 20.12.12 + dev: false diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index a1167940..1dfad62c 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,3 +2,4 @@ packages: - "packages/*" - "apps/*" - "examples/*" + - "tests/*" diff --git a/tests/rgbpp/env.ts b/tests/rgbpp/env.ts new file mode 100644 index 00000000..e65e8a27 --- /dev/null +++ b/tests/rgbpp/env.ts @@ -0,0 +1,34 @@ +import { AddressPrefix, privateKeyToAddress } from '@nervosnetwork/ckb-sdk-utils'; +import { DataSource, BtcAssetsApi } from 'rgbpp'; +import { ECPair, ECPairInterface, bitcoin, NetworkType } from 'rgbpp/btc'; +import dotenv from 'dotenv'; +import { Collector } from 'rgbpp/ckb'; + +dotenv.config({ path: __dirname + '/.env' }); + +export const isMainnet = false; + +export const collector = new Collector({ + ckbNodeUrl: 'https://testnet.ckb.dev/rpc', + ckbIndexerUrl: 'https://testnet.ckb.dev/indexer', +}); +export const CKB_PRIVATE_KEY = process.env.INTEGRATION_CKB_PRIVATE_KEY!; +export const ckbAddress = privateKeyToAddress(CKB_PRIVATE_KEY, { + prefix: isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, +}); + +export const BTC_PRIVATE_KEY = process.env.INTEGRATION_BTC_PRIVATE_KEY!; +export const BTC_SERVICE_URL = process.env.VITE_SERVICE_URL!; +export const BTC_SERVICE_TOKEN = process.env.VITE_SERVICE_TOKEN!; +export const BTC_SERVICE_ORIGIN = process.env.VITE_SERVICE_ORIGIN!; + +const network = isMainnet ? bitcoin.networks.bitcoin : bitcoin.networks.testnet; +export const btcKeyPair: ECPairInterface = ECPair.fromPrivateKey(Buffer.from(BTC_PRIVATE_KEY, 'hex'), { network }); +export const { address: btcAddress } = bitcoin.payments.p2wpkh({ + pubkey: btcKeyPair.publicKey, + network, +}); + +const networkType = isMainnet ? NetworkType.MAINNET : NetworkType.TESTNET; +export const btcService = BtcAssetsApi.fromToken(BTC_SERVICE_URL, BTC_SERVICE_TOKEN, BTC_SERVICE_ORIGIN); +export const btcDataSource = new DataSource(btcService, networkType); diff --git a/tests/rgbpp/package.json b/tests/rgbpp/package.json new file mode 100644 index 00000000..33f834c2 --- /dev/null +++ b/tests/rgbpp/package.json @@ -0,0 +1,24 @@ +{ + "name": "rgbpp-integration-tests", + "version": "0.1.0", + "description": "Test the entire process of RGBPP to ensure the proper functioning of the rgbpp-sdk package.", + "private": true, + "type": "commonjs", + "scripts": { + "format": "prettier --write '**/*.{js,ts}'", + "lint": "tsc && eslint . && prettier --check '**/*.{js,ts}'", + "lint:fix": "tsc && eslint --fix --ext .js,.ts . && prettier --write '**/*.{js,ts}'", + "integration:xudt": "npx ts-node shared/prepare-utxo.ts && npx ts-node xudt/xudt-on-ckb/1-issue-xudt.ts && npx ts-node xudt/1-ckb-leap-btc.ts && npx ts-node xudt/2-btc-transfer.ts && npx ts-node xudt/3-btc-leap-ckb.ts" + }, + "dependencies": { + "@nervosnetwork/ckb-sdk-utils": "^0.109.1", + "rgbpp": "workspace:*", + "zx": "^8.0.2" + }, + "devDependencies": { + "@types/node": "^20.11.28", + "typescript": "^5.4.2", + "dotenv": "^16.4.5", + "@types/dotenv": "^8.2.0" + } +} diff --git a/tests/rgbpp/shared/prepare-utxo.ts b/tests/rgbpp/shared/prepare-utxo.ts new file mode 100644 index 00000000..582917d5 --- /dev/null +++ b/tests/rgbpp/shared/prepare-utxo.ts @@ -0,0 +1,57 @@ +import { sendBtc } from 'rgbpp/btc'; +import { getFastestFeeRate, writeStepLog } from './utils'; +import { BtcAssetsApiError } from 'rgbpp/service'; +import { btcAddress, btcDataSource, btcKeyPair, btcService } from '../env'; + +const prepareUtxo = async () => { + const feeRate = await getFastestFeeRate(); + console.log('feeRate = ', feeRate); + console.log(btcAddress); + + // Send BTC tx + const psbt = await sendBtc({ + from: btcAddress!, + tos: [ + { + address: btcAddress!, + value: 546, + minUtxoSatoshi: 546, + }, + ], + feeRate: feeRate, + source: btcDataSource, + }); + + // Sign & finalize inputs + psbt.signAllInputs(btcKeyPair); + psbt.finalizeAllInputs(); + + // Broadcast transaction + const tx = psbt.extractTransaction(); + console.log(tx.toHex()); + + const { txid: btcTxId } = await btcService.sendBtcTransaction(tx.toHex()); + console.log(`explorer: https://mempool.space/testnet/tx/${btcTxId}`); + + writeStepLog('0', { + txid: btcTxId, + index: 0, + }); + + const interval = setInterval(async () => { + try { + console.log('Waiting for BTC tx to be confirmed'); + const tx = await btcService.getBtcTransaction(btcTxId); + if (tx.status.confirmed) { + clearInterval(interval); + console.info(`Utxo is confirmed ${btcTxId}:0`); + } + } catch (error) { + if (!(error instanceof BtcAssetsApiError)) { + console.error(error); + } + } + }, 20 * 1000); +}; + +prepareUtxo(); diff --git a/tests/rgbpp/shared/utils.ts b/tests/rgbpp/shared/utils.ts new file mode 100644 index 00000000..79394338 --- /dev/null +++ b/tests/rgbpp/shared/utils.ts @@ -0,0 +1,25 @@ +import 'dotenv/config'; +import * as fs from 'fs'; +import * as path from 'path'; +import { btcService } from '../env'; + +export const network = 'testnet'; + +export async function getFastestFeeRate() { + const fees = await btcService.getBtcRecommendedFeeRates(); + return Math.ceil(fees.fastestFee * 3); +} + +export async function writeStepLog(step: string, data: string | object) { + const file = path.join(__dirname, `../${network}/step-${step}.log`); + if (typeof data !== 'string') { + data = JSON.stringify(data); + } + + fs.writeFileSync(file, data); +} + +export function readStepLog(step: string) { + const file = path.join(__dirname, `../${network}/step-${step}.log`); + return JSON.parse(fs.readFileSync(file).toString()); +} diff --git a/tests/rgbpp/testnet/.gitkeep b/tests/rgbpp/testnet/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/tests/rgbpp/tsconfig.json b/tests/rgbpp/tsconfig.json new file mode 100644 index 00000000..b5f09128 --- /dev/null +++ b/tests/rgbpp/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "target": "ES2015", + "lib": ["dom", "dom.iterable", "esnext"], + "module": "NodeNext", + "composite": false, + "resolveJsonModule": true, + "strictNullChecks": true, + "noEmit": true, + "declaration": true, + "declarationMap": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "inlineSources": false, + "isolatedModules": true, + "moduleResolution": "NodeNext", + "noUnusedLocals": false, + "noUnusedParameters": false, + "preserveWatchOutput": true, + "skipLibCheck": true, + "strict": true + }, + "exclude": ["node_modules"] +} diff --git a/tests/rgbpp/xudt/1-ckb-leap-btc.ts b/tests/rgbpp/xudt/1-ckb-leap-btc.ts new file mode 100644 index 00000000..93401b91 --- /dev/null +++ b/tests/rgbpp/xudt/1-ckb-leap-btc.ts @@ -0,0 +1,54 @@ +import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; +import { genCkbJumpBtcVirtualTx } from 'rgbpp'; +import { getSecp256k1CellDep, buildRgbppLockArgs, getXudtTypeScript } from 'rgbpp/ckb'; +import { CKB_PRIVATE_KEY, isMainnet, collector, ckbAddress } from '../env'; +import { readStepLog } from '../shared/utils'; + +interface LeapToBtcParams { + outIndex: number; + btcTxId: string; + xudtTypeArgs: string; + transferAmount: bigint; +} + +const leapFromCkbToBtc = async ({ outIndex, btcTxId, xudtTypeArgs, transferAmount }: LeapToBtcParams) => { + const { retry } = await import('zx'); + await retry(20, '10s', async () => { + const toRgbppLockArgs = buildRgbppLockArgs(outIndex, btcTxId); + + // Warning: Please replace with your real xUDT type script here + const xudtType: CKBComponents.Script = { + ...getXudtTypeScript(isMainnet), + args: xudtTypeArgs, + }; + + const ckbRawTx = await genCkbJumpBtcVirtualTx({ + collector, + fromCkbAddress: ckbAddress, + toRgbppLockArgs, + xudtTypeBytes: serializeScript(xudtType), + transferAmount, + }); + + const emptyWitness = { lock: '', inputType: '', outputType: '' }; + const unsignedTx: CKBComponents.RawTransactionToSign = { + ...ckbRawTx, + cellDeps: [...ckbRawTx.cellDeps, getSecp256k1CellDep(false)], + witnesses: [emptyWitness, ...ckbRawTx.witnesses.slice(1)], + }; + + const signedTx = collector.getCkb().signTransaction(CKB_PRIVATE_KEY)(unsignedTx); + + const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); + console.info(`Rgbpp asset has been jumped from CKB to BTC and tx hash is ${txHash}`); + console.info(`explorer: https://pudge.explorer.nervos.org/transaction/${txHash}`); + }); +}; + +// Use your real BTC UTXO information on the BTC Testnet +leapFromCkbToBtc({ + outIndex: readStepLog('0').index, + btcTxId: readStepLog('0').txid, + xudtTypeArgs: readStepLog('1').args, + transferAmount: BigInt(800_0000_0000), +}); diff --git a/tests/rgbpp/xudt/2-btc-transfer.ts b/tests/rgbpp/xudt/2-btc-transfer.ts new file mode 100644 index 00000000..884697eb --- /dev/null +++ b/tests/rgbpp/xudt/2-btc-transfer.ts @@ -0,0 +1,85 @@ +import { buildRgbppLockArgs, getXudtTypeScript } from 'rgbpp/ckb'; +import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; +import { genBtcTransferCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; +import { isMainnet, collector, btcAddress, btcKeyPair, btcService, btcDataSource } from '../env'; +import { readStepLog, writeStepLog } from '../shared/utils'; + +interface RgbppTransferParams { + rgbppLockArgsList: string[]; + toBtcAddress: string; + xudtTypeArgs: string; + transferAmount: bigint; +} + +const transfer = async ({ rgbppLockArgsList, toBtcAddress, xudtTypeArgs, transferAmount }: RgbppTransferParams) => { + const { retry } = await import('zx'); + await retry(120, '10s', async () => { + const xudtType: CKBComponents.Script = { + ...getXudtTypeScript(isMainnet), + args: xudtTypeArgs, + }; + + const ckbVirtualTxResult = await genBtcTransferCkbVirtualTx({ + collector, + rgbppLockArgsList, + xudtTypeBytes: serializeScript(xudtType), + transferAmount, + isMainnet, + }); + + const { commitment, ckbRawTx } = ckbVirtualTxResult; + + // Send BTC tx + const psbt = await sendRgbppUtxos({ + ckbVirtualTx: ckbRawTx, + commitment, + tos: [toBtcAddress], + ckbCollector: collector, + from: btcAddress!, + source: btcDataSource, + }); + psbt.signAllInputs(btcKeyPair); + psbt.finalizeAllInputs(); + + const btcTx = psbt.extractTransaction(); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); + + console.log('BTC TxId: ', btcTxId); + console.log(`explorer: https://mempool.space/testnet/tx/${btcTxId}`); + + writeStepLog('2', { + txid: btcTxId, + index: 1, + }); + + await btcService.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); + + try { + const interval = setInterval(async () => { + const { state, failedReason } = await btcService.getRgbppTransactionState(btcTxId); + console.log('state', state); + if (state === 'completed' || state === 'failed') { + clearInterval(interval); + if (state === 'completed') { + const { txhash: txHash } = await btcService.getRgbppTransactionHash(btcTxId); + console.info(`Rgbpp asset has been transferred on BTC and the related CKB tx hash is ${txHash}`); + console.info(`explorer: https://pudge.explorer.nervos.org/transaction/${txHash}`); + } else { + console.warn(`Rgbpp CKB transaction failed and the reason is ${failedReason} `); + } + } + }, 30 * 1000); + } catch (error) { + console.error(error); + } + }); +}; + +// Use your real BTC UTXO information on the BTC Testnet +// rgbppLockArgs: outIndexU32 + btcTxId +transfer({ + rgbppLockArgsList: [buildRgbppLockArgs(readStepLog('0').index, readStepLog('0').txid)], + toBtcAddress: 'tb1qtt2vh9q8xam35xxsy35ec6majad8lz8fep8w04', + xudtTypeArgs: readStepLog('1').args, + transferAmount: BigInt(500_0000_0000), +}); diff --git a/tests/rgbpp/xudt/3-btc-leap-ckb.ts b/tests/rgbpp/xudt/3-btc-leap-ckb.ts new file mode 100644 index 00000000..578dafcc --- /dev/null +++ b/tests/rgbpp/xudt/3-btc-leap-ckb.ts @@ -0,0 +1,80 @@ +import { buildRgbppLockArgs, getXudtTypeScript } from 'rgbpp/ckb'; +import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; +import { genBtcJumpCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; +import { isMainnet, collector, btcAddress, btcKeyPair, btcService, btcDataSource } from '../env'; +import { readStepLog } from '../shared/utils'; + +interface LeapToCkbParams { + rgbppLockArgsList: string[]; + toCkbAddress: string; + xudtTypeArgs: string; + transferAmount: bigint; +} + +const leapFromBtcToCKB = async ({ rgbppLockArgsList, toCkbAddress, xudtTypeArgs, transferAmount }: LeapToCkbParams) => { + const { retry } = await import('zx'); + await retry(120, '10s', async () => { + const xudtType: CKBComponents.Script = { + ...getXudtTypeScript(isMainnet), + args: xudtTypeArgs, + }; + + const ckbVirtualTxResult = await genBtcJumpCkbVirtualTx({ + collector, + rgbppLockArgsList, + xudtTypeBytes: serializeScript(xudtType), + transferAmount, + toCkbAddress, + isMainnet, + }); + + const { commitment, ckbRawTx } = ckbVirtualTxResult; + + // Send BTC tx + const psbt = await sendRgbppUtxos({ + ckbVirtualTx: ckbRawTx, + commitment, + tos: [btcAddress!], + ckbCollector: collector, + from: btcAddress!, + source: btcDataSource, + }); + psbt.signAllInputs(btcKeyPair); + psbt.finalizeAllInputs(); + + const btcTx = psbt.extractTransaction(); + const { txid: btcTxId } = await btcService.sendBtcTransaction(btcTx.toHex()); + + console.log('BTC TxId: ', btcTxId); + console.log(`explorer: https://mempool.space/testnet/tx/${btcTxId}`); + + await btcService.sendRgbppCkbTransaction({ btc_txid: btcTxId, ckb_virtual_result: ckbVirtualTxResult }); + + try { + const interval = setInterval(async () => { + const { state, failedReason } = await btcService.getRgbppTransactionState(btcTxId); + console.log('state', state); + if (state === 'completed' || state === 'failed') { + clearInterval(interval); + if (state === 'completed') { + const { txhash: txHash } = await btcService.getRgbppTransactionHash(btcTxId); + console.info(`Rgbpp asset has been jumped from BTC to CKB and the related CKB tx hash is ${txHash}`); + console.info(`explorer: https://pudge.explorer.nervos.org/transaction/${txHash}`); + } else { + console.warn(`Rgbpp CKB transaction failed and the reason is ${failedReason} `); + } + } + }, 30 * 1000); + } catch (error) { + console.error(error); + } + }); +}; + +// rgbppLockArgs: outIndexU32 + btcTxId +leapFromBtcToCKB({ + rgbppLockArgsList: [buildRgbppLockArgs(readStepLog('2').index, readStepLog('2').txid)], + toCkbAddress: 'ckt1qrfrwcdnvssswdwpn3s9v8fp87emat306ctjwsm3nmlkjg8qyza2cqgqq9kxr7vy7yknezj0vj0xptx6thk6pwyr0sxamv6q', + xudtTypeArgs: readStepLog('1').args, + transferAmount: BigInt(300_0000_0000), +}); diff --git a/tests/rgbpp/xudt/xudt-on-ckb/1-issue-xudt.ts b/tests/rgbpp/xudt/xudt-on-ckb/1-issue-xudt.ts new file mode 100644 index 00000000..5430e4b7 --- /dev/null +++ b/tests/rgbpp/xudt/xudt-on-ckb/1-issue-xudt.ts @@ -0,0 +1,119 @@ +import { addressToScript, getTransactionSize, scriptToHash } from '@nervosnetwork/ckb-sdk-utils'; +import { + getSecp256k1CellDep, + RgbppTokenInfo, + NoLiveCellError, + calculateUdtCellCapacity, + MAX_FEE, + MIN_CAPACITY, + getXudtTypeScript, + append0x, + getUniqueTypeScript, + u128ToLe, + encodeRgbppTokenInfo, + getXudtDep, + getUniqueTypeDep, + SECP256K1_WITNESS_LOCK_SIZE, + calculateTransactionFee, + generateUniqueTypeArgs, + calculateXudtTokenInfoCellCapacity, +} from 'rgbpp/ckb'; +import { CKB_PRIVATE_KEY, ckbAddress, collector, isMainnet } from '../../env'; +import { writeStepLog } from '../../shared/utils'; + +/** + * issueXudt can be used to issue xUDT assets with unique cell as token info cell. + * @param xudtTotalAmount The xudtTotalAmount specifies the total amount of asset issuance + * @param tokenInfo The xUDT token info which includes decimal, name and symbol + */ +const issueXudt = async ({ xudtTotalAmount, tokenInfo }: { xudtTotalAmount: bigint; tokenInfo: RgbppTokenInfo }) => { + const issueLock = addressToScript(ckbAddress); + + let emptyCells = await collector.getCells({ + lock: issueLock, + }); + if (!emptyCells || emptyCells.length === 0) { + throw new NoLiveCellError('The address has no empty cells'); + } + emptyCells = emptyCells.filter((cell) => !cell.output.type); + + const xudtCapacity = calculateUdtCellCapacity(issueLock); + const xudtInfoCapacity = calculateXudtTokenInfoCellCapacity(tokenInfo, issueLock); + + const txFee = MAX_FEE; + const { inputs, sumInputsCapacity } = collector.collectInputs(emptyCells, xudtCapacity + xudtInfoCapacity, txFee, { + minCapacity: MIN_CAPACITY, + }); + + const xudtType: CKBComponents.Script = { + ...getXudtTypeScript(isMainnet), + args: append0x(scriptToHash(issueLock)), + }; + + console.log('xUDT type script', xudtType); + + writeStepLog('1', { + codeHash: xudtType.codeHash, + hashType: xudtType.hashType, + args: xudtType.args, + }); + + let changeCapacity = sumInputsCapacity - xudtCapacity - xudtInfoCapacity; + const outputs: CKBComponents.CellOutput[] = [ + { + lock: issueLock, + type: xudtType, + capacity: append0x(xudtCapacity.toString(16)), + }, + { + lock: issueLock, + type: { + ...getUniqueTypeScript(isMainnet), + args: generateUniqueTypeArgs(inputs[0], 1), + }, + capacity: append0x(xudtInfoCapacity.toString(16)), + }, + { + lock: issueLock, + capacity: append0x(changeCapacity.toString(16)), + }, + ]; + const totalAmount = xudtTotalAmount * BigInt(10 ** tokenInfo.decimal); + const outputsData = [append0x(u128ToLe(totalAmount)), encodeRgbppTokenInfo(tokenInfo), '0x']; + + const emptyWitness = { lock: '', inputType: '', outputType: '' }; + const witnesses = inputs.map((_, index) => (index === 0 ? emptyWitness : '0x')); + + const cellDeps = [getSecp256k1CellDep(isMainnet), getUniqueTypeDep(isMainnet), getXudtDep(isMainnet)]; + + const unsignedTx = { + version: '0x0', + cellDeps, + headerDeps: [], + inputs, + outputs, + outputsData, + witnesses, + }; + + if (txFee === MAX_FEE) { + const txSize = getTransactionSize(unsignedTx) + SECP256K1_WITNESS_LOCK_SIZE; + const estimatedTxFee = calculateTransactionFee(txSize); + changeCapacity -= estimatedTxFee; + unsignedTx.outputs[unsignedTx.outputs.length - 1].capacity = append0x(changeCapacity.toString(16)); + } + + const signedTx = collector.getCkb().signTransaction(CKB_PRIVATE_KEY)(unsignedTx); + const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); + + console.info(`xUDT asset on CKB has been issued and tx hash is ${txHash}`); + console.info(`explorer: https://pudge.explorer.nervos.org/transaction/${txHash}`); +}; + +const XUDT_TOKEN_INFO: RgbppTokenInfo = { + decimal: 8, + name: 'XUDT Test Token', + symbol: 'PDD', +}; + +issueXudt({ xudtTotalAmount: BigInt(2100_0000), tokenInfo: XUDT_TOKEN_INFO }); From c1a9729dc6bd687246a813a39822a1a859a0393f Mon Sep 17 00:00:00 2001 From: Dawn <13477199767@163.com> Date: Sun, 26 May 2024 10:13:53 +0800 Subject: [PATCH 77/78] chore: define and use CkbVirtualTxResultType in saveCkbVirtualTxResult --- examples/rgbpp/shared/utils.ts | 18 ++++++++++++++++-- examples/rgbpp/spore/local/4-transfer-spore.ts | 2 +- .../rgbpp/spore/local/5-leap-spore-to-ckb.ts | 2 +- examples/rgbpp/xudt/local/2-btc-transfer.ts | 2 +- examples/rgbpp/xudt/local/3-btc-leap-ckb.ts | 2 +- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/examples/rgbpp/shared/utils.ts b/examples/rgbpp/shared/utils.ts index 57cdabca..2c5d2e6f 100644 --- a/examples/rgbpp/shared/utils.ts +++ b/examples/rgbpp/shared/utils.ts @@ -1,16 +1,30 @@ import * as fs from 'fs'; import * as path from 'path'; +import { + BaseCkbVirtualTxResult, + SporeVirtualTxResult, + SporeCreateVirtualTxResult, + SporeTransferVirtualTxResult, +} from 'rgbpp/ckb'; /** * Save ckbVirtualTxResult to a log file * @param ckbVirtualTxResult - The ckbVirtualTxResult to save * @param exampleName - Example name used to distinguish different log files */ -export const saveCkbVirtualTxResult = (ckbVirtualTxResult: unknown, exampleName: string) => { + +export type CkbVirtualTxResultType = + | BaseCkbVirtualTxResult + | SporeVirtualTxResult + | SporeCreateVirtualTxResult + | SporeTransferVirtualTxResult; + +export const saveCkbVirtualTxResult = (ckbVirtualTxResult: CkbVirtualTxResultType, exampleName: string) => { try { // Define log file path const logDir = path.resolve(__dirname, '../logs'); - const logFilePath = path.join(logDir, `${exampleName}-ckbVirtualTxResult.log`); + const timestamp = new Date().toISOString().replace(/:/g, '-'); // Replace colons with hyphens + const logFilePath = path.join(logDir, `${exampleName}-${timestamp}-ckbVirtualTxResult.log`); // Ensure the log directory exists if (!fs.existsSync(logDir)) { diff --git a/examples/rgbpp/spore/local/4-transfer-spore.ts b/examples/rgbpp/spore/local/4-transfer-spore.ts index 28e89046..a695c818 100644 --- a/examples/rgbpp/spore/local/4-transfer-spore.ts +++ b/examples/rgbpp/spore/local/4-transfer-spore.ts @@ -37,7 +37,7 @@ const transferSpore = async ({ sporeRgbppLockArgs, toBtcAddress, sporeTypeArgs } }); // Save ckbVirtualTxResult - saveCkbVirtualTxResult(ckbVirtualTxResult, '4-transfer-spore'); + saveCkbVirtualTxResult(ckbVirtualTxResult, '4-transfer-spore-local'); const { commitment, ckbRawTx, sporeCell } = ckbVirtualTxResult; diff --git a/examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts b/examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts index c5eb3bf2..06856e96 100644 --- a/examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts +++ b/examples/rgbpp/spore/local/5-leap-spore-to-ckb.ts @@ -37,7 +37,7 @@ const leapSpore = async ({ sporeRgbppLockArgs, toCkbAddress, sporeTypeArgs }: Sp }); // Save ckbVirtualTxResult - saveCkbVirtualTxResult(ckbVirtualTxResult, '5-leap-spore-to-ckb'); + saveCkbVirtualTxResult(ckbVirtualTxResult, '5-leap-spore-to-ckb-local'); const { commitment, ckbRawTx, sporeCell } = ckbVirtualTxResult; diff --git a/examples/rgbpp/xudt/local/2-btc-transfer.ts b/examples/rgbpp/xudt/local/2-btc-transfer.ts index f70c7e7b..92a4185d 100644 --- a/examples/rgbpp/xudt/local/2-btc-transfer.ts +++ b/examples/rgbpp/xudt/local/2-btc-transfer.ts @@ -34,7 +34,7 @@ const transfer = async ({ rgbppLockArgsList, toBtcAddress, xudtTypeArgs, transfe }); // Save ckbVirtualTxResult - saveCkbVirtualTxResult(ckbVirtualTxResult, '2-btc-transfer'); + saveCkbVirtualTxResult(ckbVirtualTxResult, '2-btc-transfer-local'); const { commitment, ckbRawTx } = ckbVirtualTxResult; diff --git a/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts b/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts index 45ba39d0..d42615a8 100644 --- a/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts +++ b/examples/rgbpp/xudt/local/3-btc-leap-ckb.ts @@ -35,7 +35,7 @@ const leapFromBtcToCkb = async ({ rgbppLockArgsList, toCkbAddress, xudtTypeArgs, }); // Save ckbVirtualTxResult - saveCkbVirtualTxResult(ckbVirtualTxResult, '3-btc-leap-ckb'); + saveCkbVirtualTxResult(ckbVirtualTxResult, '3-btc-leap-ckb-local'); const { commitment, ckbRawTx } = ckbVirtualTxResult; From ef597c1aa3135dc094541e7353304863d389cbfd Mon Sep 17 00:00:00 2001 From: Shook <44739165+ShookLyngs@users.noreply.github.com> Date: Tue, 28 May 2024 09:24:12 +0800 Subject: [PATCH 78/78] Bump RGB++ SDK to v0.2.0 (#194) --- .changeset/afraid-pianos-do.md | 5 ----- .changeset/clean-chairs-nail.md | 5 ----- .changeset/fast-mice-smash.md | 5 ----- .changeset/flat-starfishes-confess.md | 5 ----- .changeset/large-nails-greet.md | 5 ----- .changeset/rude-feet-love.md | 5 ----- .changeset/selfish-lions-trade.md | 5 ----- .changeset/silly-emus-raise.md | 6 ------ .changeset/slimy-eggs-mix.md | 5 ----- .changeset/slimy-rockets-watch.md | 5 ----- .changeset/stupid-donuts-grin.md | 5 ----- .changeset/sweet-jeans-check.md | 5 ----- .changeset/young-students-own.md | 5 ----- packages/btc/CHANGELOG.md | 16 ++++++++++++++++ packages/btc/package.json | 2 +- packages/ckb/CHANGELOG.md | 23 +++++++++++++++++++++++ packages/ckb/package.json | 2 +- packages/rgbpp/CHANGELOG.md | 16 ++++++++++++++++ packages/rgbpp/package.json | 2 +- packages/service/CHANGELOG.md | 10 ++++++++++ packages/service/package.json | 2 +- 21 files changed, 69 insertions(+), 70 deletions(-) delete mode 100644 .changeset/afraid-pianos-do.md delete mode 100644 .changeset/clean-chairs-nail.md delete mode 100644 .changeset/fast-mice-smash.md delete mode 100644 .changeset/flat-starfishes-confess.md delete mode 100644 .changeset/large-nails-greet.md delete mode 100644 .changeset/rude-feet-love.md delete mode 100644 .changeset/selfish-lions-trade.md delete mode 100644 .changeset/silly-emus-raise.md delete mode 100644 .changeset/slimy-eggs-mix.md delete mode 100644 .changeset/slimy-rockets-watch.md delete mode 100644 .changeset/stupid-donuts-grin.md delete mode 100644 .changeset/sweet-jeans-check.md delete mode 100644 .changeset/young-students-own.md create mode 100644 packages/rgbpp/CHANGELOG.md diff --git a/.changeset/afraid-pianos-do.md b/.changeset/afraid-pianos-do.md deleted file mode 100644 index dfac1ff1..00000000 --- a/.changeset/afraid-pianos-do.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rgbpp-sdk/btc": minor ---- - -Support query data caching internally in TxBuilder/DataSource, preventing query from the BtcAssetsApi too often when paying fee diff --git a/.changeset/clean-chairs-nail.md b/.changeset/clean-chairs-nail.md deleted file mode 100644 index 540a9ebd..00000000 --- a/.changeset/clean-chairs-nail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"rgbpp": patch ---- - -Fix the export of NetworkType/AddressType in the rgbpp lib diff --git a/.changeset/fast-mice-smash.md b/.changeset/fast-mice-smash.md deleted file mode 100644 index c84cc96f..00000000 --- a/.changeset/fast-mice-smash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rgbpp-sdk/ckb": minor ---- - -feat: Increase the max length of RGB++ inputs to 40 diff --git a/.changeset/flat-starfishes-confess.md b/.changeset/flat-starfishes-confess.md deleted file mode 100644 index 6040e217..00000000 --- a/.changeset/flat-starfishes-confess.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"rgbpp": major ---- - -feat: Add rgbpp sub package diff --git a/.changeset/large-nails-greet.md b/.changeset/large-nails-greet.md deleted file mode 100644 index 05b46c33..00000000 --- a/.changeset/large-nails-greet.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rgbpp-sdk/ckb": minor ---- - -refactor: Collect all RGB++ inputs without isMax parameter diff --git a/.changeset/rude-feet-love.md b/.changeset/rude-feet-love.md deleted file mode 100644 index f741593d..00000000 --- a/.changeset/rude-feet-love.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rgbpp-sdk/service': patch ---- - -add no_cache params to btc/rgbpp service api diff --git a/.changeset/selfish-lions-trade.md b/.changeset/selfish-lions-trade.md deleted file mode 100644 index 700344eb..00000000 --- a/.changeset/selfish-lions-trade.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rgbpp-sdk/ckb": minor ---- - -refactor: Filter xudt cell whose amount is valid for collector diff --git a/.changeset/silly-emus-raise.md b/.changeset/silly-emus-raise.md deleted file mode 100644 index 4f113c3b..00000000 --- a/.changeset/silly-emus-raise.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@rgbpp-sdk/service": minor -"@rgbpp-sdk/btc": minor ---- - -Replace all "void 0" to "undefined" in the btc/service lib diff --git a/.changeset/slimy-eggs-mix.md b/.changeset/slimy-eggs-mix.md deleted file mode 100644 index 16d9858d..00000000 --- a/.changeset/slimy-eggs-mix.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rgbpp-sdk/ckb": minor ---- - -refactor: Check spore type script for spore transfer and leap diff --git a/.changeset/slimy-rockets-watch.md b/.changeset/slimy-rockets-watch.md deleted file mode 100644 index 10201d25..00000000 --- a/.changeset/slimy-rockets-watch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rgbpp-sdk/btc": patch ---- - -Fix the message of INSUFFICIENT_UTXO error when collection failed diff --git a/.changeset/stupid-donuts-grin.md b/.changeset/stupid-donuts-grin.md deleted file mode 100644 index f5a3352b..00000000 --- a/.changeset/stupid-donuts-grin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rgbpp-sdk/ckb": minor ---- - -feat: Build ckb raw tx to be signed for spores creation diff --git a/.changeset/sweet-jeans-check.md b/.changeset/sweet-jeans-check.md deleted file mode 100644 index 7ecd851d..00000000 --- a/.changeset/sweet-jeans-check.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rgbpp-sdk/ckb": minor ---- - -refactor: Update ckb cell fields size to make the code more readable diff --git a/.changeset/young-students-own.md b/.changeset/young-students-own.md deleted file mode 100644 index 576432b3..00000000 --- a/.changeset/young-students-own.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rgbpp-sdk/ckb": minor ---- - -fix: Update RRB++ witnesses for BTC batch transfer TX diff --git a/packages/btc/CHANGELOG.md b/packages/btc/CHANGELOG.md index 1aa30071..aff4d077 100644 --- a/packages/btc/CHANGELOG.md +++ b/packages/btc/CHANGELOG.md @@ -1,5 +1,21 @@ # @rgbpp-sdk/btc +## v0.2.0 + +### Minor Changes + +- [#184](https://github.com/ckb-cell/rgbpp-sdk/pull/184): Support query data caching internally in TxBuilder/DataSource, preventing query from the BtcAssetsApi too often when paying fee ([@ShookLyngs](https://github.com/ShookLyngs)) + +- [#165](https://github.com/ckb-cell/rgbpp-sdk/pull/165): Replace all "void 0" to "undefined" in the btc/service lib ([@ShookLyngs](https://github.com/ShookLyngs)) + +### Patch Changes + +- [#166](https://github.com/ckb-cell/rgbpp-sdk/pull/166): Fix the message of INSUFFICIENT_UTXO error when collection failed ([@ShookLyngs](https://github.com/ShookLyngs)) + +- Updated dependencies [[`5e0e817`](https://github.com/ckb-cell/rgbpp-sdk/commit/5e0e8175a4c195e6491a37abedc755728c91cbed), [`a9b9796`](https://github.com/ckb-cell/rgbpp-sdk/commit/a9b9796f5ef8d27a9ad94d09a832bb9a7fe56c8e), [`9f9daa9`](https://github.com/ckb-cell/rgbpp-sdk/commit/9f9daa91486ca0cc1015713bd2648aa606da8717), [`299b404`](https://github.com/ckb-cell/rgbpp-sdk/commit/299b404217036feab409956d8888bfdc8fa820f4), [`e59322e`](https://github.com/ckb-cell/rgbpp-sdk/commit/e59322e7c6b9aff682bc1c8517337e3611dc122d), [`64c4312`](https://github.com/ckb-cell/rgbpp-sdk/commit/64c4312768885cb965285d41de99d023a4517ed3), [`1d58dd5`](https://github.com/ckb-cell/rgbpp-sdk/commit/1d58dd531947f4078667bb7294d2b3bb9351ead9), [`8cfc06e`](https://github.com/ckb-cell/rgbpp-sdk/commit/8cfc06e449c213868f103d9757f79f24521da280), [`4fcf4fa`](https://github.com/ckb-cell/rgbpp-sdk/commit/4fcf4fa6c0b20cf2fa957664a320f66601991817)]: + - @rgbpp-sdk/ckb@0.2.0 + - @rgbpp-sdk/service@0.2.0 + ## v0.1.0 - Release @rgbpp-sdk/btc for RGBPP BTC-side transaction construction, providing APIs to send BTC or send RGBPP UTXO. Read the docs for more information: https://github.com/ckb-cell/rgbpp-sdk/tree/develop/packages/btc diff --git a/packages/btc/package.json b/packages/btc/package.json index 70efc86d..5140f506 100644 --- a/packages/btc/package.json +++ b/packages/btc/package.json @@ -1,6 +1,6 @@ { "name": "@rgbpp-sdk/btc", - "version": "0.1.0", + "version": "0.2.0", "scripts": { "test": "vitest", "build": "tsc -p tsconfig.build.json", diff --git a/packages/ckb/CHANGELOG.md b/packages/ckb/CHANGELOG.md index 9636deec..93b550d7 100644 --- a/packages/ckb/CHANGELOG.md +++ b/packages/ckb/CHANGELOG.md @@ -1,5 +1,28 @@ # @rgbpp-sdk/ckb +## v0.2.0 + +### Minor Changes + +- [#179](https://github.com/ckb-cell/rgbpp-sdk/pull/179): Increase the max length of RGB++ inputs to 40 ([@duanyytop](https://github.com/duanyytop)) + +- [#160](https://github.com/ckb-cell/rgbpp-sdk/pull/160): Collect all RGB++ inputs without isMax parameter ([@duanyytop](https://github.com/duanyytop)) + +- [#190](https://github.com/ckb-cell/rgbpp-sdk/pull/190): Filter xudt cell whose amount is valid for collector ([@duanyytop](https://github.com/duanyytop)) + +- [#172](https://github.com/ckb-cell/rgbpp-sdk/pull/172): Check spore type script for spore transfer and leap ([@duanyytop](https://github.com/duanyytop)) + +- [#171](https://github.com/ckb-cell/rgbpp-sdk/pull/171): Build ckb raw tx to be signed for spores creation ([@duanyytop](https://github.com/duanyytop)) + +- [#174](https://github.com/ckb-cell/rgbpp-sdk/pull/174): Update ckb cell fields size to make the code more readable ([@duanyytop](https://github.com/duanyytop)) + +- [#187](https://github.com/ckb-cell/rgbpp-sdk/pull/187): Update RRB++ witnesses for BTC batch transfer TX ([@duanyytop](https://github.com/duanyytop)) + +### Patch Changes + +- Updated dependencies [[`9f9daa9`](https://github.com/ckb-cell/rgbpp-sdk/commit/9f9daa91486ca0cc1015713bd2648aa606da8717), [`e59322e`](https://github.com/ckb-cell/rgbpp-sdk/commit/e59322e7c6b9aff682bc1c8517337e3611dc122d)]: + - @rgbpp-sdk/service@0.2.0 + ## v0.1.0 - Release @rgbpp-sdk/ckb for RGBPP CKB-side transaction construction, providing APIs to bind/transfer/leap assets on CKB/BTC. Read the docs for more information: https://github.com/ckb-cell/rgbpp-sdk/tree/develop/packages/ckb diff --git a/packages/ckb/package.json b/packages/ckb/package.json index ade8494d..0971879f 100644 --- a/packages/ckb/package.json +++ b/packages/ckb/package.json @@ -1,6 +1,6 @@ { "name": "@rgbpp-sdk/ckb", - "version": "0.1.0", + "version": "0.2.0", "scripts": { "test": "vitest", "build": "tsc -p tsconfig.build.json", diff --git a/packages/rgbpp/CHANGELOG.md b/packages/rgbpp/CHANGELOG.md new file mode 100644 index 00000000..a8a4cc28 --- /dev/null +++ b/packages/rgbpp/CHANGELOG.md @@ -0,0 +1,16 @@ +# rgbpp + +## v0.2.0 + +### Minor Changes + +- [#157](https://github.com/ckb-cell/rgbpp-sdk/pull/157): Add rgbpp sub package ([@duanyytop](https://github.com/duanyytop)) + +### Patch Changes + +- [#177](https://github.com/ckb-cell/rgbpp-sdk/pull/177): Fix the export of NetworkType/AddressType in the rgbpp lib ([@ShookLyngs](https://github.com/ShookLyngs)) + +- Updated dependencies [[`8a8e11b`](https://github.com/ckb-cell/rgbpp-sdk/commit/8a8e11bdca4d3fb8b8d20c771e116bb1684bb1c6), [`5e0e817`](https://github.com/ckb-cell/rgbpp-sdk/commit/5e0e8175a4c195e6491a37abedc755728c91cbed), [`a9b9796`](https://github.com/ckb-cell/rgbpp-sdk/commit/a9b9796f5ef8d27a9ad94d09a832bb9a7fe56c8e), [`9f9daa9`](https://github.com/ckb-cell/rgbpp-sdk/commit/9f9daa91486ca0cc1015713bd2648aa606da8717), [`299b404`](https://github.com/ckb-cell/rgbpp-sdk/commit/299b404217036feab409956d8888bfdc8fa820f4), [`e59322e`](https://github.com/ckb-cell/rgbpp-sdk/commit/e59322e7c6b9aff682bc1c8517337e3611dc122d), [`64c4312`](https://github.com/ckb-cell/rgbpp-sdk/commit/64c4312768885cb965285d41de99d023a4517ed3), [`d37cf5b`](https://github.com/ckb-cell/rgbpp-sdk/commit/d37cf5b1aaf50f42a2f900f9b6aa073a916840b2), [`1d58dd5`](https://github.com/ckb-cell/rgbpp-sdk/commit/1d58dd531947f4078667bb7294d2b3bb9351ead9), [`8cfc06e`](https://github.com/ckb-cell/rgbpp-sdk/commit/8cfc06e449c213868f103d9757f79f24521da280), [`4fcf4fa`](https://github.com/ckb-cell/rgbpp-sdk/commit/4fcf4fa6c0b20cf2fa957664a320f66601991817)]: + - @rgbpp-sdk/btc@0.2.0 + - @rgbpp-sdk/ckb@0.2.0 + - @rgbpp-sdk/service@0.2.0 diff --git a/packages/rgbpp/package.json b/packages/rgbpp/package.json index 517e6649..42a4a3dd 100644 --- a/packages/rgbpp/package.json +++ b/packages/rgbpp/package.json @@ -1,6 +1,6 @@ { "name": "rgbpp", - "version": "0.1.0", + "version": "0.2.0", "scripts": { "build": "tsc -p tsconfig.build.json", "lint": "tsc && eslint --ext .ts src/* && prettier --check 'src/*.ts'", diff --git a/packages/service/CHANGELOG.md b/packages/service/CHANGELOG.md index 6d3d62d3..c8f94e79 100644 --- a/packages/service/CHANGELOG.md +++ b/packages/service/CHANGELOG.md @@ -1,5 +1,15 @@ # @rgbpp-sdk/service +## v0.2.0 + +### Minor Changes + +- [#165](https://github.com/ckb-cell/rgbpp-sdk/pull/165): Replace all "void 0" to "undefined" in the btc/service lib ([@ShookLyngs](https://github.com/ShookLyngs)) + +### Patch Changes + +- [#181](https://github.com/ckb-cell/rgbpp-sdk/pull/181): add no_cache params to btc/rgbpp service api ([@ahonn](https://github.com/ahonn)) + ## v0.1.0 - Release @rgbpp-sdk/service for communicating with the [btc-assets-api](https://github.com/ckb-cell/btc-assets-api), providing APIs to query data from or post transactions to the service. Read the docs for more information: https://github.com/ckb-cell/rgbpp-sdk/tree/develop/packages/service diff --git a/packages/service/package.json b/packages/service/package.json index d2253082..f55ae9da 100644 --- a/packages/service/package.json +++ b/packages/service/package.json @@ -1,6 +1,6 @@ { "name": "@rgbpp-sdk/service", - "version": "0.1.0", + "version": "0.2.0", "scripts": { "test": "vitest", "build": "tsc -p tsconfig.build.json",