From 348ba0d144b12c91d4a5cae69f01c6e8e0389f98 Mon Sep 17 00:00:00 2001 From: Ravi Hegde Date: Thu, 22 Oct 2026 15:52:58 +0530 Subject: [PATCH] feat(sdk-coin-canton): support Broadridge standing delegation response parsing Ticket: CHALO-1921 --- ...roadridgeSettlementAuthorizationBuilder.ts | 6 ++++- .../sdk-coin-canton/src/lib/clearSigning.ts | 2 +- modules/sdk-coin-canton/src/lib/iface.ts | 4 ++- modules/sdk-coin-canton/src/lib/utils.ts | 1 + modules/sdk-coin-canton/test/resources.ts | 14 ++++++++++ .../settlementAuthorizationBuilder.ts | 2 ++ modules/sdk-coin-canton/test/unit/utils.ts | 27 +++++++++++++++++++ 7 files changed, 53 insertions(+), 3 deletions(-) diff --git a/modules/sdk-coin-canton/src/lib/broadridgeSettlementAuthorizationBuilder.ts b/modules/sdk-coin-canton/src/lib/broadridgeSettlementAuthorizationBuilder.ts index 156f4f68f84..6939b65757a 100644 --- a/modules/sdk-coin-canton/src/lib/broadridgeSettlementAuthorizationBuilder.ts +++ b/modules/sdk-coin-canton/src/lib/broadridgeSettlementAuthorizationBuilder.ts @@ -172,6 +172,9 @@ export class BroadridgeSettlementAuthorizationBuilder extends CantonCommandBuild }, }; this.command(command); + const createArguments = operation === 'Create' ? params.choiceArgument ?? {} : {}; + const client = typeof createArguments.client === 'string' ? createArguments.client : undefined; + const executor = typeof createArguments.executor === 'string' ? createArguments.executor : undefined; this._broadridge = { protocol: 'broadridge', standard: 'CIP-56', @@ -182,7 +185,8 @@ export class BroadridgeSettlementAuthorizationBuilder extends CantonCommandBuild ...(operation !== 'Create' ? { choice: operation } : {}), role, actors: [...params.actAs], - ...(params.contractId ? { contractId: params.contractId } : {}), + ...(client ? { client } : {}), + ...(executor ? { executor } : {}), ...(params.requestCid ? { requestCid: params.requestCid } : {}), ...(params.agreementCid ? { agreementCid: params.agreementCid } : {}), ...(params.settlement ? { settlement: params.settlement } : {}), diff --git a/modules/sdk-coin-canton/src/lib/clearSigning.ts b/modules/sdk-coin-canton/src/lib/clearSigning.ts index dd3e3edd584..6ab0433f635 100644 --- a/modules/sdk-coin-canton/src/lib/clearSigning.ts +++ b/modules/sdk-coin-canton/src/lib/clearSigning.ts @@ -31,7 +31,7 @@ export interface DecodedCantonTransaction { choice?: string; /** Contract ID being exercised — present for ExerciseCommand only */ contractId?: string; - /** Parties acting on this command — present for ExerciseCommand only */ + /** Parties acting on this command — submitter actAs for CreateCommand, root acting parties for ExerciseCommand */ actingParties?: string[]; } diff --git a/modules/sdk-coin-canton/src/lib/iface.ts b/modules/sdk-coin-canton/src/lib/iface.ts index 94c123ea01b..ed7b16f17e8 100644 --- a/modules/sdk-coin-canton/src/lib/iface.ts +++ b/modules/sdk-coin-canton/src/lib/iface.ts @@ -131,6 +131,8 @@ export interface BroadridgeProtocolDescriptor { choice?: string; role: 'client' | 'executor' | 'trading-party' | 'agreement' | 'request' | 'allocation'; actors: string[]; + client?: string; + executor?: string; contractId?: string; requestCid?: string; agreementCid?: string; @@ -421,5 +423,5 @@ export interface CantonCommandInfo { argument: unknown; choice?: string; // ExerciseCommand only contractId?: string; // ExerciseCommand only - actingParties?: string[]; // ExerciseCommand only + actingParties?: string[]; // Submitter actAs for CreateCommand; root acting parties for ExerciseCommand } diff --git a/modules/sdk-coin-canton/src/lib/utils.ts b/modules/sdk-coin-canton/src/lib/utils.ts index 8f7fcc8272a..843e33a269b 100644 --- a/modules/sdk-coin-canton/src/lib/utils.ts +++ b/modules/sdk-coin-canton/src/lib/utils.ts @@ -791,6 +791,7 @@ export class Utils implements BaseUtils { entityName: createNode.templateId.entityName, }, argument: this.damlValueToJson(createNode.argument), + actingParties: [...(decoded.metadata?.submitterInfo?.actAs ?? [])], }; } if (nodeType.oneofKind === 'exercise') { diff --git a/modules/sdk-coin-canton/test/resources.ts b/modules/sdk-coin-canton/test/resources.ts index 23a3fac63ca..1561d2c5a96 100644 --- a/modules/sdk-coin-canton/test/resources.ts +++ b/modules/sdk-coin-canton/test/resources.ts @@ -503,3 +503,17 @@ export const TransferPreapprovalCancelPrepareResponse = { preparedTransactionHash: 'placeholder-hash-not-cryptographically-verified==', hashingSchemeVersion: 'HASHING_SCHEME_VERSION_V2', }; + +export const CantonStandingDelegationPrepareResponse = { + preparedTransaction: + 'CuAICgMyLjESATAasQgKATDCPqoICqcICgMyLjESQjAwYmU0YWI1OTdmNzMwNWVkMzdiM2VlYjgzYzQwNWVhMDc3ZGVlZjlkNDBmY2M2ZmIzZGU0ZjEwZDMxMzExYWQzMBopYnJvYWRyaWRnZS1zZXR0bGVtZW50LWF1dGhvcml6YXRpb24tY2lwNTYimQEKQDNmZTVjMzQyNDUyMDE0NmU1NGY0M2IyYzc0NTQzZmEzODdiMDA3NzJmZDE5OGIwYTI3MDc5NzA4Y2M1OTg2NjMSOkJyb2FkcmlkZ2UuVG9rZW4uSW1wbGVtZW50YXRpb25zLlN0YW5kaW5nRGVsZWdhdGlvbkltcGxfdjEaGVN0YW5kaW5nRGVsZWdhdGlvbkltcGxfdjEqkQRyjgQKmQEKQDNmZTVjMzQyNDUyMDE0NmU1NGY0M2IyYzc0NTQzZmEzODdiMDA3NzJmZDE5OGIwYTI3MDc5NzA4Y2M1OTg2NjMSOkJyb2FkcmlkZ2UuVG9rZW4uSW1wbGVtZW50YXRpb25zLlN0YW5kaW5nRGVsZWdhdGlvbkltcGxfdjEaGVN0YW5kaW5nRGVsZWdhdGlvbkltcGxfdjESYQoGY2xpZW50Elc6VXRlc3QtZGVsZWdhdGlvbjo6MTIyMDkyZTdkMzNhYzEwYzBmM2Q1NTk3NjM0MmYzNzU1NWRmMDVkYTViNzQyOTU2ZDU2YTYyYWUyMzY3NzY5MDc5ZDISYQoIZXhlY3V0b3ISVTpTYnRnby1vcGVyYXRvcjo6MTIyMGViNjkzYWRlNDg2ZmY4YTExMmY5OTllNjM5MmZjMDQyN2JjMTRkYTQyZWUyMGU1MTk5ODU3NWE1M2VmZWYwY2QSqQEKBG1ldGESoAFynQEKaQpANGRlZDZiNjY4Y2IzYjY0ZjdhODhhMzA4NzRjZDQxYzc1ODI5ZjVlMDY0YjNmYmJhZGY0MWVjN2U4MzYzMzU0ZhIbU3BsaWNlLkFwaS5Ub2tlbi5NZXRhZGF0YVYxGghNZXRhZGF0YRIwCgZ2YWx1ZXMSJmIkCiIKEmJpdGdvLnNhbmRib3gvbm90ZRIMQgpvbmJvYXJkaW5nMlV0ZXN0LWRlbGVnYXRpb246OjEyMjA5MmU3ZDMzYWMxMGMwZjNkNTU5NzYzNDJmMzc1NTVkZjA1ZGE1Yjc0Mjk1NmQ1NmE2MmFlMjM2Nzc2OTA3OWQyOlNidGdvLW9wZXJhdG9yOjoxMjIwZWI2OTNhZGU0ODZmZjhhMTEyZjk5OWU2MzkyZmMwNDI3YmMxNGRhNDJlZTIwZTUxOTk4NTc1YTUzZWZlZjBjZDpVdGVzdC1kZWxlZ2F0aW9uOjoxMjIwOTJlN2QzM2FjMTBjMGYzZDU1OTc2MzQyZjM3NTU1ZGYwNWRhNWI3NDI5NTZkNTZhNjJhZTIzNjc3NjkwNzlkMiIiEiDcvbU+UsBQy7GKbq9PqCHF+0Qjudd2HW1b5oDFNvSjGRKJAhJ9ClV0ZXN0LWRlbGVnYXRpb246OjEyMjA5MmU3ZDMzYWMxMGMwZjNkNTU5NzYzNDJmMzc1NTVkZjA1ZGE1Yjc0Mjk1NmQ1NmE2MmFlMjM2Nzc2OTA3OWQyEiQ3M2Q2YTViYi1jYzM4LTRkZTYtOWU1YS04ZTA0NDc5OTk0NjIaWWdsb2JhbC1kb21haW46OjEyMjBmMjJhOGI4ZjJkODEzYzI1YjlhNjg0ZGM0ZGQ1MmI1MzJhMDE3NGQ4ZTczYTEzY2RmMmJhYWJmZmY3NTE4MzM3OjozNS0zKiRkNTBlYzFjZS0wMDQ4LTQ2ZWQtOTI2Ni0zY2MzYzk0ODZiODQwxt+S97DNlwM=', + preparedTransactionHash: 'ksIGb7rHHuKuVP8RDe1f2NBTuUeeJTXfdYm1HonctHs=', + hashingSchemeVersion: 'HASHING_SCHEME_VERSION_V2', + hashingDetails: null, + costEstimation: { + estimationTimestamp: '2026-10-22T10:09:19.086839Z', + confirmationRequestTrafficCostEstimation: 3491, + confirmationResponseTrafficCostEstimation: 0, + totalTrafficCostEstimation: 3491, + }, +}; diff --git a/modules/sdk-coin-canton/test/unit/builder/settlementAuthorization/settlementAuthorizationBuilder.ts b/modules/sdk-coin-canton/test/unit/builder/settlementAuthorization/settlementAuthorizationBuilder.ts index 546f1aad2c3..2a179d0b720 100644 --- a/modules/sdk-coin-canton/test/unit/builder/settlementAuthorization/settlementAuthorizationBuilder.ts +++ b/modules/sdk-coin-canton/test/unit/builder/settlementAuthorization/settlementAuthorizationBuilder.ts @@ -39,6 +39,8 @@ describe('Broadridge Settlement Authorization Builder', function () { }); assert.equal(request.broadridge?.standard, 'CIP-56'); assert.equal(request.broadridge?.role, 'client'); + assert.equal(request.broadridge?.client, client); + assert.equal(request.broadridge?.executor, executor); assert.equal(request.broadridge?.entityName, 'StandingDelegationImpl_v1'); }); diff --git a/modules/sdk-coin-canton/test/unit/utils.ts b/modules/sdk-coin-canton/test/unit/utils.ts index 68dae077428..a8c22f8047d 100644 --- a/modules/sdk-coin-canton/test/unit/utils.ts +++ b/modules/sdk-coin-canton/test/unit/utils.ts @@ -9,6 +9,7 @@ import { CANTON_ADDRESSES, CANTON_BLOCK_HEIGHT, CantonAllocationAllocatePrepareResponse, + CantonStandingDelegationPrepareResponse, CantonAllocationAllocateNativePrepareResponse, CantonAllocationAllocateNativeV2ReceiveOnlyPreparedResponse, CantonAllocationAllocateTokenV2ReceiveOnlyPreparedResponse, @@ -236,6 +237,32 @@ describe('Canton Util', function () { assert.equal(parsedData.amount, '5000000000'); assert.equal(parsedData.token, 'tcanton:tt'); }); + + it('should parse the Broadridge standing delegation prepared transaction', () => { + const parsedData = utils.parseRawCantonTransactionData( + CantonStandingDelegationPrepareResponse.preparedTransaction, + TransactionType.CantonCommand + ); + should.exist(parsedData.broadridgeSettlementAuthorizationData); + assert.equal(parsedData.sender, ''); + assert.equal(parsedData.receiver, ''); + assert.equal(parsedData.amount, '0'); + assert.equal( + parsedData.broadridgeSettlementAuthorizationData?.descriptor.entityName, + 'StandingDelegationImpl_v1' + ); + assert.equal( + parsedData.broadridgeSettlementAuthorizationData?.client, + 'test-delegation::122092e7d33ac10c0f3d55976342f37555df05da5b742956d56a62ae2367769079d2' + ); + assert.equal( + parsedData.broadridgeSettlementAuthorizationData?.executor, + 'btgo-operator::1220eb693ade486ff8a112f999e6392fc0427bc14da42ee20e51998575a53efef0cd' + ); + assert.deepStrictEqual(parsedData.broadridgeSettlementAuthorizationData?.descriptor.actors, [ + 'test-delegation::122092e7d33ac10c0f3d55976342f37555df05da5b742956d56a62ae2367769079d2', + ]); + }); }); describe('Wallet init transaction', function () {