diff --git a/docs/wallet-integration-guide/examples/scripts/06-merge-utxos.ts b/docs/wallet-integration-guide/examples/scripts/06-merge-utxos.ts index 9ca87a591..008d5a70d 100644 --- a/docs/wallet-integration-guide/examples/scripts/06-merge-utxos.ts +++ b/docs/wallet-integration-guide/examples/scripts/06-merge-utxos.ts @@ -19,9 +19,27 @@ const amulet = await sdk.amulet(AMULET_NAMESPACE_CONFIG) const aliceKeys = sdk.keys.generate() +const connectedSyncResponse = await sdk.ledger.state.connectedSynchronizers({}) + +let synchronizerId + +if ( + connectedSyncResponse.connectedSynchronizers && + connectedSyncResponse.connectedSynchronizers.length > 0 +) { + logger.info( + `connected synchronizers: ${connectedSyncResponse.connectedSynchronizers.map((s) => s.synchronizerId).join(', ')}` + ) + synchronizerId = + connectedSyncResponse.connectedSynchronizers[0].synchronizerId +} else { + throw new Error('No connected synchronizers found') +} + const alice = await sdk.party.external .create(aliceKeys.publicKey, { partyHint: 'v1-06-alice', + ...(synchronizerId && { synchronizerId }), }) .sign(aliceKeys.privateKey) .execute() @@ -36,11 +54,14 @@ const tapPromises = tapIndices.map(async () => { '2000000' ) + const synchronizerId = amuletTapDisclosedContracts[0]?.synchronizerId + return sdk.ledger .prepare({ partyId: alice.partyId, commands: amuletTapCommand, disclosedContracts: amuletTapDisclosedContracts, + ...(synchronizerId && { synchronizerId }), }) .sign(aliceKeys.privateKey) .execute({ partyId: alice.partyId }) @@ -59,11 +80,14 @@ const [mergeUtxoCommands, mergedDisclosedContracts] = await token.utxos.merge({ }) const mergePromises = mergeUtxoCommands.map((mergeCommand) => { + const synchronizerId = mergedDisclosedContracts[0]?.synchronizerId + return sdk.ledger .prepare({ partyId: alice.partyId, commands: mergeCommand, disclosedContracts: mergedDisclosedContracts, + ...(synchronizerId && { synchronizerId }), }) .sign(aliceKeys.privateKey) .execute({ partyId: alice.partyId }) diff --git a/scripts/src/start-localnet.ts b/scripts/src/start-localnet.ts index e2b19d97b..e17fab7e6 100644 --- a/scripts/src/start-localnet.ts +++ b/scripts/src/start-localnet.ts @@ -55,8 +55,8 @@ const composeBase = [ 'app-provider', '--profile', 'app-user', - // '--profile', - // 'multi-sync', + '--profile', + 'multi-sync', ] const network = getNetworkArg() diff --git a/sdk/wallet-sdk/src/wallet/namespace/ledger/client.ts b/sdk/wallet-sdk/src/wallet/namespace/ledger/client.ts index 2484bbc36..0d5ee83a7 100644 --- a/sdk/wallet-sdk/src/wallet/namespace/ledger/client.ts +++ b/sdk/wallet-sdk/src/wallet/namespace/ledger/client.ts @@ -13,6 +13,7 @@ import { Dar } from './dar/client.js' import { AcsOptions } from '@canton-network/core-acs-reader' import { InternalPartySubmitterService } from './internal.js' import { PreparedTransactionService } from './hash/index.js' +import { State } from '../state/index.js' type ListACSBody = { filter?: v3_4.components['schemas']['TransactionFilter'] @@ -22,10 +23,12 @@ export class Ledger { public readonly dar: Dar public readonly internal: InternalPartySubmitterService public readonly preparedTransaction: PreparedTransactionService + public readonly state: State constructor(private readonly sdkContext: CommonCtx) { this.dar = new Dar(sdkContext) this.internal = new InternalPartySubmitterService(sdkContext) this.preparedTransaction = new PreparedTransactionService(sdkContext) + this.state = new State(sdkContext) } public async ledgerEnd() { diff --git a/sdk/wallet-sdk/src/wallet/namespace/party/external/signed.ts b/sdk/wallet-sdk/src/wallet/namespace/party/external/signed.ts index 1893cef8c..d77fbe302 100644 --- a/sdk/wallet-sdk/src/wallet/namespace/party/external/signed.ts +++ b/sdk/wallet-sdk/src/wallet/namespace/party/external/signed.ts @@ -144,7 +144,9 @@ export class SignedPartyCreation { } = options const ledgerProvider = defaultLedgerProvider ?? this.ctx.ledgerProvider try { - const synchronizerId = this.ctx.defaultSynchronizerId + const synchronizerId = + this.createPartyOptions?.synchronizerId ?? + this.ctx.defaultSynchronizerId await this.allocate( ledgerProvider, diff --git a/sdk/wallet-sdk/src/wallet/namespace/state/client.ts b/sdk/wallet-sdk/src/wallet/namespace/state/client.ts new file mode 100644 index 000000000..06fb8824c --- /dev/null +++ b/sdk/wallet-sdk/src/wallet/namespace/state/client.ts @@ -0,0 +1,57 @@ +// Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { CommonCtx } from '../../sdk.js' +import { Ops } from '@canton-network/core-provider-ledger' +import { SDKLogger } from '../../logger/index.js' + +export type ConnectedSynchronizersOptions = { + party?: string + participantId?: string + identityProviderId?: string +} + +export class State { + private readonly logger: SDKLogger + + constructor(private readonly ctx: CommonCtx) { + this.logger = ctx.logger.child({ namespace: 'State' }) + } + + /** + * Returns the list of connected synchronizers for the given party / participant. + * + * Calls GET /v2/state/connected-synchronizers with optional query parameters. + * + * @param options - Optional filters: party, participantId, identityProviderId. + */ + public async connectedSynchronizers( + options?: ConnectedSynchronizersOptions + ) { + this.logger.debug({ options }, 'Fetching connected synchronizers') + + const result = + await this.ctx.ledgerProvider.request( + { + method: 'ledgerApi', + params: { + resource: '/v2/state/connected-synchronizers', + requestMethod: 'get', + query: { + ...(options?.party !== undefined && { + party: options.party, + }), + ...(options?.participantId !== undefined && { + participantId: options.participantId, + }), + ...(options?.identityProviderId !== undefined && { + identityProviderId: options.identityProviderId, + }), + }, + }, + } + ) + + return result + } +} diff --git a/sdk/wallet-sdk/src/wallet/namespace/state/index.ts b/sdk/wallet-sdk/src/wallet/namespace/state/index.ts new file mode 100644 index 000000000..ccb7adf4e --- /dev/null +++ b/sdk/wallet-sdk/src/wallet/namespace/state/index.ts @@ -0,0 +1,4 @@ +// Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +export * from './client.js'