diff --git a/modules/sdk-coin-ton/src/lib/explainTransactionWasm.ts b/modules/sdk-coin-ton/src/lib/explainTransactionWasm.ts index bf0b1a3934..e14fab45f2 100644 --- a/modules/sdk-coin-ton/src/lib/explainTransactionWasm.ts +++ b/modules/sdk-coin-ton/src/lib/explainTransactionWasm.ts @@ -23,11 +23,11 @@ function extractOutputs( parsed: WasmParsedTransaction, toAddressBounceable: boolean ): { - outputs: { address: string; amount: string }[]; + outputs: { address: string; amount: string; memo?: string }[]; outputAmount: string; withdrawAmount: string | undefined; } { - const outputs: { address: string; amount: string }[] = []; + const outputs: { address: string; amount: string; memo?: string }[] = []; let withdrawAmount: string | undefined; for (const action of parsed.sendActions) { @@ -39,10 +39,14 @@ function extractOutputs( } else { // destinationBounceable is always EQ... (bounceable) // destination respects the original bounce flag (UQ... when bounce=false) - outputs.push({ + const output: { address: string; amount: string; memo?: string } = { address: toAddressBounceable ? action.destinationBounceable : action.destination, amount: String(action.amount), - }); + }; + if (action.memo) { + output.memo = action.memo; + } + outputs.push(output); } // withdrawAmount comes from the body payload parsed by WASM (not the message TON value) diff --git a/modules/sdk-coin-ton/src/lib/iface.ts b/modules/sdk-coin-ton/src/lib/iface.ts index 7c24021ee5..ec84639d84 100644 --- a/modules/sdk-coin-ton/src/lib/iface.ts +++ b/modules/sdk-coin-ton/src/lib/iface.ts @@ -17,6 +17,7 @@ export interface TxData { sub_wallet_id: number; signature: string; bounceable: boolean; + memoId?: string; } export type TransactionExplanation = ITransactionExplanation; diff --git a/modules/sdk-coin-ton/src/lib/transaction.ts b/modules/sdk-coin-ton/src/lib/transaction.ts index 38f51bcea7..14817ac178 100644 --- a/modules/sdk-coin-ton/src/lib/transaction.ts +++ b/modules/sdk-coin-ton/src/lib/transaction.ts @@ -53,7 +53,7 @@ export class Transaction extends BaseTransaction { true, !new TonWeb.Address(this.recipient.address).isBounceable ); - return { + const result: TxData = { id: this._id as string, sender: this.sender, destination: this.recipient.address, @@ -67,6 +67,10 @@ export class Transaction extends BaseTransaction { signature: this._signatures[0], bounceable: this.bounceable, }; + if (this.message && typeof this.message === 'string' && this._type === TransactionType.Send) { + result.memoId = this.message; + } + return result; } get signablePayload(): Buffer { diff --git a/modules/sdk-coin-ton/src/ton.ts b/modules/sdk-coin-ton/src/ton.ts index 792790f429..4052aa3d43 100644 --- a/modules/sdk-coin-ton/src/ton.ts +++ b/modules/sdk-coin-ton/src/ton.ts @@ -219,19 +219,21 @@ export class Ton extends BaseCoin { const rebuiltTransaction = await transactionBuilder.build(); const parsedTransaction = rebuiltTransaction.toJson(); + const inputEntry: { address: string; amount: string; memo?: string } = { + address: parsedTransaction.sender, + amount: parsedTransaction.amount, + }; + const outputEntry: { address: string; amount: string; memo?: string } = { + address: parsedTransaction.destination, + amount: parsedTransaction.amount, + }; + if (parsedTransaction.memoId) { + inputEntry.memo = parsedTransaction.memoId; + outputEntry.memo = parsedTransaction.memoId; + } return { - inputs: [ - { - address: parsedTransaction.sender, - amount: parsedTransaction.amount, - }, - ], - outputs: [ - { - address: parsedTransaction.destination, - amount: parsedTransaction.amount, - }, - ], + inputs: [inputEntry], + outputs: [outputEntry], }; } diff --git a/modules/sdk-coin-ton/test/resources/ton.ts b/modules/sdk-coin-ton/test/resources/ton.ts index 13b34aad4b..1932e3967e 100644 --- a/modules/sdk-coin-ton/test/resources/ton.ts +++ b/modules/sdk-coin-ton/test/resources/ton.ts @@ -129,6 +129,16 @@ export const signedSendTransactionForMemoId = { }, }; +export const signedSendTransactionWithNumericMemo = { + tx: 'te6cckECGAEAA7wAAuGIADZN0H0n1tz6xkYgWqJSRmkURKYajjEgXeawBo9cifPIGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACmpoxdJlgLSAAAAAAADgEXAgE0AhYBFP8A9KQT9LzyyAsDAgEgBBECAUgFCALm0AHQ0wMhcbCSXwTgItdJwSCSXwTgAtMfIYIQcGx1Z70ighBkc3RyvbCSXwXgA/pAMCD6RAHIygfL/8nQ7UTQgQFA1yH0BDBcgQEI9ApvoTGzkl8H4AXTP8glghBwbHVnupI4MOMNA4IQZHN0crqSXwbjDQYHAHgB+gD0BDD4J28iMFAKoSG+8uBQghBwbHVngx6xcIAYUATLBSbPFlj6Ahn0AMtpF8sfUmDLPyDJgED7AAYAilAEgQEI9Fkw7UTQgQFA1yDIAc8W9ADJ7VQBcrCOI4IQZHN0coMesXCAGFAFywVQA88WI/oCE8tqyx/LP8mAQPsAkl8D4gIBIAkQAgEgCg8CAVgLDAA9sp37UTQgQFA1yH0BDACyMoHy//J0AGBAQj0Cm+hMYAIBIA0OABmtznaiaEAga5Drhf/AABmvHfaiaEAQa5DrhY/AABG4yX7UTQ1wsfgAWb0kK29qJoQICga5D6AhhHDUCAhHpJN9KZEM5pA+n/mDeBKAG3gQFImHFZ8xhAT48oMI1xgg0x/TH9MfAvgju/Jk7UTQ0x/TH9P/9ATRUUO68qFRUbryogX5AVQQZPkQ8qP4ACSkyMsfUkDLH1Iwy/9SEPQAye1U+A8B0wchwACfbFGTINdKltMH1AL7AOgw4CHAAeMAIcAC4wABwAORMOMNA6TIyx8Syx/L/xITFBUAbtIH+gDU1CL5AAXIygcVy//J0Hd0gBjIywXLAiLPFlAF+gIUy2sSzMzJc/sAyEAUgQEI9FHypwIAcIEBCNcY+gDTP8hUIEeBAQj0UfKnghBub3RlcHSAGMjLBcsCUAbPFlAE+gIUy2oSyx/LP8lz+wACAGyBAQjXGPoA0z8wUiSBAQj0WfKnghBkc3RycHSAGMjLBcsCUAXPFlAD+gITy2rLHxLLP8lz+wAACvQAye1UAFEAAAAAKamjF8DDudwJkyEh7jUbJEjFCjriVxsSlRJFyF872V1eegb4QACCQgAaRefBOjTi/hwqDjv+7I6nGj9WEAe3ls/rFuBEQvggr6A613oAAAAAAAAAAAAAAAAAAAAAAAA1NzI4MjY1MDkaHeZ4', + recipient: { + address: 'EQA0i8-CdGnF_DhUHHf92R1ONH6sIA9vLZ_WLcCIhfBBXwtG', + amount: '123400000', + }, + memoId: '572826509', + sender: 'EQAbJug-k-tufWMjEC1RKSM0iiJTDUcYkC7zWANHrkT55Fol', +}; + export const signedSingleNominatorWithdrawTransaction = { tx: 'te6cckECGAEAA8MAAuGIADZN0H0n1tz6xkYgWqJSRmkURKYajjEgXeawBo9cifPIGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACmpoxdJlgLSAAAAAAADgEXAgE0AhYBFP8A9KQT9LzyyAsDAgEgBBECAUgFCALm0AHQ0wMhcbCSXwTgItdJwSCSXwTgAtMfIYIQcGx1Z70ighBkc3RyvbCSXwXgA/pAMCD6RAHIygfL/8nQ7UTQgQFA1yH0BDBcgQEI9ApvoTGzkl8H4AXTP8glghBwbHVnupI4MOMNA4IQZHN0crqSXwbjDQYHAHgB+gD0BDD4J28iMFAKoSG+8uBQghBwbHVngx6xcIAYUATLBSbPFlj6Ahn0AMtpF8sfUmDLPyDJgED7AAYAilAEgQEI9Fkw7UTQgQFA1yDIAc8W9ADJ7VQBcrCOI4IQZHN0coMesXCAGFAFywVQA88WI/oCE8tqyx/LP8mAQPsAkl8D4gIBIAkQAgEgCg8CAVgLDAA9sp37UTQgQFA1yH0BDACyMoHy//J0AGBAQj0Cm+hMYAIBIA0OABmtznaiaEAga5Drhf/AABmvHfaiaEAQa5DrhY/AABG4yX7UTQ1wsfgAWb0kK29qJoQICga5D6AhhHDUCAhHpJN9KZEM5pA+n/mDeBKAG3gQFImHFZ8xhAT48oMI1xgg0x/TH9MfAvgju/Jk7UTQ0x/TH9P/9ATRUUO68qFRUbryogX5AVQQZPkQ8qP4ACSkyMsfUkDLH1Iwy/9SEPQAye1U+A8B0wchwACfbFGTINdKltMH1AL7AOgw4CHAAeMAIcAC4wABwAORMOMNA6TIyx8Syx/L/xITFBUAbtIH+gDU1CL5AAXIygcVy//J0Hd0gBjIywXLAiLPFlAF+gIUy2sSzMzJc/sAyEAUgQEI9FHypwIAcIEBCNcY+gDTP8hUIEeBAQj0UfKnghBub3RlcHSAGMjLBcsCUAbPFlAE+gIUy2oSyx/LP8lz+wACAGyBAQjXGPoA0z8wUiSBAQj0WfKnghBkc3RycHSAGMjLBcsCUAXPFlAD+gITy2rLHxLLP8lz+wAACvQAye1UAFEAAAAAKamjF8DDudwJkyEh7jUbJEjFCjriVxsSlRJFyF872V1eegb4QACPQgAaRefBOjTi/hwqDjv+7I6nGj9WEAe3ls/rFuBEQvggr6A613oAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAHA0/PoUC5EIEyWuPg==', txBounceable: diff --git a/modules/sdk-coin-ton/test/unit/ton.ts b/modules/sdk-coin-ton/test/unit/ton.ts index 9862cc95dc..de175d93b2 100644 --- a/modules/sdk-coin-ton/test/unit/ton.ts +++ b/modules/sdk-coin-ton/test/unit/ton.ts @@ -395,6 +395,30 @@ describe('TON:', function () { stub.restore(); }); }); + + it('should parse a TON transfer transaction with numeric memo (memoId)', async function () { + const tx = testData.signedSendTransactionWithNumericMemo; + const parsedTransaction = await basecoin.parseTransaction({ + txHex: Buffer.from(tx.tx, 'base64').toString('hex'), + }); + + parsedTransaction.should.deepEqual({ + inputs: [ + { + address: tx.sender, + amount: tx.recipient.amount, + memo: tx.memoId, + }, + ], + outputs: [ + { + address: tx.recipient.address, + amount: tx.recipient.amount, + memo: tx.memoId, + }, + ], + }); + }); }); describe('Address Validation', () => {