Skip to content

Commit

Permalink
Merge pull request #226 from ckb-cell/test/transfer-xudt-integration
Browse files Browse the repository at this point in the history
test: Add transfer-xudt integration tests
  • Loading branch information
Flouse authored Jun 12, 2024
2 parents 2d634ab + c3a2fa9 commit 20441ec
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 1 deletion.
2 changes: 1 addition & 1 deletion tests/rgbpp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"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",
"integration:xudt": "npx ts-node shared/prepare-utxo.ts && npx ts-node xudt/xudt-on-ckb/1-issue-xudt.ts && npx ts-node xudt/xudt-on-ckb/2-transfer-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",
"integration:spore": "npx ts-node shared/prepare-utxo.ts && npx ts-node spore/launch/1-prepare-cluster.ts && npx ts-node spore/launch/2-create-cluster.ts && npx ts-node spore/launch/3-create-spores.ts && npx ts-node spore/4-transfer-spore.ts && npx ts-node spore/5-leap-spore-to-ckb.ts"
},
"dependencies": {
Expand Down
165 changes: 165 additions & 0 deletions tests/rgbpp/xudt/xudt-on-ckb/2-transfer-xudt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import { addressToScript, getTransactionSize } from '@nervosnetwork/ckb-sdk-utils';
import {
getSecp256k1CellDep,
RgbppTokenInfo,
NoLiveCellError,
calculateUdtCellCapacity,
MAX_FEE,
MIN_CAPACITY,
append0x,
u128ToLe,
SECP256K1_WITNESS_LOCK_SIZE,
calculateTransactionFee,
NoXudtLiveCellError,
fetchTypeIdCellDeps,
} from 'rgbpp/ckb';
import { CKB_PRIVATE_KEY, ckbAddress, collector, isMainnet } from '../../env';
import { readStepLog } from '../../shared/utils';

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 { retry } = await import('zx');
await retry(12, '10s', async () => {
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));

let sumXudtOutputCapacity = receivers
.map(({ toAddress }) => calculateUdtCellCapacity(addressToScript(toAddress)))
.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 outputs: CKBComponents.CellOutput[] = receivers.map(({ toAddress }) => ({
lock: addressToScript(toAddress),
type: xudtType,
capacity: append0x(calculateUdtCellCapacity(addressToScript(toAddress)).toString(16)),
}));
const outputsData = receivers.map(({ transferAmount }) => append0x(u128ToLe(transferAmount)));

if (sumAmount > sumTransferAmount) {
const xudtChangeCapacity = calculateUdtCellCapacity(fromLock);
outputs.push({
lock: fromLock,
type: xudtType,
capacity: append0x(xudtChangeCapacity.toString(16)),
});
outputsData.push(append0x(u128ToLe(sumAmount - sumTransferAmount)));
sumXudtOutputCapacity += xudtChangeCapacity;
}

const txFee = MAX_FEE;
if (sumXudtInputsCapacity <= sumXudtOutputCapacity) {
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 = sumXudtOutputCapacity - sumXudtInputsCapacity;
const { inputs: emptyInputs, sumInputsCapacity: sumEmptyCapacity } = collector.collectInputs(
emptyCells,
needCapacity,
txFee,
{ minCapacity: MIN_CAPACITY },
);
inputs = [...inputs, ...emptyInputs];
actualInputsCapacity += sumEmptyCapacity;
}

let changeCapacity = actualInputsCapacity - sumXudtOutputCapacity;
outputs.push({
lock: fromLock,
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), ...(await fetchTypeIdCellDeps(isMainnet, { xudt: true }))];

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}`);
console.info(`explorer: https://pudge.explorer.nervos.org/transaction/${txHash}`);
});
};

const XUDT_TOKEN_INFO: RgbppTokenInfo = {
decimal: 8,
name: 'XUDT Test Token',
symbol: 'PDD',
};

transferXudt({
// The xudtType comes from 1-issue-xudt
xudtType: {
codeHash: readStepLog('xUDT-type-script').codeHash,
hashType: readStepLog('xUDT-type-script').hashType,
args: readStepLog('xUDT-type-script').args,
},
receivers: [
{
toAddress: 'ckt1qrfrwcdnvssswdwpn3s9v8fp87emat306ctjwsm3nmlkjg8qyza2cqgqqxtfdmw2e5kzfcz536qrnf6w36kyhpzweupegx46',
transferAmount: BigInt(1) * BigInt(10 ** XUDT_TOKEN_INFO.decimal),
},
{
toAddress: 'ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqgj8re09l7gk267ank62hadpp3t2kp20kqnud0jc',
transferAmount: BigInt(1000) * BigInt(10 ** XUDT_TOKEN_INFO.decimal),
},
{
toAddress: 'ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqgj8re09l7gk267ank62hadpp3t2kp20kqnud0jc',
transferAmount: BigInt(2000) * BigInt(10 ** XUDT_TOKEN_INFO.decimal),
},
],
});

1 comment on commit 20441ec

@github-actions
Copy link

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:

Name Version
@rgbpp-sdk/btc 0.0.0-snap-20240612103219

Please sign in to comment.