Skip to content

TS client: no offline proposal creation — createSwitchGuardianProposal pushes to the current GUARDIAN before caching anything (Rust has create_proposal_offline) #433

Description

@haseebrabbani

Problem

The offline switch path exists so an account can leave an unreachable operator: executeProposal for switch_guardian uses the locally cached tx summary, skips the GUARDIAN ack, treats the old-operator push as best-effort, and registers on the new operator from local state. The Rust client exposes the full trio for this (create_proposal_offline / sign_imported_proposal / execute_imported_proposal, crates/miden-multisig-client/src/client/offline.rs), documented as "Only SwitchGuardian transactions can be executed fully offline."

The TS package has import/sign/execute (importProposal, signProposalOffline) but no creation counterpart. createSwitchGuardianProposal funnels into createProposal, which calls pushDeltaProposal against the account's current GUARDIAN before caching the proposal locally (packages/miden-multisig-client/src/multisig.ts). Against a dead operator the call throws and the locally built summary/metadata are lost — so the one proposal type designed to work without the current operator cannot be created without it.

A TS consumer can work around this by hand-assembling the ExportedProposal JSON for importProposal from the exported primitives (buildUpdateGuardianTransactionRequest, executeForSummary, chainAnchorToBase64), but the commitment has to be derived via the SDK (TransactionSummary.toCommitment()) because computeCommitmentFromTxSummary is not exported. This asymmetry is a direct contributor to 0xMiden/wallet#782, where the wallet routed the switch through the outgoing operator's HTTP API and an account got stuck on a network-dead operator.

Proposal

  • Add createSwitchGuardianProposalOffline(newGuardianEndpoint, newGuardianPubkey, options) (or a general createProposalOffline gated to switch, mirroring Rust): build the request and summary locally, verify the new endpoint's /pubkey commitment, include the proposer's signature, cache the proposal locally, and return the ExportedProposal — no push to the current operator.
  • Export computeCommitmentFromTxSummary (or document the SDK-based derivation) so hand-rolled flows are at least possible without guesswork.
  • Unit tests mirroring the Rust offline tests: create → sign (second signer) → execute with the current-operator client pointed at an unreachable endpoint.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions