Skip to content

Commit a248143

Browse files
authored
Merge pull request #7663 from BitGo/COIN-6748
feat: added memoId handling in verifyTransaction
2 parents a600d30 + c777fed commit a248143

File tree

7 files changed

+85
-3
lines changed

7 files changed

+85
-3
lines changed

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,17 @@ export class Canton extends BaseCoin {
119119
if (txParams.recipients !== undefined) {
120120
const filteredRecipients = txParams.recipients?.map((recipient) => {
121121
const { address, amount } = recipient;
122+
const [addressPart, memoId] = address.split('?memoId=');
123+
if (memoId) {
124+
return { address: addressPart, amount, memo: memoId };
125+
}
122126
return { address, amount };
123127
});
124128
const filteredOutputs = explainedTx.outputs?.map((output) => {
125-
const { address, amount } = output;
129+
const { address, amount, memo } = output;
130+
if (memo) {
131+
return { address, amount, memo };
132+
}
126133
return { address, amount };
127134
});
128135
if (JSON.stringify(filteredRecipients) !== JSON.stringify(filteredOutputs)) {

modules/sdk-coin-canton/src/lib/iface.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ export interface TxData {
2121
receiver: string;
2222
amount: string;
2323
acknowledgeData?: TransferAcknowledge;
24+
memoId?: string;
2425
}
2526

2627
export interface PreparedTxnParsedInfo {
2728
sender: string;
2829
receiver: string;
2930
amount: string;
31+
memoId?: string;
3032
}
3133

3234
export interface WalletInitTxData {

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ export class Transaction extends BaseTransaction {
157157
result.sender = parsedInfo.sender;
158158
result.receiver = parsedInfo.receiver;
159159
result.amount = parsedInfo.amount;
160+
if (parsedInfo.memoId) {
161+
result.memoId = parsedInfo.memoId;
162+
}
160163
return result;
161164
}
162165

@@ -244,7 +247,14 @@ export class Transaction extends BaseTransaction {
244247
}
245248
case TransactionType.Send: {
246249
const txData = this.toJson();
247-
outputs.push({ address: txData.receiver, amount: txData.amount });
250+
const output: ITransactionRecipient = {
251+
address: txData.receiver,
252+
amount: txData.amount,
253+
};
254+
if (txData.memoId) {
255+
output.memo = txData.memoId;
256+
}
257+
outputs.push(output);
248258
outputAmount = txData.amount;
249259
break;
250260
}

modules/sdk-coin-canton/src/lib/utils.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export class Utils implements BaseUtils {
9090
let sender = '';
9191
let receiver = '';
9292
let amount = '';
93+
let memoId: string | undefined;
9394
let preApprovalNode: RecordField[] = [];
9495
let transferNode: RecordField[] = [];
9596
let transferAcceptRejectNode: RecordField[] = [];
@@ -161,6 +162,24 @@ export class Utils implements BaseUtils {
161162

162163
const amountData = getField(transferRecord, 'amount');
163164
if (amountData?.oneofKind === 'numeric') amount = amountData.numeric ?? '';
165+
166+
const metaField = getField(transferRecord, 'meta');
167+
if (metaField?.oneofKind === 'record') {
168+
const metaFields = metaField.record?.fields;
169+
if (metaFields && metaFields.length) {
170+
const valuesField = getField(metaFields, 'values');
171+
if (valuesField?.oneofKind === 'textMap') {
172+
const entries = valuesField.textMap?.entries ?? [];
173+
const memoEntry = entries.find((e) => e.key === 'splice.lfdecentralizedtrust.org/reason');
174+
if (memoEntry) {
175+
const memoValue = memoEntry?.value?.sum;
176+
if (memoValue?.oneofKind === 'text') {
177+
memoId = memoValue.text;
178+
}
179+
}
180+
}
181+
}
182+
}
164183
}
165184
}
166185
} else if (transferAcceptRejectNode.length) {
@@ -185,11 +204,15 @@ export class Utils implements BaseUtils {
185204
throw new Error(`invalid transaction data: missing ${missingFields.join(', ')}`);
186205
}
187206
const convertedAmount = this.convertAmountToLowestUnit(new BigNumber(amount));
188-
return {
207+
const parsedData: PreparedTxnParsedInfo = {
189208
sender,
190209
receiver,
191210
amount: convertedAmount,
192211
};
212+
if (memoId) {
213+
parsedData.memoId = memoId;
214+
}
215+
return parsedData;
193216
}
194217

195218
/**

modules/sdk-coin-canton/test/integration/canton.integration.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import {
1010
GenerateTopologyResponse,
1111
TransferAcceptRawTransaction,
1212
TransferRawTxn,
13+
TransferRawTxnWithMemo,
1314
TransferRejectRawTransaction,
1415
TxParams,
16+
TxParamsWithMemo,
1517
WalletInitRawTransaction,
1618
} from '../resources';
1719
import { Tcanton } from '../../src';
@@ -54,6 +56,23 @@ describe('Canton integration tests', function () {
5456
const isTxnVerifies = await basecoin.verifyTransaction({ txPrebuild: txPrebuild, txParams: txParams, wallet });
5557
isTxnVerifies.should.equal(true);
5658
});
59+
60+
it('should verify transfer transaction with memo', async function () {
61+
const txPrebuild = {
62+
txHex: TransferRawTxnWithMemo,
63+
txInfo: {},
64+
};
65+
const txParams = {
66+
recipients: [
67+
{
68+
address: TxParamsWithMemo.RECIPIENT_ADDRESS,
69+
amount: TxParamsWithMemo.AMOUNT,
70+
},
71+
],
72+
};
73+
const isTxnVerifies = await basecoin.verifyTransaction({ txPrebuild: txPrebuild, txParams: txParams, wallet });
74+
isTxnVerifies.should.equal(true);
75+
});
5776
});
5877

5978
describe('Explain raw transaction', function () {

modules/sdk-coin-canton/test/resources.ts

Lines changed: 11 additions & 0 deletions
Large diffs are not rendered by default.

modules/sdk-coin-canton/test/unit/utils.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
GenerateTopologyResponse,
1111
OneStepPreApprovalPrepareResponse,
1212
PreparedTransactionRawData,
13+
PreparedTransactionWithMemo,
1314
PreparedTxn1StepReceiver,
1415
PreparedTxn2StepReceiver,
1516
PrepareSubmissionResponse,
@@ -27,6 +28,15 @@ describe('Canton Util', function () {
2728
assert.equal(parsedData.amount, '200000000000');
2829
});
2930

31+
it('should parse the prepared transaction with memo id field', function () {
32+
const parsedData = utils.parseRawCantonTransactionData(PreparedTransactionWithMemo, TransactionType.Send);
33+
should.exist(parsedData);
34+
assert.equal(parsedData.sender, '1220b::1220bab6ef3eec37b1b3816099befe72b43bf6c1380077d6349254c41ffb7f7753bb');
35+
assert.equal(parsedData.receiver, '1220a::1220ade60300cf7d0b18ffaa2ffe4f492ad1ad601cfc162b20f77ec99d16c2c2f158');
36+
assert.equal(parsedData.amount, '1000000000');
37+
assert.equal(parsedData.memoId, '11');
38+
});
39+
3040
it('should parse correctly when receiver is on 2-step', () => {
3141
const parsedData = utils.parseRawCantonTransactionData(PreparedTxn2StepReceiver, TransactionType.Send);
3242
should.exist(parsedData);

0 commit comments

Comments
 (0)