Skip to content

feat: add starforge multisig ceremony command family - #65

Merged
Nanle-code merged 1 commit into
StarsForges:masterfrom
Emmy123222:feat/multisig-ceremony
Jul 30, 2026
Merged

feat: add starforge multisig ceremony command family#65
Nanle-code merged 1 commit into
StarsForges:masterfrom
Emmy123222:feat/multisig-ceremony

Conversation

@Emmy123222

@Emmy123222 Emmy123222 commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a starforge multisig ceremony command family that orchestrates the
full lifecycle of an M-of-N Stellar transaction signing session as a single
portable, self-describing file — the workflow that matters most for treasury
and protocol-governance safety, where signers operate on separate
(potentially air-gapped) machines and no single machine should ever hold
enough signing authority to submit alone.

Today, coordinating this requires signers to manually copy XDR blobs around
and hope they combine them correctly. This PR replaces that with four
subcommands built on the existing utils/multisig.rs and
utils/hardware_wallet.rs primitives:

  • starforge multisig ceremony start — builds an unsigned transaction
    envelope plus a manifest (required signers, threshold, expiry) into one
    .ceremony file.
  • starforge multisig ceremony sign — adds a signer's signature (local
    wallet or --hardware ledger|trezor), no network access required.
  • starforge multisig ceremony status — reports collected vs. required
    signatures, outstanding signers, and time remaining before expiry.
  • starforge multisig ceremony submit — verifies the threshold is met
    and submits, refusing to do so if signatures are insufficient, from
    unauthorized signers, or if the file has been tampered with.

Ceremony files are plain JSON (base64 XDR embedded as a string) — diffable
and git-friendly, so they can be passed via USB drive, QR code, or a shared
repo/PR for auditability.

What's included

  • src/utils/ceremony.rs (new) — the ceremony file format (versioned),
    manifest + transaction-body integrity hashing, and signature
    collection/merge logic, built on top of utils/multisig.rs's existing XDR
    encode/decode/sign primitives (several of which were changed from private
    to pub(crate) for reuse rather than duplicated).
  • src/commands/multisig_ceremony.rs (new) — CLI wiring for the four
    subcommands, reusing the existing hardware wallet signing path for
    --hardware rather than reimplementing device communication.
  • Tamper detection — every sign/status/submit call re-derives two
    SHA-256 hashes from the current file contents (one over the unsigned
    transaction body, one over the manifest's signer set/threshold/expiry) and
    compares them to the values recorded at ceremony start. Any edit to
    either after the ceremony began is rejected with a clear error, at the next
    sign, status, or submit.
  • docs/multisig-ceremony.md (new) + a new README section — a full
    walkthrough of a 3-of-4 treasury payout across multiple machines, including
    the air-gapped/USB-transfer use case and the tamper-detection model.
  • Tests (11 new, all in src/utils/ceremony.rs) — threshold math edge
    cases (exactly at threshold, below threshold, duplicate signer), tamper
    detection (transaction body and manifest), expiry handling, round-trip
    serialization, and independent multi-machine sign invocations against a
    shared on-disk file with no shared process state.

Design notes

  • --op accepts inline JSON or a path to a JSON file describing the
    operation (currently payment, reusing utils/tx_batch::BatchOperation
    and its existing validation).
  • Expiry is implemented via the transaction's standard time bounds
    (Preconditions::Time), set at ceremony start via
    --expires-in-minutes, so it doesn't require a live ledger height lookup
    to check later.
  • submit cross-checks the signature log against the actual signature count
    in the raw XDR envelope, so a hand-edited signature_log claiming a
    threshold isn't enough on its own — the envelope has to actually carry that
    many signatures.
  • These are integrity/authorization checks, not a replacement for each
    signer reviewing the transaction contents before approving.

Test plan

  • cargo build --bin starforge — clean build
  • cargo test --lib — 233 passed (0 failed), including the 11 new
    utils::ceremony tests and the existing utils::multisig suite
    (unaffected by the pub(crate) visibility changes)
  • cargo clippy --lib — no new warnings introduced
  • Manual end-to-end run against real Stellar testnet Horizon:
    • ceremony start with a 2-of-3 threshold
    • three independent ceremony sign invocations (separate process
      invocations, no shared state) against the same file
    • ceremony status showing collected/outstanding signers and expiry
      countdown at each step
    • ceremony submit with only 1 of 2 required signatures → rejected with
      "Not enough signatures to submit: 1 of 3 ... (threshold 2)"
    • duplicate signer re-sign → "had already signed this ceremony; no change
      made", signature count unaffected
    • hand-edited (tampered) manifest threshold → rejected at status,
      sign, and submit with "Ceremony manifest integrity check failed"
    • submit once threshold met → reached real Horizon submission (rejected
      only because the test source account's real key wasn't held locally,
      confirming the full pipeline runs end-to-end up to network submission)

Closes #59

Adds an orchestrated M-of-N signing workflow (start/sign/status/submit)
for treasury and governance transactions, where signers can operate on
separate, potentially air-gapped machines with no shared process state.

- src/utils/ceremony.rs: portable ceremony file format (manifest + tx
  envelope + signature log), manifest/tx-body integrity hashing, and
  signature collection built on the existing multisig.rs primitives.
- src/commands/multisig_ceremony.rs: CLI wiring for
  `starforge multisig ceremony start|sign|status|submit`, reusing the
  existing hardware wallet signing path for --hardware.
- Tamper detection rejects a ceremony file whose manifest or unsigned
  transaction body was altered after the ceremony started.
- docs/multisig-ceremony.md: full multi-machine/air-gapped walkthrough.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Nanle-code
Nanle-code merged commit 636fa86 into StarsForges:master Jul 30, 2026
2 of 5 checks passed
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.

Offline Multisig Signing Ceremony Workflow for Air-Gapped and Multi-Party Transaction Approval (starforge multisig ceremony)

2 participants