Skip to content

feat: migrate coordinator frontend from REST API to PSM SDK#24

Merged
WiktorStarczewski merged 16 commits intomainfrom
wiktor-psm
Feb 12, 2026
Merged

feat: migrate coordinator frontend from REST API to PSM SDK#24
WiktorStarczewski merged 16 commits intomainfrom
wiktor-psm

Conversation

@WiktorStarczewski
Copy link
Collaborator

Summary

Migrates the coordinator frontend from the coordinator REST API layer to the PSM (Private State Manager) SDK, replacing all server-mediated multisig operations with direct client-side interactions via @openzeppelin/miden-multisig-client.

  • Replace coordinator API with MultisigContext — single context manages WebClient, MultisigClient, signer keys,
    proposals, wallet connections, and all PSM operations
  • Add multi-wallet support — local keys, Para wallet, and Miden Wallet can all be used as signing sources, switchable
    from the global header
  • Persist signer keys across reloads — Falcon/ECDSA keys stored in a dedicated IndexedDB (MultisigSignerKeys) that
    survives clearMidenDatabase(), with commitment normalization to prevent PSM 401 rejections
  • Simplify Redux — removed transactionSlice, signatureSlice, walletStatsSlice; only wallet form state remains in Redux
  • Fix proposal status/type handling — proposal.status is an object { type: 'pending' | 'ready' | 'finalized' }, not a
    string; proposal type lives at proposal.metadata.proposalType, not proposal.type

Changes

Architecture

  • New MultisigContext as the central state manager replacing coordinator services
  • New AppHeader component with wallet source selector, signer keys popover, and PSM status/editor — rendered globally via Providers
  • New lib modules: initClient.ts (WebClient + key persistence), multisigApi.ts (MultisigClient wrapper), helpers.ts,
    errors.ts, procedures.ts
  • New hooks: useParaSession (Para wallet), useMidenWallet (Miden Wallet adapter)

Dependency updates

  • @demox-labs/miden-sdk v0.12 → @miden-sdk/miden-sdk v0.13
  • Added @openzeppelin/miden-multisig-client, @openzeppelin/psm-client
  • Added @getpara/react-sdk-lite, @tanstack/react-query

Deleted

  • Coordinator services (walletApi.ts, transactionApi.ts, signatureApi.ts)
  • Old contexts (MidenClientContext)
  • Old hooks (useMidenSdk, useWalletData, useFungibleAssets)
  • Unused components (ConnectWalletModal, WalletInfo, DynamicWalletButton, TransferBox, WalletConnection,
    WalletTransaction)
  • Old type files (transaction.ts, signature.ts, wallet.ts, notes.ts, hooks.ts)
  • Redux slices (transactionSlice, signatureSlice, walletStatsSlice)

Bug fixes

  • Prevent useMultisig crash on page reload (Providers mount guard)
  • Auto-load saved account from localStorage after WebClient init
  • Normalize all commitments to 0x{lowercase_hex} to match PSM server format
  • Guard against undefined proposal.type in transaction lists
  • Use proposal.status.type (object) instead of proposal.status (string comparison) for filtering pending/executed
    proposals
  • Remove redundant address fields from create account flow (commitment = address)

Test plan

  • Create a new multisig account with 2 signers across separate browser sessions
  • Reload page — keys persist, account auto-loads without PSM 401
  • Claim a note → proposal appears in recent transactions as PENDING
  • Open "Approve Queued Transfers" → proposal appears and can be signed
  • Sign from second signer tab → proposal reaches threshold and can be executed
  • Execute proposal → status changes to EXECUTED/finalized
  • Switch wallet source (local/Para/Miden Wallet) from header
  • Verify PSM status indicator and endpoint editing works

Copy link
Collaborator

@Dominik1999 Dominik1999 left a comment

Choose a reason for hiding this comment

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

This PR is a bit too big to review. We can merge it and I will test the features.

Switch from @demox-labs/miden-sdk v0.12 to @miden-sdk/miden-sdk v0.13.
Add @openzeppelin/miden-multisig-client, psm-client, Para wallet
SDKs, and @tanstack/react-query. Add PSM config, WASM copy paths,
and Para module stubs in next.config.mjs.
Port initClient, multisigApi, helpers, errors, and procedures from
the PSM example app. Add wallet type definitions (WalletSource,
ExternalWalletState), PSM type definitions (SignerInfo), and hooks
for Para wallet session and Miden Wallet adapter integration.
Create MultisigContext as the central state manager replacing the
coordinator API layer. Manages WebClient, MultisigClient, signer
keys, proposals, wallet source selection, and all PSM operations.
Update Providers with ParaProvider, QueryClientProvider, and
MultisigProvider tree.
Replace coordinator REST API calls with MultisigClient SDK operations
across all dashboard pages, login flows, and transaction interactions.
Use proposals from context instead of coordinator transactions.
Switch account ID format from bech32 to hex.
Delete coordinator services (walletApi, transactionApi, signatureApi),
old contexts (MidenClientContext), old hooks (useMidenSdk, useWalletData,
useFungibleAssets), unused components (ConnectWalletModal, WalletInfo,
DynamicWalletButton, etc.), and old type files. Simplify Redux store
to only wallet form slice. Remove transactionSlice, signatureSlice,
and walletStatsSlice.
Add AppHeader component showing wallet source selector, signer keys
popover, and PSM endpoint status/editor. Rendered globally via
Providers so it appears on login and dashboard pages. Auto-switches
wallet source when Para or Miden Wallet connects.
- Signer 1 is now read-only and shows the active wallet's commitment
- Other signers (2+) are added manually via commitment input
- Persist account ID in cookie after create/load for middleware auth
- Review step highlights Signer 1 with wallet source label
Return null from Providers before mount instead of rendering children
without MultisigProvider, which caused a runtime error when dashboard
components called useMultisig() during initial hydration.
- Auto-load account from localStorage after client initialization so
  dashboard shows correct signers/threshold on refresh
- Call syncAll() after account creation to populate detectedConfig
Persist local Falcon/ECDSA keys in a separate IndexedDB (MultisigSignerKeys)
so they survive page reloads without being cleared by clearMidenDatabase().

Normalize all signer commitments to 0x-prefixed lowercase hex to match the
format the PSM server derives during signature verification, preventing 401
rejections from format mismatches.
@WiktorStarczewski WiktorStarczewski merged commit f1ec032 into main Feb 12, 2026
11 checks passed
@WiktorStarczewski WiktorStarczewski deleted the wiktor-psm branch February 12, 2026 14:02
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.

2 participants