Skip to content
This repository was archived by the owner on May 27, 2025. It is now read-only.

Commit f816626

Browse files
authored
feat: Add generating btc time cell example (#259)
1 parent 85a22ec commit f816626

File tree

3 files changed

+154
-3
lines changed

3 files changed

+154
-3
lines changed

examples/rgbpp/xudt/4-unlock-btc-time-cell.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,5 @@ const unlockBtcTimeCell = async ({ btcTimeCellArgs }: { btcTimeCellArgs: string
3838
// The btcTimeCellArgs is from the outputs[0].lock.args(BTC Time lock args) of the 3-btc-leap-ckb.ts CKB transaction
3939
unlockBtcTimeCell({
4040
btcTimeCellArgs:
41-
'0x7d00000010000000590000005d000000490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000f9a9ad51ed14936d33f7bb854aaefa5f47a3ccbd14000000b83a6014c458544360730d97e0ae5f36ecf6335f73afadf8eb10f84487392a27',
41+
'0x7d00000010000000590000005d000000490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000f9a9ad51ed14936d33f7bb854aaefa5f47a3ccbd880d0100ffc34d3d23f86df84a23a3b2cf72b45c8a309fec417ab196bee8e7a74483e05f',
4242
});

examples/xudt-on-ckb/2-transfer-xudt.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
calculateTransactionFee,
1313
NoXudtLiveCellError,
1414
fetchTypeIdCellDeps,
15+
getXudtTypeScript,
1516
} from 'rgbpp/ckb';
1617
import { CKB_PRIVATE_KEY, ckbAddress, collector, isMainnet } from './env';
1718

@@ -139,8 +140,7 @@ const XUDT_TOKEN_INFO: RgbppTokenInfo = {
139140
transferXudt({
140141
// The xudtType comes from 1-issue-xudt
141142
xudtType: {
142-
codeHash: '0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb',
143-
hashType: 'type',
143+
...getXudtTypeScript(isMainnet),
144144
args: '0x562e4e8a2f64a3e9c24beb4b7dd002d0ad3b842d0cc77924328e36ad114e3ebe',
145145
},
146146
receivers: [
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
import { addressToScript, getTransactionSize } from '@nervosnetwork/ckb-sdk-utils';
2+
import {
3+
getSecp256k1CellDep,
4+
NoLiveCellError,
5+
calculateUdtCellCapacity,
6+
MAX_FEE,
7+
MIN_CAPACITY,
8+
append0x,
9+
u128ToLe,
10+
SECP256K1_WITNESS_LOCK_SIZE,
11+
calculateTransactionFee,
12+
NoXudtLiveCellError,
13+
fetchTypeIdCellDeps,
14+
calculateRgbppCellCapacity,
15+
getBtcTimeLockScript,
16+
genBtcTimeLockArgs,
17+
getXudtTypeScript,
18+
} from 'rgbpp/ckb';
19+
import { CKB_PRIVATE_KEY, ckbAddress, collector, isMainnet } from './env';
20+
21+
interface BtcTimeCellParams {
22+
xudtType: CKBComponents.Script;
23+
toCkbAddress: string;
24+
xudtAmount: bigint;
25+
btcTxId: string;
26+
after: number;
27+
}
28+
29+
/**
30+
* Generate btc time cell with custom btc txid, after and target lock script
31+
* @param xudtType The xUDT type script that comes from 1-issue-xudt or 2-transfer-xudt
32+
* BTC time lock args:
33+
* table BTCTimeLock {
34+
to_lock_script: Script,
35+
after: Uint32,
36+
btc_txid: Byte32,
37+
}
38+
*/
39+
const generateBtcTimeCell = async ({ xudtType, toCkbAddress, xudtAmount, btcTxId, after }: BtcTimeCellParams) => {
40+
const fromLock = addressToScript(ckbAddress);
41+
42+
const xudtCells = await collector.getCells({
43+
lock: fromLock,
44+
type: xudtType,
45+
});
46+
if (!xudtCells || xudtCells.length === 0) {
47+
throw new NoXudtLiveCellError('The address has no xudt cells');
48+
}
49+
50+
const btcTimeOutputCapacity = calculateRgbppCellCapacity(xudtType);
51+
let sumXudtOutputCapacity = btcTimeOutputCapacity;
52+
53+
const {
54+
inputs: udtInputs,
55+
sumInputsCapacity: sumXudtInputsCapacity,
56+
sumAmount,
57+
} = collector.collectUdtInputs({
58+
liveCells: xudtCells,
59+
needAmount: xudtAmount,
60+
});
61+
let actualInputsCapacity = sumXudtInputsCapacity;
62+
let inputs = udtInputs;
63+
64+
const outputs: CKBComponents.CellOutput[] = [
65+
{
66+
lock: {
67+
...getBtcTimeLockScript(isMainnet),
68+
args: genBtcTimeLockArgs(addressToScript(toCkbAddress), btcTxId, after),
69+
},
70+
type: xudtType,
71+
capacity: append0x(btcTimeOutputCapacity.toString(16)),
72+
},
73+
];
74+
const outputsData = [append0x(u128ToLe(xudtAmount))];
75+
76+
if (sumAmount > xudtAmount) {
77+
const xudtChangeCapacity = calculateUdtCellCapacity(fromLock);
78+
outputs.push({
79+
lock: fromLock,
80+
type: xudtType,
81+
capacity: append0x(xudtChangeCapacity.toString(16)),
82+
});
83+
outputsData.push(append0x(u128ToLe(sumAmount - xudtAmount)));
84+
sumXudtOutputCapacity += xudtChangeCapacity;
85+
}
86+
87+
const txFee = MAX_FEE;
88+
if (sumXudtInputsCapacity <= sumXudtOutputCapacity) {
89+
let emptyCells = await collector.getCells({
90+
lock: fromLock,
91+
});
92+
if (!emptyCells || emptyCells.length === 0) {
93+
throw new NoLiveCellError('The address has no empty cells');
94+
}
95+
emptyCells = emptyCells.filter((cell) => !cell.output.type);
96+
const needCapacity = sumXudtOutputCapacity - sumXudtInputsCapacity;
97+
const { inputs: emptyInputs, sumInputsCapacity: sumEmptyCapacity } = collector.collectInputs(
98+
emptyCells,
99+
needCapacity,
100+
txFee,
101+
{ minCapacity: MIN_CAPACITY },
102+
);
103+
inputs = [...inputs, ...emptyInputs];
104+
actualInputsCapacity += sumEmptyCapacity;
105+
}
106+
107+
let changeCapacity = actualInputsCapacity - sumXudtOutputCapacity;
108+
outputs.push({
109+
lock: fromLock,
110+
capacity: append0x(changeCapacity.toString(16)),
111+
});
112+
outputsData.push('0x');
113+
114+
const emptyWitness = { lock: '', inputType: '', outputType: '' };
115+
const witnesses = inputs.map((_, index) => (index === 0 ? emptyWitness : '0x'));
116+
117+
const cellDeps = [getSecp256k1CellDep(isMainnet), ...(await fetchTypeIdCellDeps(isMainnet, { xudt: true }))];
118+
119+
const unsignedTx = {
120+
version: '0x0',
121+
cellDeps,
122+
headerDeps: [],
123+
inputs,
124+
outputs,
125+
outputsData,
126+
witnesses,
127+
};
128+
129+
if (txFee === MAX_FEE) {
130+
const txSize = getTransactionSize(unsignedTx) + SECP256K1_WITNESS_LOCK_SIZE;
131+
const estimatedTxFee = calculateTransactionFee(txSize);
132+
changeCapacity -= estimatedTxFee;
133+
unsignedTx.outputs[unsignedTx.outputs.length - 1].capacity = append0x(changeCapacity.toString(16));
134+
}
135+
136+
const signedTx = collector.getCkb().signTransaction(CKB_PRIVATE_KEY)(unsignedTx);
137+
const txHash = await collector.getCkb().rpc.sendTransaction(signedTx, 'passthrough');
138+
139+
console.info(`xUDT asset has been transferred to BTC time lock and CKB tx hash is ${txHash}`);
140+
};
141+
142+
generateBtcTimeCell({
143+
xudtType: {
144+
...getXudtTypeScript(isMainnet),
145+
args: '0x562e4e8a2f64a3e9c24beb4b7dd002d0ad3b842d0cc77924328e36ad114e3ebe',
146+
},
147+
toCkbAddress: 'ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq0e4xk4rmg5jdkn8aams492a7jlg73ue0gc0ddfj',
148+
xudtAmount: BigInt(1000) * BigInt(10 ** 8),
149+
btcTxId: '5fe08344a7e7e8be96b17a41ec9f308a5cb472cfb2a3234af86df8233d4dc3ff',
150+
after: 69000,
151+
});

0 commit comments

Comments
 (0)