Skip to content

feat: multi sync example - #1622

Open
Viktor-Kalashnykov-da wants to merge 40 commits into
mainfrom
wiktor/multisync-example
Open

feat: multi sync example#1622
Viktor-Kalashnykov-da wants to merge 40 commits into
mainfrom
wiktor/multisync-example

Conversation

@Viktor-Kalashnykov-da

@Viktor-Kalashnykov-da Viktor-Kalashnykov-da commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

Multi-Synchronizer DvP Example - On ledger API - Part 1

Showcases automatic reassignment of Token from private synchronizer to global one, used on a realistic trade scenario with use of a custom Token.

New test:
https://github.com/canton-network/wallet/pull/1622/changes#diff-37db720ea457076fe6d04f6938d19c44e5dde3d7e1a5815953ff6b83199a1052

Design principles:

  1. !!! We remove handling of synchronizers inside wallet-sdk.
    Client code should be responsible of selecting synchronizerId in multi-sync scenarios.
    If not provided - synchronizer choice is left for canton participant logic.
    Existing tests are updated (refactor(wallet-sdk): remove default synchronizer auto-selection #1740).

  2. We try to show "realistic scenario" - we use multiple parties (Alice, Bob, TokenAdmin, TradingApp) we also
    distribute dars to selected synchronizers (private dars to private). This contributes to relative complexity of the test code

image

source:
https://docs.google.com/presentation/d/1q6LpHi-wC_MO_mzf7wp5D-15j4lNeKjCMW5xmBggaTY

  1. Example works with Token Standard V1
    We have experimented with token standard V2 -> but as V2 is not yet merged to splice use of V2 means even more code

  2. All tests run on multi-sync

This is a first PR in a series
Showcases only on-ledger part - and ensures code works.
There are 2 follow up PRs (wip)

Technical limitations:
In this PR we introduce separate tests for multi-sync (otherwise regular tests are flaky on multi-sync) - that split will be removed in a separate PR (above)

New example script:
docs/wallet-integration-guide/examples/scripts/15-multi-sync-trade.ts

Notes

  1. explicit reassignment
    we experimented with automatic reassignment of contracts - and it basically worked BUT.

It worked as long as Bob is owner of TokenRules contract which seems unrealistic.
We introduced TokenAdmin as additional party that is issuer of Token on app-synchronizer (private one).
But this in fact forces us to use explicit reassignment.

  1. TestToken on global synchronizer. The original intention seemed to be that TestToken dar is only vetted on private synchronizer.
    But since the settlement actually happens on global - TestToken related models must be also on global synchronizer

@Viktor-Kalashnykov-da
Viktor-Kalashnykov-da requested review from a team as code owners April 14, 2026 19:09
@Viktor-Kalashnykov-da
Viktor-Kalashnykov-da marked this pull request as draft April 14, 2026 19:09
Comment thread docs/wallet-integration-guide/examples/scripts/multi-sync/15-multi-sync-trade.ts Outdated
Comment thread docs/wallet-integration-guide/examples/scripts/multi-sync/15-multi-sync-trade.ts Outdated
Comment thread docs/wallet-integration-guide/examples/scripts/15-multi-sync-trade.ts Outdated
Comment thread sdk/wallet-sdk/src/wallet/sdk.ts Fixed
@Viktor-Kalashnykov-da Viktor-Kalashnykov-da changed the title Multi-Sync Example feat(multisync-example): Multi-Sync Example Apr 17, 2026
Comment thread core/token-standard-service/src/token-standard-service.ts Outdated
Comment thread docs/wallet-integration-guide/examples/scripts/utils/synchronizer.ts Outdated
Comment thread docs/wallet-integration-guide/examples/scripts/utils/synchronizer.ts Outdated
Comment thread docs/wallet-integration-guide/examples/scripts/multi-sync/15-multi-sync-trade.ts Outdated
Comment thread docs/wallet-integration-guide/examples/scripts/15-multi-sync-trade.ts Outdated
Comment thread docs/wallet-integration-guide/examples/scripts/multi-sync/15-multi-sync-trade.ts Outdated
Comment thread docs/wallet-integration-guide/examples/scripts/multi-sync/15-multi-sync-trade.ts Outdated
Comment thread docs/wallet-integration-guide/examples/scripts/utils/synchronizer.ts Outdated
Comment thread scripts/src/start-localnet.ts Outdated
Comment thread sdk/wallet-sdk/src/wallet/namespace/contract/client.ts Outdated
Comment thread sdk/wallet-sdk/src/wallet/namespace/ledger/dar/client.ts Outdated
Comment thread .gitignore Outdated

@jarekr-da jarekr-da left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made first round or review.
Generally that is a scenario we want.
I posted questions and problems to recheck / fix.

@Viktor-Kalashnykov-da Viktor-Kalashnykov-da changed the title feat(multisync-example): Multi-Sync Example feat: multi sync example Apr 21, 2026
Comment thread core/wallet-test-utils/src/wallet-gateway.ts Outdated
Comment thread .vscode/settings.json Outdated
Comment thread api-specs/ledger-api/3.4.12/openapi.yaml Outdated
Comment thread core/ledger-client/src/ledger-client.ts Outdated
jarekr-da and others added 13 commits August 28, 2026 09:37
Signed-off-by: jarekr-da <jaroslaw.ratajski@digitalasset.com>
Signed-off-by: jarekr-da <jaroslaw.ratajski@digitalasset.com>
Signed-off-by: jarekr-da <jaroslaw.ratajski@digitalasset.com>
Signed-off-by: jarekr-da <jaroslaw.ratajski@digitalasset.com>
Signed-off-by: jarekr-da <jaroslaw.ratajski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: jarekr-da <jaroslaw.ratajski@digitalasset.com>
Co-authored-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
mjuchli-da
mjuchli-da previously approved these changes Aug 31, 2026
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: jarekr-da <jaroslaw.ratajski@digitalasset.com>
…ge manager

Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
// /app/app-synchronizer.sc by scripts/src/start-localnet.ts so the change
// survives a `yarn script:fetch:localnet` (the .localnet bundle is gitignored).
//
// TODO(#2283): this is a temporary workaround until we have a proper multi-synchronizer bootstrap script in the Canton repo

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self comment: we will be able to remove this file after switching to splice >= 0.7.4

providerVetted.nonEmpty && providerVetted.head.item.packages.nonEmpty
val multiSyncFeatureFlag =
Seq(SynchronizerTrustCertificate.ParticipantTopologyFeatureFlag.EnableMultiSynchronizer)
multiSyncParticipants.foreach { participant =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should await for those operations to take effect with utils.retry_until_true. Probably won't be a problem as there is plenty of time between this script finishing and multi sync e2e test starting in CI.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jarekr-da what's your take on this?

Comment thread .github/workflows/build.yml
Comment thread core/ledger-client/src/ledger-client.ts
Comment thread docs/wallet-integration-guide/examples/scripts/17-multi-sync/README.md Outdated
Comment thread docs/wallet-integration-guide/examples/scripts/17-multi-sync/_setup.ts Outdated
// When a specific synchronizerId is provided, check whether the party
// is already registered on that synchronizer (not just on the participant).
if (
await this.checkIfPartyExists(

@pawelstepien-da pawelstepien-da Sep 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a problem, that it exits early if party exists on createPartyOptions?.synchronizerId, if also createPartyOptions?.additionalSynchronizerIds were passed? A couple of lines lower it loops through additionalSynchronizerIds and registers the party there.

@mateuszpiatkowski-da mateuszpiatkowski-da Sep 2, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a problem but I'd like a confirmation from someone else too.

CC @rukmini-basu-da @jarekr-da

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current logic is mostly result of code evolution: we have not realized about that problem.

@meiersi-da meiersi-da left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jarekr-da @mjuchli-da @mateuszpiatkowski-da : I've done another high-level review. As you can see from my comments I'm still a bit worried about missing a problem due to

  1. not using a one-participant-per-party topology
  2. not relying on automatic reassignments, which is what ultimately want to promote.

How do you propose to address these two concerns?

Comment thread docs/wallet-integration-guide/examples/scripts/17-multi-sync/README.md Outdated
)
if (!testTokenAllocation) throw new Error('TestToken allocation not found')
// ── Step 10b: Reassign Bob's TestToken allocation app-synchronizer → global ──
// TODO #2097 remove after bugfix in canton

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jarekr-da : I understand that fix to allow auto assignment has landed in Canton already hasn't it?

Comment thread docs/wallet-integration-guide/examples/scripts/utils/acs-logger.ts

// TokenAdmin offers the freshly-minted TestToken to Bob. The transfer factory
// and choice context come from the registry's transfer-instruction-v1 API
// (the TestToken registry is also resolved via the metadata-v1 API).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jarekr-da or @mateuszpiatkowski-da : what's the status of this?

Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
@mateuszpiatkowski-da

Copy link
Copy Markdown
Contributor

From my side: some of the minor issues listed here are already fixed, the rest of them is either implemented here: #2383 or moved as a follow-up task: #2391. @jarekr-da will also contribute by creating a PR to this branch implementing some stuff from his side.

Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>

@jarekr-da jarekr-da left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

responded to changes -
PR with review issues
#2387

Comment thread docs/wallet-integration-guide/examples/scripts/17-multi-sync/index.ts Outdated
Comment thread core/ledger-client/src/ledger-client.ts Outdated
Comment thread docs/wallet-integration-guide/examples/scripts/17-multi-sync/_setup.ts Outdated

// TokenAdmin offers the freshly-minted TestToken to Bob. The transfer factory
// and choice context come from the registry's transfer-instruction-v1 API
// (the TestToken registry is also resolved via the metadata-v1 API).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@meiersi-da I have not understood the original issue/comment


// The settlement is submitted by TradingApp (sv), so Alice's resulting Token
// holding propagates to her participant (app-user) asynchronously. Poll app-user until it
// becomes visible instead of reading once (cross-participant read-after-write).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With multiple synchronizers - events might be observer with a delay and sometime out of order (order is preserved for one synchronizer but not between). But I will just remove this comment.

},
}
)
} catch (e: unknown) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done ( this is not pretentious - thanks)

originalError: e,
})
}
throw e

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

>

export interface ReassignParams {
submitter: string

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do needed claude in this :-) - done

// When a specific synchronizerId is provided, check whether the party
// is already registered on that synchronizer (not just on the participant).
if (
await this.checkIfPartyExists(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current logic is mostly result of code evolution: we have not realized about that problem.

return
}

const topology =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed - done

Signed-off-by: jarekr-da <jaroslaw.ratajski@digitalasset.com>
Signed-off-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Co-authored-by: Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants