From f2422d37a98a5eac581ac5fee538d76358ba4db9 Mon Sep 17 00:00:00 2001 From: Ravi Hegde Date: Sat, 25 Oct 2025 17:14:46 +0530 Subject: [PATCH] feat(sdk-coin-canton): added handling is parse raw canton transaction to correctly extract the data Ticket: COIN-6180 --- modules/sdk-coin-canton/src/lib/utils.ts | 61 ++++++++++++++-------- modules/sdk-coin-canton/test/unit/utils.ts | 27 ++++++++++ 2 files changed, 65 insertions(+), 23 deletions(-) diff --git a/modules/sdk-coin-canton/src/lib/utils.ts b/modules/sdk-coin-canton/src/lib/utils.ts index 905554cd5a..fdafe902fb 100644 --- a/modules/sdk-coin-canton/src/lib/utils.ts +++ b/modules/sdk-coin-canton/src/lib/utils.ts @@ -94,32 +94,47 @@ export class Utils implements BaseUtils { const createNode = nodeType.create; + const getField = (fields: RecordField[], label: string) => fields.find((f) => f.label === label)?.value?.sum; + // Check if it's the correct template const template = createNode.templateId; - if (template?.entityName !== 'AmuletTransferInstruction') return; - - // Now parse the 'create' argument - if (createNode.argument?.sum?.oneofKind !== 'record') return; - const fields = createNode.argument?.sum?.record?.fields; + const argSum = createNode.argument?.sum; + if (!argSum || argSum.oneofKind !== 'record') return; + const fields = argSum.record?.fields; if (!fields) return; - - // Find the 'transfer' field - const transferField = fields.find((f) => f.label === 'transfer'); - if (transferField?.value?.sum?.oneofKind !== 'record') return; - const transferRecord = transferField?.value?.sum?.record?.fields; - if (!transferRecord) return; - - const getField = (fields: RecordField[], label: string) => fields.find((f) => f.label === label)?.value?.sum; - - const senderData = getField(transferRecord, 'sender'); - if (!senderData || senderData.oneofKind !== 'party') return; - sender = senderData.party; - const receiverData = getField(transferRecord, 'receiver'); - if (!receiverData || receiverData.oneofKind !== 'party') return; - receiver = receiverData.party; - const amountData = getField(transferRecord, 'amount'); - if (!amountData || amountData.oneofKind !== 'numeric') return; - amount = amountData.numeric; + if (template?.entityName === 'AmuletTransferInstruction') { + const transferField = fields.find((f) => f.label === 'transfer'); + const transferSum = transferField?.value?.sum; + if (!transferSum || transferSum.oneofKind !== 'record') return; + const transferRecord = transferSum.record?.fields; + if (!transferRecord) return; + const senderData = getField(transferRecord, 'sender'); + if (senderData?.oneofKind === 'party') sender = senderData.party ?? ''; + + const receiverData = getField(transferRecord, 'receiver'); + if (receiverData?.oneofKind === 'party') receiver = receiverData.party ?? ''; + + const amountData = getField(transferRecord, 'amount'); + if (amountData?.oneofKind === 'numeric') amount = amountData.numeric ?? ''; + } else if (template?.entityName === 'Amulet') { + const dsoData = getField(fields, 'dso'); + if (dsoData?.oneofKind === 'party') sender = dsoData.party ?? ''; + const ownerData = getField(fields, 'owner'); + if (ownerData?.oneofKind === 'party') receiver = ownerData.party ?? ''; + const amountField = getField(fields, 'amount'); + if (!amountField || amountField.oneofKind !== 'record') return; + + const amountRecord = amountField.record?.fields; + if (!amountRecord) return; + const initialAmountData = getField(amountRecord, 'initialAmount'); + if (initialAmountData?.oneofKind === 'numeric') amount = initialAmountData.numeric ?? ''; + } else if (template?.entityName === 'TransferPreapprovalProposal') { + const receiverData = getField(fields, 'receiver'); + if (receiverData?.oneofKind === 'party') receiver = receiverData.party ?? ''; + const providerData = getField(fields, 'provider'); + if (providerData?.oneofKind === 'party') sender = providerData.party ?? ''; + amount = '0'; + } }); if (!sender || !receiver || !amount) { const missingFields: string[] = []; diff --git a/modules/sdk-coin-canton/test/unit/utils.ts b/modules/sdk-coin-canton/test/unit/utils.ts index 32ce645f53..fc0edb2e59 100644 --- a/modules/sdk-coin-canton/test/unit/utils.ts +++ b/modules/sdk-coin-canton/test/unit/utils.ts @@ -4,8 +4,10 @@ import utils from '../../src/lib/utils'; import { CANTON_ADDRESSES, GenerateTopologyResponse, + OneStepPreApprovalPrepareResponse, PreparedTransactionRawData, PrepareSubmissionResponse, + TransferAcceptancePrepareResponse, } from '../resources'; describe('Canton Util', function () { @@ -17,6 +19,31 @@ describe('Canton Util', function () { assert.equal(parsedData.receiver, 'abc-2::12207e96ada18a845adf4dc01410265633d5266dca9bb280c98e35c3692db87d3e35'); assert.equal(parsedData.amount, '20.0000000000'); }); + + it('should parse the acceptance prepared transaction', () => { + const parsedData = utils.parseRawCantonTransactionData(TransferAcceptancePrepareResponse.preparedTransaction); + should.exist(parsedData); + assert.equal(parsedData.sender, 'DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a'); + assert.equal( + parsedData.receiver, + 'ravi-demo-party-txn-01-tapper::1220ea7ab5a723f8a6b2078e617e6c58cb7e78e49947ddc239e1a941aa56e6ba08b4' + ); + assert.equal(parsedData.amount, '5.0000000000'); + }); + + it('should parse the one-step preapproval prepared transaction', () => { + const parsedData = utils.parseRawCantonTransactionData(OneStepPreApprovalPrepareResponse.preparedTransaction); + should.exist(parsedData); + assert.equal( + parsedData.sender, + 'Bitgo-devnet-validator-1::1220a0a0f60b0e62b5d750c484b18c091dba23080c133d944614ba75a5858cba3045' + ); + assert.equal( + parsedData.receiver, + 'ravi-test-party-1::12205b4e3537a95126d90604592344d8ad3c3ddccda4f79901954280ee19c576714d' + ); + assert.equal(parsedData.amount, '0'); + }); }); describe('Wallet init transaction', function () {