Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions modules/sdk-coin-ada/src/ada.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export interface AdaTxInfo {

export interface ExplainTransactionOptions {
txPrebuild: TransactionPrebuild;
changeAddress?: string;
}

export interface AdaParseTransactionOptions extends BaseParseTransactionOptions {
Expand Down Expand Up @@ -204,16 +205,20 @@ export class Ada extends BaseCoin {
*/
async explainTransaction(params: ExplainTransactionOptions): Promise<AdaTransactionExplanation> {
const factory = this.getBuilder();
let rebuiltTransaction: BaseTransaction;
let rebuiltTransaction: Transaction;
const txRaw = params.txPrebuild.txHex;

try {
const transactionBuilder = factory.from(txRaw);
rebuiltTransaction = await transactionBuilder.build();
rebuiltTransaction = (await transactionBuilder.build()) as Transaction;
} catch {
throw new Error('Invalid transaction');
}

if (params.changeAddress) {
rebuiltTransaction.changeAddress = params.changeAddress;
}

return rebuiltTransaction.explainTransaction() as unknown as AdaTransactionExplanation;
}

Expand Down
7 changes: 7 additions & 0 deletions modules/sdk-coin-ada/src/lib/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ export class Transaction extends BaseTransaction {
private _transaction: CardanoWasm.Transaction;
private _fee: string;
private _pledgeDetails?: PledgeDetails;
private _changeAddress?: string;

set changeAddress(address: string) {
this._changeAddress = address;
}

constructor(coinConfig: Readonly<CoinConfig>) {
super(coinConfig);
Expand Down Expand Up @@ -426,10 +431,12 @@ export class Transaction extends BaseTransaction {
id: txJson.id,
outputs: txJson.outputs.map((o) => {
const multiAssets = Transaction.parseMultiAssets(o.multiAssets as CardanoWasm.MultiAsset | undefined);
const isChange = this._changeAddress !== undefined && o.address === this._changeAddress;
return {
address: o.address,
amount: o.amount,
...(multiAssets && { multiAssets }),
...(isChange && { change: true }),
};
}),
outputAmount: outputAmount,
Expand Down
9 changes: 9 additions & 0 deletions modules/sdk-coin-ada/src/lib/transactionBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,9 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
this.setMutableSenderAssetList();
this.addOutputs(outputs);
this._transaction.transaction = this.prepareAdaTransactionDraft(inputs, outputs, true);
if (this._changeAddress) {
this._transaction.changeAddress = this._changeAddress;
}
return this.transaction;
}

Expand Down Expand Up @@ -573,6 +576,9 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {

const finalOutputs = this.buildExplicitOutputsCollection(this._fee);
this._transaction.transaction = this.prepareAdaTransactionDraft(inputs, finalOutputs, true);
if (this._changeAddress) {
this._transaction.changeAddress = this._changeAddress;
}
return this.transaction;
}

Expand Down Expand Up @@ -924,6 +930,9 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
});
witnessSet.set_vkeys(vkeyWitnesses);
this._transaction.transaction = CardanoWasm.Transaction.new(txRaw, witnessSet);
if (this._changeAddress) {
this._transaction.changeAddress = this._changeAddress;
}
return this.transaction;
}

Expand Down
62 changes: 62 additions & 0 deletions modules/sdk-coin-ada/test/unit/transactionBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -549,4 +549,66 @@ describe('ADA Transaction Builder', async () => {
// console.log(err);
// }
// });

describe('explainTransaction change output marking', () => {
it('should mark the change output with change: true in explainTransaction', async () => {
const txBuilder = factory.getTransferBuilder();
txBuilder.input({
transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21',
transaction_index: 1,
});
const outputAmount = 7823121;
txBuilder.output({
address: testData.rawTx.outputAddress1.address,
amount: outputAmount.toString(),
});
const changeAddr = testData.rawTx.outputAddress2.address;
const totalInput = 21032023;
txBuilder.changeAddress(changeAddr, totalInput.toString());
txBuilder.ttl(800000000);

const tx = (await txBuilder.build()) as Transaction;
const explained = tx.explainTransaction();

const changeOutputs = explained.outputs.filter((o) => o.change === true);
const nonChangeOutputs = explained.outputs.filter((o) => !o.change);

changeOutputs.length.should.equal(1);
changeOutputs[0].address.should.equal(changeAddr);
nonChangeOutputs.length.should.equal(1);
nonChangeOutputs[0].address.should.equal(testData.rawTx.outputAddress1.address);
});

it('should not mark any output as change when no changeAddress is set', async () => {
const preBuiltTx = new Transaction(coins.get('tada'));
preBuiltTx.fromRawTransaction(testData.rawTx.unsignedTx2);
const txBuilder = factory.getTransferBuilder();
txBuilder.initBuilder(preBuiltTx);

const tx = (await txBuilder.build()) as Transaction;
const explained = tx.explainTransaction();

const changeOutputs = explained.outputs.filter((o) => o.change === true);
changeOutputs.length.should.equal(0);
});

it('should mark consolidation output with change: true when changeAddress matches the single output', async () => {
const txBuilder = factory.getTransferBuilder();
txBuilder.input({
transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21',
transaction_index: 1,
});
const changeAddr = testData.rawTx.outputAddress1.address;
const totalInput = 20000000;
txBuilder.changeAddress(changeAddr, totalInput.toString());
txBuilder.ttl(800000000);

const tx = (await txBuilder.build()) as Transaction;
const explained = tx.explainTransaction();

const changeOutputs = explained.outputs.filter((o) => o.change === true);
changeOutputs.length.should.equal(1);
changeOutputs[0].address.should.equal(changeAddr);
});
});
});
Loading