feat(connect): add useParties() for every party the wallet holds - #66
feat(connect): add useParties() for every party the wallet holds#66fernandomg wants to merge 3 commits into
Conversation
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
There was a problem hiding this comment.
Pull request overview
This PR adds a useParties() hook to canton-connect, exposing every usable party the connected wallet holds (primary first), updating on accountsChanged. It is the party read-model slice of issue #51, cut from a larger stack whose selection half lands in #63. The account-mapping helper gains a toParties function that filters on the wallet's status (only allocated parties are offered; disabled is deliberately never filtered on), and the provider now tracks a parties array alongside party, keeping party === parties[0] through one shared applyAccounts mapping. The test doubles (fake wallet, mock adapter) accept a per-account status so the filter can be driven.
Changes:
- New
useParties()hook +UsePartiesResult, exported from the barrel with JSDoc;selectPrimaryAccount/toPartystay internal. toPartiescentralizes account→Partymapping (status filter + primary-first ordering); provider wires it into restore/connect/disconnect via a singleapplyAccountscallback and addspartiesto the context value.- Fake wallet and mock adapter accept a per-account
status, defaulting toallocatedin the mock.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
canton-connect/src/walletAccount.ts |
Adds toParties (status filter via isUsable, primary-first order) and status/disabled fields on the raw account shape. |
canton-connect/src/walletAccount.test.ts |
Covers toParties filtering, ordering, per-account networkId fallback, and empty cases. |
canton-connect/src/hooks/useParties.ts |
New hook returning { parties } from context, with JSDoc. |
canton-connect/src/CantonConnectProvider.tsx |
Adds parties state and applyAccounts, maintaining party === parties[0] across all lifecycle paths. |
canton-connect/src/CantonConnectProvider.test.tsx |
Adds push/read/disconnect parity tests for useParties(). |
canton-connect/src/testing/fakeWallet.ts |
Adds optional per-account status. |
canton-connect/src/mock/mockAdapter.ts |
Adds per-account status (defaults to allocated); renames MOCK_WALLET_STATUS→DEFAULT_WALLET_STATUS. |
canton-connect/src/mock/mockAdapter.test.ts |
Verifies status pass-through and the allocated default. |
canton-connect/src/index.ts |
Exports useParties and UsePartiesResult. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
ab056c3 to
9cec1a0
Compare
9cec1a0 to
b33e9ec
Compare
The SDK returns one record per account, each carrying its own required status. Both doubles now model that per-account rather than wallet-wide: the fake wallet passes a declared status straight through, and the mock defaults to allocated when an account declares none.
- only `allocated` parties are offered: `initialized` never finished signing, `removed` is gone - an account reporting no status is kept, so older wallets and test doubles still work - `disabled` is never filtered on — such a party signs through the participant and still works - the primary account leads; the rest keep the wallet's order
- provider tracks parties beside party; one applyAccounts callback maps both - initial listAccounts read and the accountsChanged push share that mapping - parties empties wherever party goes undefined: lock, disconnect, dead probe - party is always parties[0]; a test states the invariant
b33e9ec to
64084f5
Compare
|
|
||
| /** | ||
| * Every party the connected wallet holds that can actually act, primary | ||
| * first. Empty while disconnected and while the wallet is locked; parties the |
There was a problem hiding this comment.
Promises "Empty while disconnected and while the wallet is locked;", but statusChanged handler at CantonConnectProvider.tsx sets only isLocked and never clears parties.
| (accounts: AccountsChangedEvent): void => { | ||
| const mapped = toParties(accounts, networkId) | ||
| setParties(mapped) | ||
| setParty(mapped[0]) |
There was a problem hiding this comment.
(CC feedback)
connected + unlocked + zero parties is now reachable, undocumented, untested
The status filter at walletAccount.ts:30-31 can empty the list for a live wallet. Previously selectPrimaryAccount fell back to the first entry regardless of status (walletAccount.ts:18-19), so party was always defined once connected.
Verified: a wallet holding one initialized account connects successfully and yields { parties: [], party: undefined, status: 'connected', isConnected: true }.
isConnected no longer implies party. useParty.ts:11 still says party is undefined only "until connect() succeeds", and no test covers this state. A consumer doing if (isConnected) party.partyId now throws.
| // Only an allocated party exists on the ledger; a missing status is trusted (older wallets). | ||
| const isUsable = (account: RawWalletAccount): boolean => | ||
| account.status === undefined || account.status === 'allocated' |
There was a problem hiding this comment.
(CC feedback)
the initialized exclusion rests on an undocumented inference
walletAccount.ts:29 asserts "Only an allocated party exists on the ledger". The SDK documents WalletStatus as nothing more than "The status of the wallet" (@canton-network/dapp-sdk/dist/dapp-api/rpc-gen/typings.d.ts:322-327). Nothing in the SDK, this repo, or wallet-service (which returns [] from listAccounts) corroborates the lifecycle reading.
The disabled half of the PR's reasoning does check out: the SDK explicitly documents it as "no signing provider matches the party's namespace ... Disabled wallets use participant as the default signing provider" (typings.d.ts:364-369), so never filtering on it is correct.
The risk is one-directional. If a real wallet reports initialized for a party the user can act as, parties disappear with no signal, and per the test plan no live-wallet check happens until #63. A console.warn on a dropped account, or verifying against one real wallet before the stack merges, would close it.
gabitoesmiapodo
left a comment
There was a problem hiding this comment.
Left a few comments, all low priority.
Summary
Part of #51; the issue closes at the top of this stack (#63).
#51's two halves (the party read model and the wallet list) plus the #57 lifecycle fixes grew into
one 12-commit draft. Split so each concern reviews on its own: this slice is the party read model,
cut from the same commits. Merge order is #47, #48, this, then the rest of the stack.
Changes
useParties(): every usable party the wallet holds, primary first, updating onaccountsChanged.partyis alwaysparties[0].status: onlyallocatedparties are offered.initializedmeans the party is not on the ledger yet, so it cannot act.disabledis neverfiltered on; that flag only records that no signing provider matched the namespace, and such a
party still signs through the participant.
status, so tests can drive the filter.Acceptance criteria
From #51, the criteria this slice owns:
useParties()exists, returns every usable account asParty, and updates onaccountsChangedselectPrimaryAccountandtoPartystay internalThe remaining #51 criteria (wallet entries readable from the public surface, #50's picker buildable
against them) are the selection half and land with #63, as does the
usePartiesREADME hook-tablerow (task 11 of the plan, one doc pass for the whole stack).
Test plan
Automated tests
pnpm -C canton-connect test: 38 to 50 tests. New coverage: the mapping filter cases inwalletAccount.test.ts, push/read parity foruseParties()inCantonConnectProvider.test.tsx,and the doubles'
statussupport inmockAdapter.test.ts. Verified at this commit: 50 passed,tscandbiome checkclean.Manual verification
No manual steps required; the harness walkthrough happens at the stack top (#63, task 12).
Breaking changes
None.
Checklist
Screenshots
None.