From cc4ea7ecfa354645904c254fe0fcd48e51735017 Mon Sep 17 00:00:00 2001 From: Hrishikesh Jain Date: Mon, 22 Jun 2026 14:04:06 +0530 Subject: [PATCH] feat: add canton participant and end invester intents Ticket: CHALO-683 --- modules/sdk-coin-canton/src/canton.ts | 24 ++++++ modules/sdk-core/src/bitgo/utils/mpcUtils.ts | 31 +++++++- .../sdk-core/src/bitgo/utils/tss/baseTypes.ts | 32 ++++++++ modules/sdk-core/src/bitgo/wallet/iWallet.ts | 16 ++++ modules/sdk-core/src/bitgo/wallet/wallet.ts | 77 +++++++++++++++++++ 5 files changed, 177 insertions(+), 3 deletions(-) diff --git a/modules/sdk-coin-canton/src/canton.ts b/modules/sdk-coin-canton/src/canton.ts index 190d89cb4d..e5ca997604 100644 --- a/modules/sdk-coin-canton/src/canton.ts +++ b/modules/sdk-coin-canton/src/canton.ts @@ -465,5 +465,29 @@ export class Canton extends BaseCoin { if (params.cantonCommandParams) { intent.cantonCommandParams = params.cantonCommandParams; } + if (params.endInvestorPartyId) { + intent.endInvestorPartyId = params.endInvestorPartyId; + } + if (params.reason) { + intent.reason = params.reason; + } + if (params.operator) { + intent.operator = params.operator; + } + if (params.provider) { + intent.provider = params.provider; + } + if (params.compliance) { + intent.compliance = params.compliance; + } + if (params.registrar) { + intent.registrar = params.registrar; + } + if (params.clientOnboarder) { + intent.clientOnboarder = params.clientOnboarder; + } + if (params.expirationIso) { + intent.expirationIso = params.expirationIso; + } } } diff --git a/modules/sdk-core/src/bitgo/utils/mpcUtils.ts b/modules/sdk-core/src/bitgo/utils/mpcUtils.ts index 6e8a610326..c89fb3b8b1 100644 --- a/modules/sdk-core/src/bitgo/utils/mpcUtils.ts +++ b/modules/sdk-core/src/bitgo/utils/mpcUtils.ts @@ -139,14 +139,35 @@ export abstract class MpcUtils { } if ( - ['transferAccept', 'transferReject', 'cosignDelegationAccept', 'allocationAllocate'].includes( - params.intentType - ) && + [ + 'transferAccept', + 'transferReject', + 'cosignDelegationAccept', + 'allocationAllocate', + 'cantonEndInvestorOnboardingAccept', + 'cantonEndInvestorOnboardingReject', + ].includes(params.intentType) && baseCoin.getFamily() === 'canton' ) { assert(params.txRequestId, `'txRequestId' is required parameter for ${params.intentType} intent`); } + if (params.intentType === 'cantonEndInvestorOnboardingOffer') { + assert(params.endInvestorPartyId, `'endInvestorPartyId' is required parameter for ${params.intentType} intent`); + } + + if (params.intentType === 'cantonEndInvestorOnboardingReject') { + assert(params.reason, `'reason' is required parameter for ${params.intentType} intent`); + } + + if (params.intentType === 'cantonParticipantOnboardingRequest') { + assert(params.operator, `'operator' is required parameter for ${params.intentType} intent`); + assert(params.provider, `'provider' is required parameter for ${params.intentType} intent`); + assert(params.compliance, `'compliance' is required parameter for ${params.intentType} intent`); + assert(params.registrar, `'registrar' is required parameter for ${params.intentType} intent`); + assert(params.clientOnboarder, `'clientOnboarder' is required parameter for ${params.intentType} intent`); + } + if ( ['transferOfferWithdrawn', 'allocationAllocateWithdrawn'].includes(params.intentType) && baseCoin.getFamily() === 'canton' @@ -194,6 +215,10 @@ export abstract class MpcUtils { 'allocationAllocateWithdrawn', 'bridgeFunds', 'cantonCommand', + 'cantonEndInvestorOnboardingOffer', + 'cantonEndInvestorOnboardingAccept', + 'cantonEndInvestorOnboardingReject', + 'cantonParticipantOnboardingRequest', 'defi-approve', 'defi-deposit', ].includes(params.intentType) diff --git a/modules/sdk-core/src/bitgo/utils/tss/baseTypes.ts b/modules/sdk-core/src/bitgo/utils/tss/baseTypes.ts index d95f29bab6..96c3be43ad 100644 --- a/modules/sdk-core/src/bitgo/utils/tss/baseTypes.ts +++ b/modules/sdk-core/src/bitgo/utils/tss/baseTypes.ts @@ -375,6 +375,22 @@ export interface PrebuildTransactionWithIntentOptions extends IntentOptionsBase cantonCommandParams?: CantonCommandParams; /** DeFi vault intent fields for defi-approve / defi-deposit intents. */ defiParams?: DefiIntentParams; + /** Canton party ID of the end investor to onboard (cantonEndInvestorOnboardingOffer intent). */ + endInvestorPartyId?: string; + /** Reason for rejecting the onboarding offer (cantonEndInvestorOnboardingReject intent). */ + reason?: string; + /** DTCC operator party ID (cantonParticipantOnboardingRequest intent). */ + operator?: string; + /** DTCC provider party ID (cantonParticipantOnboardingRequest intent). */ + provider?: string; + /** DTCC compliance party ID (cantonParticipantOnboardingRequest intent). */ + compliance?: string; + /** DTCC registrar party ID (cantonParticipantOnboardingRequest intent). */ + registrar?: string; + /** DTCC client onboarder party ID (cantonParticipantOnboardingRequest intent). */ + clientOnboarder?: string; + /** Optional ISO 8601 expiration timestamp (cantonParticipantOnboardingRequest intent). */ + expirationIso?: string; } export interface IntentRecipient { address: { @@ -459,6 +475,22 @@ export interface PopulatedIntent extends PopulatedIntentBase, DefiIntentFields { amount?: { value: string; symbol: string } | string; /** Canton-specific params serialized into the cantonCommand intent payload. */ cantonCommandParams?: CantonCommandParams; + /** Canton party ID of the end investor to onboard (cantonEndInvestorOnboardingOffer intent). */ + endInvestorPartyId?: string; + /** Reason for rejecting the onboarding offer (cantonEndInvestorOnboardingReject intent). */ + reason?: string; + /** DTCC operator party ID (cantonParticipantOnboardingRequest intent). */ + operator?: string; + /** DTCC provider party ID (cantonParticipantOnboardingRequest intent). */ + provider?: string; + /** DTCC compliance party ID (cantonParticipantOnboardingRequest intent). */ + compliance?: string; + /** DTCC registrar party ID (cantonParticipantOnboardingRequest intent). */ + registrar?: string; + /** DTCC client onboarder party ID (cantonParticipantOnboardingRequest intent). */ + clientOnboarder?: string; + /** Optional ISO 8601 expiration timestamp (cantonParticipantOnboardingRequest intent). */ + expirationIso?: string; } export type TxRequestState = diff --git a/modules/sdk-core/src/bitgo/wallet/iWallet.ts b/modules/sdk-core/src/bitgo/wallet/iWallet.ts index 2ede4fc716..3681c535f3 100644 --- a/modules/sdk-core/src/bitgo/wallet/iWallet.ts +++ b/modules/sdk-core/src/bitgo/wallet/iWallet.ts @@ -297,6 +297,22 @@ export interface PrebuildTransactionOptions { * Parameters for executing DAML commands on Canton. */ cantonCommandParams?: CantonCommandParams; + /** Canton party ID of the end investor to onboard (cantonEndInvestorOnboardingOffer intent). */ + endInvestorPartyId?: string; + /** Reason for rejecting the onboarding offer (cantonEndInvestorOnboardingReject intent). */ + reason?: string; + /** DTCC operator party ID (cantonParticipantOnboardingRequest intent). */ + operator?: string; + /** DTCC provider party ID (cantonParticipantOnboardingRequest intent). */ + provider?: string; + /** DTCC compliance party ID (cantonParticipantOnboardingRequest intent). */ + compliance?: string; + /** DTCC registrar party ID (cantonParticipantOnboardingRequest intent). */ + registrar?: string; + /** DTCC client onboarder party ID (cantonParticipantOnboardingRequest intent). */ + clientOnboarder?: string; + /** Optional ISO 8601 expiration timestamp (cantonParticipantOnboardingRequest intent). */ + expirationIso?: string; } export interface PrebuildAndSignTransactionOptions extends PrebuildTransactionOptions, WalletSignTransactionOptions { diff --git a/modules/sdk-core/src/bitgo/wallet/wallet.ts b/modules/sdk-core/src/bitgo/wallet/wallet.ts index 8909f33e34..74529337ce 100644 --- a/modules/sdk-core/src/bitgo/wallet/wallet.ts +++ b/modules/sdk-core/src/bitgo/wallet/wallet.ts @@ -4377,6 +4377,83 @@ export class Wallet implements IWallet { ); break; } + case 'cantonEndInvestorOnboardingOffer': { + if (!params.endInvestorPartyId) { + throw new Error('endInvestorPartyId is required for cantonEndInvestorOnboardingOffer intent'); + } + txRequest = await this.tssUtils!.prebuildTxWithIntent( + { + reqId, + intentType: 'cantonEndInvestorOnboardingOffer', + endInvestorPartyId: params.endInvestorPartyId, + comment: params.comment, + sequenceId: params.sequenceId, + }, + apiVersion, + params.preview + ); + break; + } + case 'cantonEndInvestorOnboardingAccept': { + txRequest = await this.tssUtils!.prebuildTxWithIntent( + { + reqId, + intentType: 'cantonEndInvestorOnboardingAccept', + txRequestId: params.txRequestId, + sequenceId: params.txRequestId, + }, + apiVersion, + params.preview + ); + break; + } + case 'cantonEndInvestorOnboardingReject': { + if (!params.reason) { + throw new Error('reason is required for cantonEndInvestorOnboardingReject intent'); + } + txRequest = await this.tssUtils!.prebuildTxWithIntent( + { + reqId, + intentType: 'cantonEndInvestorOnboardingReject', + txRequestId: params.txRequestId, + sequenceId: params.txRequestId, + reason: params.reason, + }, + apiVersion, + params.preview + ); + break; + } + case 'cantonParticipantOnboardingRequest': { + if ( + !params.operator || + !params.provider || + !params.compliance || + !params.registrar || + !params.clientOnboarder + ) { + throw new Error( + 'operator, provider, compliance, registrar, and clientOnboarder are required for cantonParticipantOnboardingRequest intent' + ); + } + txRequest = await this.tssUtils!.prebuildTxWithIntent( + { + reqId, + intentType: 'cantonParticipantOnboardingRequest', + operator: params.operator, + provider: params.provider, + compliance: params.compliance, + registrar: params.registrar, + clientOnboarder: params.clientOnboarder, + expirationIso: params.expirationIso, + comment: params.comment, + sequenceId: params.sequenceId, + }, + apiVersion, + params.preview + ); + break; + } case 'cantonCommand': { if (!params.cantonCommandParams) { throw new Error('cantonCommandParams is required for cantonCommand intent');