Page MenuHomePhabricator

[ecash-wallet] Implement MultisigWallet with ECDSA multisig support
ClosedPublic

Authored by bytesofman on Apr 2 2026, 17:57.

Details

Summary

This feature allows users to execute most wallet actions, including token actions, in a multisig wallet. For now, ECDSA-only, which is easier to implement. We also do not support HD or chained actions.

The first anticipated use case is multisig token actions.

We follow electrum-abc convention of lexicographic ordering of pubkeys in ecash-wallet. So, users creating multisig wallets with the same pks will always get the same p2sh address. ecash-lib will accept any ordering.

Compared to non-multisig wallets,

  • Multisig wallets do not auto-update the utxo set on build, since the utxo is not expected to be used until everyone signs
  • Multisig wallets do not attempt to retry on utxo set failures, since we cannot rebuild the tx without all parties signing again
Test Plan

npm test

Diff Detail

Repository
rABC Bitcoin ABC
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

match electrum-abc pub key sorting

more docs, validate we create with only a single sk

add a test for p2pkh to p2sh multisig token mgmt migration

bytesofman published this revision for review.Apr 2 2026, 23:45
Fabien requested changes to this revision.Apr 3 2026, 08:14
Fabien added a subscriber: Fabien.
Fabien added inline comments.
modules/ecash-wallet/src/multisigWallet.ts
66 ↗(On Diff #58888)

or just return comparePubkeysLex == 0 so you don't have to maintain the logic twice

181 ↗(On Diff #58888)

Isn't this part of WalletBase ? If not it might be worth moving it to some common file anyway and avoid code duplication (wallets may pass the utxo set so you don't have to make it a class method).

Same goes for the below functions.

224 ↗(On Diff #58888)

What is the use case for the "fallback" first cosigner with sk ? Just not having to pass your own pubkey as a convenience ?

344 ↗(On Diff #58888)

I wonder if this should throw instead of silently returning the same tx. No change required, just an API question at this point: attempting to sign again a signed multisig and getting no error might be confusing.

This revision now requires changes to proceed.Apr 3 2026, 08:14
bytesofman added inline comments.
modules/ecash-wallet/src/multisigWallet.ts
181 ↗(On Diff #58888)

Forgot why it worked this way -- it's because WatchOnlyWallet did not track tip height. In practice tho, I think it's more valuable to keep these methods "the same" across the various classes than to custom config the watch only wallet to make one fewer API call. Even though watch only wallet does not really "need" to know what utxos are spendable based on coinbase maturity, the info could still be useful there, and this kind of "saving" is not worth complicating the codebase across our now three classes.

Updated

224 ↗(On Diff #58888)

artifact from first pass at implementing, when wallet did not control for being created with multiple sks in cosigners

updated

344 ↗(On Diff #58888)

Yes I think that is better. Also realized constructor was supporting creation with no secret keys, which I think overcomplicates the API. Updated so constructor requires exactly 1 sk.

bytesofman marked 3 inline comments as done.

require exactly 1 sk, mov;e shared methods to wallet base, throw if attempt to sign already signed

This revision is now accepted and ready to land.Apr 3 2026, 15:38