-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #291 from utxostack/xudt-compatible
Support RGB++ compatible xUDT assets
- Loading branch information
Showing
40 changed files
with
820 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
--- | ||
'@rgbpp-sdk/service': minor | ||
'rgbpp': minor | ||
'@rgbpp-sdk/ckb': minor | ||
--- | ||
|
||
Support compatible xUDT RGB++ assets | ||
|
||
- Fetch compatible xUDT `cellDeps` to build CKB transactions from the `typeid-contract-cell-deps` GitHub repository | ||
- Update the `ckb` package to support RGB++ compatible xUDT assets leaping and transferring | ||
- Add optional parameter `compatibleXudtTypeScript` to the functions of the `rgbpp` package to transfer RGB++ compatible xUDT assets | ||
- Add RGB++ compatible xUDT assets leaping and transferring examples | ||
- Add RGB++ compatible xUDT assets integration tests | ||
- Add `assets/type` API to the service package |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; | ||
import { genCkbJumpBtcVirtualTx } from 'rgbpp'; | ||
import { getSecp256k1CellDep, buildRgbppLockArgs } from 'rgbpp/ckb'; | ||
import { CKB_PRIVATE_KEY, isMainnet, collector, ckbAddress, BTC_TESTNET_TYPE } from '../../env'; | ||
|
||
interface LeapToBtcParams { | ||
outIndex: number; | ||
btcTxId: string; | ||
transferAmount: bigint; | ||
compatibleXudtTypeScript: CKBComponents.Script; | ||
} | ||
|
||
const leapRusdFromCkbToBtc = async ({ | ||
outIndex, | ||
btcTxId, | ||
transferAmount, | ||
compatibleXudtTypeScript, | ||
}: LeapToBtcParams) => { | ||
const toRgbppLockArgs = buildRgbppLockArgs(outIndex, btcTxId); | ||
|
||
const ckbRawTx = await genCkbJumpBtcVirtualTx({ | ||
collector, | ||
fromCkbAddress: ckbAddress, | ||
toRgbppLockArgs, | ||
xudtTypeBytes: serializeScript(compatibleXudtTypeScript), | ||
transferAmount, | ||
btcTestnetType: BTC_TESTNET_TYPE, | ||
}); | ||
|
||
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_PRIVATE_KEY)(unsignedTx); | ||
|
||
const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough'); | ||
console.info(`Rgbpp compatible xUDT asset has been leaped from CKB to BTC and CKB tx hash is ${txHash}`); | ||
}; | ||
|
||
// Please use your real BTC UTXO information on the BTC Testnet | ||
// BTC Testnet3: https://mempool.space/testnet | ||
// BTC Signet: https://mempool.space/signet | ||
leapRusdFromCkbToBtc({ | ||
outIndex: 4, | ||
btcTxId: '44de1b4e3ddaa95cc85cc8b1c60f3e439d343002f0c60980fb4c70841ee0c75e', | ||
// Please use your own RGB++ compatible xUDT asset's type script | ||
compatibleXudtTypeScript: { | ||
codeHash: '0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a', | ||
hashType: 'type', | ||
args: '0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b', | ||
}, | ||
transferAmount: BigInt(1000_0000), | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import { buildRgbppLockArgs } from 'rgbpp/ckb'; | ||
import { buildRgbppTransferTx } from 'rgbpp'; | ||
import { isMainnet, collector, btcService, btcAccount, btcDataSource, BTC_TESTNET_TYPE } from '../../env'; | ||
import { saveCkbVirtualTxResult } from '../../shared/utils'; | ||
import { signAndSendPsbt } from '../../shared/btc-account'; | ||
import { bitcoin } from 'rgbpp/btc'; | ||
|
||
interface RgbppTransferParams { | ||
rgbppLockArgsList: string[]; | ||
toBtcAddress: string; | ||
transferAmount: bigint; | ||
compatibleXudtTypeScript: CKBComponents.Script; | ||
} | ||
|
||
const transferRusdOnBtc = async ({ | ||
rgbppLockArgsList, | ||
toBtcAddress, | ||
compatibleXudtTypeScript, | ||
transferAmount, | ||
}: RgbppTransferParams) => { | ||
const { ckbVirtualTxResult, btcPsbtHex } = await buildRgbppTransferTx({ | ||
ckb: { | ||
collector, | ||
xudtTypeArgs: compatibleXudtTypeScript.args, | ||
rgbppLockArgsList, | ||
transferAmount, | ||
compatibleXudtTypeScript, | ||
}, | ||
btc: { | ||
fromAddress: btcAccount.from, | ||
toAddress: toBtcAddress, | ||
fromPubkey: btcAccount.fromPubkey, | ||
dataSource: btcDataSource, | ||
testnetType: BTC_TESTNET_TYPE, | ||
}, | ||
isMainnet, | ||
}); | ||
|
||
// Save ckbVirtualTxResult | ||
saveCkbVirtualTxResult(ckbVirtualTxResult, '2-btc-transfer'); | ||
|
||
// Send BTC tx | ||
const psbt = bitcoin.Psbt.fromHex(btcPsbtHex); | ||
const { txId: btcTxId } = await signAndSendPsbt(psbt, btcAccount, btcService); | ||
console.log(`BTC ${BTC_TESTNET_TYPE} TxId: ${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 compatible xUDT 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); | ||
} | ||
}; | ||
|
||
// Please use your real BTC UTXO information on the BTC Testnet | ||
// BTC Testnet3: https://mempool.space/testnet | ||
// BTC Signet: https://mempool.space/signet | ||
|
||
// rgbppLockArgs: outIndexU32 + btcTxId | ||
transferRusdOnBtc({ | ||
rgbppLockArgsList: [buildRgbppLockArgs(4, '44de1b4e3ddaa95cc85cc8b1c60f3e439d343002f0c60980fb4c70841ee0c75e')], | ||
toBtcAddress: 'tb1qvt7p9g6mw70sealdewtfp0sekquxuru6j3gwmt', | ||
// Please use your own RGB++ compatible xudt asset's type script | ||
compatibleXudtTypeScript: { | ||
codeHash: '0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a', | ||
hashType: 'type', | ||
args: '0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b', | ||
}, | ||
transferAmount: BigInt(100_0000), | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { buildRgbppLockArgs } from 'rgbpp/ckb'; | ||
import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; | ||
import { genBtcJumpCkbVirtualTx, sendRgbppUtxos } from 'rgbpp'; | ||
import { isMainnet, collector, btcService, btcDataSource, btcAccount, BTC_TESTNET_TYPE } from '../../env'; | ||
import { saveCkbVirtualTxResult } from '../../shared/utils'; | ||
import { signAndSendPsbt } from '../../shared/btc-account'; | ||
|
||
interface LeapToCkbParams { | ||
rgbppLockArgsList: string[]; | ||
toCkbAddress: string; | ||
transferAmount: bigint; | ||
compatibleXudtTypeScript: CKBComponents.Script; | ||
} | ||
|
||
const leapRusdFromBtcToCKB = async ({ | ||
rgbppLockArgsList, | ||
toCkbAddress, | ||
compatibleXudtTypeScript, | ||
transferAmount, | ||
}: LeapToCkbParams) => { | ||
const ckbVirtualTxResult = await genBtcJumpCkbVirtualTx({ | ||
collector, | ||
rgbppLockArgsList, | ||
xudtTypeBytes: serializeScript(compatibleXudtTypeScript), | ||
transferAmount, | ||
toCkbAddress, | ||
isMainnet, | ||
btcTestnetType: BTC_TESTNET_TYPE, | ||
// btcConfirmationBlocks: 20, // default value is 6 | ||
}); | ||
|
||
// Save ckbVirtualTxResult | ||
saveCkbVirtualTxResult(ckbVirtualTxResult, '3-btc-leap-ckb'); | ||
|
||
const { commitment, ckbRawTx } = ckbVirtualTxResult; | ||
|
||
// Send BTC tx | ||
const psbt = await sendRgbppUtxos({ | ||
ckbVirtualTx: ckbRawTx, | ||
commitment, | ||
tos: [btcAccount.from], | ||
ckbCollector: collector, | ||
from: btcAccount.from, | ||
fromPubkey: btcAccount.fromPubkey, | ||
source: btcDataSource, | ||
}); | ||
|
||
const { txId: btcTxId } = await signAndSendPsbt(psbt, btcAccount, btcService); | ||
console.log(`BTC ${BTC_TESTNET_TYPE} TxId: ${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 compatible xUDT asset 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); | ||
} | ||
}; | ||
|
||
// Please use your real BTC UTXO information on the BTC Testnet | ||
// BTC Testnet3: https://mempool.space/testnet | ||
// BTC Signet: https://mempool.space/signet | ||
|
||
// rgbppLockArgs: outIndexU32 + btcTxId | ||
leapRusdFromBtcToCKB({ | ||
rgbppLockArgsList: [buildRgbppLockArgs(1, '58ebbdec0dfd464280658e36fadc11c41945de2c4b5b59463dad6e045a7e5faf')], | ||
toCkbAddress: 'ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq0e4xk4rmg5jdkn8aams492a7jlg73ue0gc0ddfj', | ||
// Please use your own RGB++ compatible xudt asset's type script | ||
compatibleXudtTypeScript: { | ||
codeHash: '0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a', | ||
hashType: 'type', | ||
args: '0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b', | ||
}, | ||
transferAmount: BigInt(100_0000), | ||
}); |
42 changes: 42 additions & 0 deletions
42
examples/rgbpp/xudt/compatible-xudt/4-unlock-btc-time-cell.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { buildBtcTimeCellsSpentTx, signBtcTimeCellSpentTx } from 'rgbpp'; | ||
import { sendCkbTx, getBtcTimeLockScript } from 'rgbpp/ckb'; | ||
import { BTC_TESTNET_TYPE, CKB_PRIVATE_KEY, btcService, ckbAddress, collector, isMainnet } from '../../env'; | ||
|
||
// Warning: Wait at least 6 BTC confirmation blocks to spend the BTC time cells after 3-btc-leap-ckb.ts | ||
const unlockRusdBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: string }) => { | ||
const btcTimeCells = await collector.getCells({ | ||
lock: { | ||
...getBtcTimeLockScript(isMainnet, BTC_TESTNET_TYPE), | ||
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, | ||
btcTestnetType: BTC_TESTNET_TYPE, | ||
}); | ||
|
||
const signedTx = await signBtcTimeCellSpentTx({ | ||
secp256k1PrivateKey: CKB_PRIVATE_KEY, | ||
collector, | ||
masterCkbAddress: ckbAddress, | ||
ckbRawTx, | ||
isMainnet, | ||
}); | ||
|
||
const txHash = await sendCkbTx({ collector, signedTx }); | ||
console.info(`BTC time cell has been spent and CKB tx hash is ${txHash}`); | ||
}; | ||
|
||
// The btcTimeCellArgs is from the outputs[0].lock.args(BTC Time lock args) of the 3-btc-leap-ckb.ts CKB transaction | ||
unlockRusdBtcTimeCell({ | ||
btcTimeCellArgs: | ||
'0x7d00000010000000590000005d000000490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000f9a9ad51ed14936d33f7bb854aaefa5f47a3ccbd0600000038036f35121682517b5f79732fc6a182e0050cfe1ad4cce0a1314c229a1ba364', | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { serializeScript } from '@nervosnetwork/ckb-sdk-utils'; | ||
import { btcService } from '../../env'; | ||
|
||
(async () => { | ||
const assets = await btcService.getRgbppAssetsByBtcAddress('tb1qvt7p9g6mw70sealdewtfp0sekquxuru6j3gwmt', { | ||
type_script: serializeScript({ | ||
codeHash: '0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a', | ||
hashType: 'type', | ||
args: '0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b', | ||
}), | ||
}); | ||
console.log('RUSD Assets: ', JSON.stringify(assets)); | ||
|
||
const activities = await btcService.getRgbppActivityByBtcAddress('tb1qvt7p9g6mw70sealdewtfp0sekquxuru6j3gwmt', { | ||
type_script: serializeScript({ | ||
codeHash: '0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a', | ||
hashType: 'type', | ||
args: '0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b', | ||
}), | ||
}); | ||
console.log('RUSD Activities: ', JSON.stringify(activities)); | ||
|
||
const info = await btcService.getRgbppAssetInfoByTypeScript( | ||
serializeScript({ | ||
codeHash: '0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb', | ||
hashType: 'type', | ||
args: '0x661cfbe2124b3e79e50e505c406be5b2dcf9da15d8654b749ec536fa4c2eaaae', | ||
}), | ||
); | ||
console.log('Standard xUDT info: ', JSON.stringify(info)); | ||
})(); |
Oops, something went wrong.
3240864
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New snapshot version of the rgbpp-sdk packages have been released:
0.0.0-snap-20250106033736
0.0.0-snap-20250106033736
0.0.0-snap-20250106033736
0.0.0-snap-20250106033736