Skip to content

Commit ef4ce6d

Browse files
committed
feat(sdk-coin-ada): add dummy witness in legacy build for sponsored tx
Ticket: WIN-8764
1 parent e711153 commit ef4ce6d

File tree

3 files changed

+86
-1
lines changed

3 files changed

+86
-1
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,4 +450,5 @@ export class Transaction extends BaseTransaction {
450450
export interface SponsorshipInfo {
451451
feeAddress: string;
452452
feeAddressInputBalance: string;
453+
isRebuild?: boolean; // hack to redirect the flow to the legacy build
453454
}

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,14 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
476476

477477
/** @inheritdoc */
478478
protected async buildImplementation(): Promise<Transaction> {
479-
if (this._isTokenTransaction || (this._sponsorshipInfo && this._type === TransactionType.Send)) {
479+
/**
480+
* Fee address utxo reservation builds a new transaction that goes through legacy build
481+
* rebuild flag is just a hack to redirect the flow to the legacy build
482+
*/
483+
if (
484+
this._isTokenTransaction ||
485+
(this._sponsorshipInfo && !this._sponsorshipInfo.isRebuild && this._type === TransactionType.Send)
486+
) {
480487
return this.processTokenBuild();
481488
}
482489
const inputs = CardanoWasm.TransactionInputs.new();
@@ -598,6 +605,11 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
598605
if (this._type !== TransactionType.Send) {
599606
vkeyWitnesses.add(vkeyWitness);
600607
}
608+
if (this._sponsorshipInfo?.isRebuild) {
609+
const sponsorPrv = CardanoWasm.PrivateKey.generate_ed25519();
610+
const sponsorVkeyWitness = CardanoWasm.make_vkey_witness(txHash, sponsorPrv);
611+
vkeyWitnesses.add(sponsorVkeyWitness);
612+
}
601613
}
602614
witnessSet.set_vkeys(vkeyWitnesses);
603615

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

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,78 @@ describe('ADA Token Operations', async () => {
403403
tx.getFee.should.equal('182485'); // Fee with two witnesses
404404
});
405405

406+
it(`should rebuild a sponsored transaction from hex with isRebuild flag`, async () => {
407+
const feeAddress =
408+
'addr_test1qz2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3jcu5d8ps7zex2k2xt3uqxgjqnnj83ws8lhrn648jjxtwq2ytjqp';
409+
const quantity = '20';
410+
const senderInputBalance = 5000000;
411+
const feeAddressInputBalance = 20000000;
412+
const totalAssetList = {
413+
[fingerprint]: {
414+
quantity: '100',
415+
policy_id: policyId,
416+
asset_name: asciiEncodedName,
417+
},
418+
};
419+
420+
// Step 1: Build the initial sponsored transaction
421+
const txBuilder = factory.getTransferBuilder();
422+
txBuilder.input({
423+
transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21',
424+
transaction_index: 1,
425+
});
426+
txBuilder.input({
427+
transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba22',
428+
transaction_index: 0,
429+
});
430+
431+
txBuilder.output({
432+
address: receiverAddress,
433+
amount: '0',
434+
multiAssets: {
435+
asset_name: asciiEncodedName,
436+
policy_id: policyId,
437+
quantity,
438+
fingerprint,
439+
},
440+
});
441+
442+
txBuilder.changeAddress(senderAddress, senderInputBalance.toString(), totalAssetList);
443+
txBuilder.sponsorshipInfo({
444+
feeAddress: feeAddress,
445+
feeAddressInputBalance: feeAddressInputBalance.toString(),
446+
});
447+
txBuilder.ttl(800000000);
448+
txBuilder.isTokenTransaction();
449+
const initialTx = (await txBuilder.build()) as Transaction;
450+
const initialTxHex = initialTx.toBroadcastFormat();
451+
const initialFee = initialTx.getFee;
452+
453+
// Step 2: Rebuild from hex with isRebuild = true
454+
const rebuildTxBuilder = factory.from(initialTxHex);
455+
rebuildTxBuilder.changeAddress(senderAddress, senderInputBalance.toString(), totalAssetList);
456+
rebuildTxBuilder.sponsorshipInfo({
457+
feeAddress: feeAddress,
458+
feeAddressInputBalance: feeAddressInputBalance.toString(),
459+
isRebuild: true,
460+
});
461+
462+
const rebuiltTx = (await rebuildTxBuilder.build()) as Transaction;
463+
const rebuiltTxData = rebuiltTx.toJson();
464+
465+
// Verify the rebuilt transaction has same structure
466+
rebuiltTxData.inputs.length.should.equal(2);
467+
rebuiltTxData.outputs.length.should.equal(4);
468+
469+
// The fee should remain the same since isRebuild adds dummy witness for fee calculation
470+
rebuiltTx.getFee.should.equal(initialFee);
471+
472+
// Verify receiver output is preserved
473+
const receiverOutput = rebuiltTxData.outputs.filter((output) => output.address === receiverAddress);
474+
receiverOutput.length.should.equal(1);
475+
receiverOutput[0].amount.should.equal('1500000');
476+
});
477+
406478
describe('AdaToken verifyTransaction', () => {
407479
let bitgo: TestBitGoAPI;
408480
let adaToken;

0 commit comments

Comments
 (0)