From 3661c2b5eb8b4b3b14e3f08b263266dfe0a50279 Mon Sep 17 00:00:00 2001 From: Dhanush GM Date: Fri, 20 Feb 2026 12:29:19 +0530 Subject: [PATCH] fix(sdk-coin-ada): relax verifyTransaction amount check for gas tan TICKET: WIN-9022 --- modules/sdk-coin-ada/src/ada.ts | 5 +- modules/sdk-coin-ada/src/adaToken.ts | 2 +- modules/sdk-coin-ada/test/unit/ada.ts | 91 +++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 2 deletions(-) diff --git a/modules/sdk-coin-ada/src/ada.ts b/modules/sdk-coin-ada/src/ada.ts index 870fe2ecc7..ccbd07a871 100644 --- a/modules/sdk-coin-ada/src/ada.ts +++ b/modules/sdk-coin-ada/src/ada.ts @@ -139,7 +139,10 @@ export class Ada extends BaseCoin { for (const recipient of txParams.recipients) { let find = false; for (const output of explainedTx.outputs) { - if (recipient.address === output.address && recipient.amount === output.amount) { + if ( + recipient.address === output.address && + (recipient.amount === 'max' || BigInt(output.amount) >= BigInt(recipient.amount)) + ) { find = true; } } diff --git a/modules/sdk-coin-ada/src/adaToken.ts b/modules/sdk-coin-ada/src/adaToken.ts index 20126a5970..4ec4a98883 100644 --- a/modules/sdk-coin-ada/src/adaToken.ts +++ b/modules/sdk-coin-ada/src/adaToken.ts @@ -137,7 +137,7 @@ export class AdaToken extends Ada { } const multiAssets = output.multiAssets as CardanoWasm.MultiAsset; const tokenQty = multiAssets.get_asset(policyScriptHash, assetName); - return tokenQty && tokenQty.to_str() === recipient.amount; + return tokenQty && (recipient.amount === 'max' || BigInt(tokenQty.to_str()) >= BigInt(recipient.amount)); }); if (!found) { diff --git a/modules/sdk-coin-ada/test/unit/ada.ts b/modules/sdk-coin-ada/test/unit/ada.ts index 21ffa39013..255ef59602 100644 --- a/modules/sdk-coin-ada/test/unit/ada.ts +++ b/modules/sdk-coin-ada/test/unit/ada.ts @@ -249,6 +249,97 @@ describe('ADA', function () { validTransaction.should.equal(true); }); + it('should succeed when output amount >= requested amount for any gas tank address (WIN-9022)', async () => { + // WIN-9022: gas tank transactions cause the server to absorb dust change into the + // output, so the actual output amount may be larger than requested. The >= check + // allows this for ANY address as long as the output sends at least what was requested. + const txPrebuild = newTxPrebuild(); + const testCases = [ + { address: rawTx.outputAddress1.address, amount: '2000000' }, + { address: rawTx.outputAddress1.address, amount: '1' }, + { address: rawTx.outputAddress1.address, amount: '5000000' }, + { address: rawTx.outputAddress2.address, amount: '1' }, + ]; + for (const { address, amount } of testCases) { + const txParams = { + recipients: [{ address, amount }], + }; + const isTransactionVerified = await basecoin.verifyTransaction({ + txParams, + txPrebuild, + verification: {}, + }); + isTransactionVerified.should.equal(true); + } + }); + + it('should fail when requested amount exceeds actual output amount', async () => { + const txPrebuild = newTxPrebuild(); + const txParams = { + recipients: [ + { + address: rawTx.outputAddress1.address, + amount: '9999999999', + }, + ], + }; + + await basecoin + .verifyTransaction({ txParams, txPrebuild, verification: {} }) + .should.be.rejectedWith('cannot find recipient in expected output'); + }); + + it('should succeed when recipient amount is max', async () => { + const txPrebuild = newTxPrebuild(); + const txParams = { + recipients: [ + { + address: rawTx.outputAddress1.address, + amount: 'max', + }, + ], + }; + + const isTransactionVerified = await basecoin.verifyTransaction({ + txParams, + txPrebuild, + verification: {}, + }); + isTransactionVerified.should.equal(true); + }); + + it('should fail when address does not match any output regardless of amount', async () => { + const txPrebuild = newTxPrebuild(); + const txParams = { + recipients: [ + { + address: 'addr_test1vrcx9yqtect97qlfq0hmttsd6ns38kvqw6lhcsyjwsh6zuqdpvg6u', + amount: '1', + }, + ], + }; + + await basecoin + .verifyTransaction({ txParams, txPrebuild, verification: {} }) + .should.be.rejectedWith('cannot find recipient in expected output'); + }); + + it('should fail when recipient amount is max but address does not match', async () => { + const txPrebuild = newTxPrebuild(); + const txParams = { + recipients: [ + { + address: '9f7b0675db59d19b4bd9c8c72eaabba75a9863d02b30115b8b3c3ca5c20f0254', + amount: 'max', + }, + ], + }; + + await basecoin + .verifyTransaction({ txParams, txPrebuild, verification: {} }) + .should.be.rejectedWith('cannot find recipient in expected output'); + }); + it('should verify a valid consolidation transaction', async () => { const consolidationTx = { txRequestId: '1b5c79c5-ab7c-4f47-912b-de6a95fb0779',