Skip to content

Commit 8035b13

Browse files
committed
fix(sdk-coin-ada): unsigned sweep support for WRW with asset list
Ticket: CSHLD-134 Made-with: Cursor
1 parent d7d12b7 commit 8035b13

File tree

2 files changed

+92
-9
lines changed

2 files changed

+92
-9
lines changed

modules/sdk-coin-ada/src/ada.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -499,21 +499,25 @@ export class Ada extends BaseCoin {
499499
const transactionPrebuild = { txHex: serializedTx };
500500
const parsedTx = await this.parseTransaction({ txPrebuild: transactionPrebuild });
501501
const walletCoin = this.getChain();
502-
const output = (parsedTx.outputs as ITransactionRecipient)[0];
502+
const txOutputs = unsignedTransaction.toJson().outputs;
503+
const output = (parsedTx.outputs as ITransactionRecipient[])[0];
504+
// All tokens from the spent UTXOs — shown on the input so WRW can display what is being swept
505+
const assetList = Object.values(aggregatedAssetList);
503506
const inputs = [
504507
{
505508
address: senderAddr,
506509
valueString: output.amount,
507-
value: new BigNumber(output.amount).toNumber(),
508-
},
509-
];
510-
const outputs = [
511-
{
512-
address: output.address,
513-
valueString: output.amount,
514-
coinName: walletCoin,
510+
value: new BigNumber(output.amount as string).toNumber(),
511+
...(assetList.length > 0 && { assetList }),
515512
},
516513
];
514+
// Only attach assetList to outputs that actually carry tokens (have multiAssets)
515+
const outputs = (parsedTx.outputs as ITransactionRecipient[]).map((o, i) => ({
516+
address: o.address,
517+
valueString: o.amount,
518+
coinName: walletCoin,
519+
...(txOutputs[i]?.multiAssets && { assetList }),
520+
}));
517521
const spendAmount = output.amount;
518522
const completedParsedTx = { inputs: inputs, outputs: outputs, spendAmount: spendAmount, type: '' };
519523
const fee = new BigNumber((parsedTx.fee as { fee: string }).fee);

modules/sdk-coin-ada/test/unit/ada.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,85 @@ describe('ADA', function () {
674674
should.deepEqual(Number(txJson.outputs[0].amount) + fee, testnetUTXO.UTXO_1.value);
675675
});
676676

677+
it('should recover ADA plus token UTXOs - token and ADA both appear in outputs (unsigned sweep)', async function () {
678+
callBack
679+
.withArgs('address_info', { _addresses: [wrwUser.walletAddress0] })
680+
.resolves(endpointResponses.addressInfoResponse.ADAAndTokenUTXOs);
681+
682+
const res = await basecoin.recover({
683+
bitgoKey: wrwUser.bitgoKey,
684+
recoveryDestination: destAddr,
685+
});
686+
res.should.not.be.empty();
687+
const unsignedTx = res.txRequests[0].transactions[0].unsignedTx;
688+
unsignedTx.should.hasOwnProperty('serializedTx');
689+
690+
const tx = new Transaction(basecoin);
691+
tx.fromRawTransaction(unsignedTx.serializedTx);
692+
const txJson = tx.toJson();
693+
694+
txJson.inputs.length.should.equal(2);
695+
should.deepEqual(txJson.inputs[0].transaction_id, testnetUTXO.UTXO_1.tx_hash);
696+
should.deepEqual(txJson.inputs[1].transaction_id, testnetUTXO.UTXO_TOKEN.tx_hash);
697+
698+
txJson.outputs.length.should.equal(2);
699+
700+
const tokenPolicyId = '2533cca6eb42076e144e9f2772c390dece9fce173bc38c72294b3924';
701+
const tokenEncodedAssetName = '5741544552';
702+
const tokenQuantity = '111';
703+
const minADAForToken = 1500000;
704+
705+
const tokenOutput = txJson.outputs.find((o) => o.multiAssets !== undefined);
706+
should.exist(tokenOutput);
707+
should.deepEqual(tokenOutput!.address, destAddr);
708+
should.deepEqual(Number(tokenOutput!.amount), minADAForToken);
709+
const expectedPolicyId = CardanoWasm.ScriptHash.from_bytes(Buffer.from(tokenPolicyId, 'hex'));
710+
const expectedAssetName = CardanoWasm.AssetName.new(Buffer.from(tokenEncodedAssetName, 'hex'));
711+
(tokenOutput!.multiAssets as CardanoWasm.MultiAsset)
712+
.get_asset(expectedPolicyId, expectedAssetName)
713+
.to_str()
714+
.should.equal(tokenQuantity);
715+
716+
const adaOutput = txJson.outputs.find((o) => o.multiAssets === undefined);
717+
should.exist(adaOutput);
718+
should.deepEqual(adaOutput!.address, destAddr);
719+
const fee = Number(tx.explainTransaction().fee.fee);
720+
const totalBalance = testnetUTXO.UTXO_1.value + testnetUTXO.UTXO_TOKEN.value;
721+
should.deepEqual(Number(adaOutput!.amount), totalBalance - minADAForToken - fee);
722+
723+
const explained = tx.explainTransaction();
724+
const explainedTokenOutput = explained.outputs.find((o) => o.amount === minADAForToken.toString());
725+
should.exist(explainedTokenOutput);
726+
727+
// inputs and outputs in parsedTx should carry the assetList from the UTXO directly
728+
const parsedTxInputs = res.txRequests[0].transactions[0].unsignedTx.parsedTx.inputs as {
729+
address: string;
730+
valueString: string;
731+
assetList?: { policy_id: string; asset_name: string; quantity: string }[];
732+
}[];
733+
parsedTxInputs.length.should.equal(1);
734+
should.exist(parsedTxInputs[0].assetList);
735+
parsedTxInputs[0].assetList!.length.should.equal(1);
736+
should.deepEqual(parsedTxInputs[0].assetList![0].policy_id, tokenPolicyId);
737+
should.deepEqual(parsedTxInputs[0].assetList![0].asset_name, tokenEncodedAssetName);
738+
should.deepEqual(parsedTxInputs[0].assetList![0].quantity, tokenQuantity);
739+
740+
const parsedTxOutputs = res.txRequests[0].transactions[0].unsignedTx.parsedTx.outputs as {
741+
address: string;
742+
valueString: string;
743+
assetList?: { policy_id: string; asset_name: string; quantity: string }[];
744+
}[];
745+
const parsedTokenOutput = parsedTxOutputs.find((o) => o.assetList !== undefined);
746+
should.exist(parsedTokenOutput);
747+
parsedTokenOutput!.assetList!.length.should.equal(1);
748+
should.deepEqual(parsedTokenOutput!.assetList![0].policy_id, tokenPolicyId);
749+
should.deepEqual(parsedTokenOutput!.assetList![0].asset_name, tokenEncodedAssetName);
750+
should.deepEqual(parsedTokenOutput!.assetList![0].quantity, tokenQuantity);
751+
// pure ADA output should not have assetList
752+
const parsedAdaOutput = parsedTxOutputs.find((o) => o.assetList === undefined);
753+
should.exist(parsedAdaOutput);
754+
});
755+
677756
it('should recover ADA plus token UTXOs - token and ADA both appear in outputs (signed)', async function () {
678757
callBack
679758
.withArgs('address_info', { _addresses: [wrwUser.walletAddress0] })

0 commit comments

Comments
 (0)