Breaking Down the Multisig Improvements Coming to Stacks With SIP-027

Hi, this is Vlad from Asigna. We are building a multisig wallet for Bitcoin, Ordinals, BRC20s, and Stacks. In this post, I’m going to talk about SIP-027 and the work we did to bring updated multisigs to Stacks.

Type
Deep dive
Topic(s)
Ecosystem
Stacks
Published
September 12, 2024
Author(s)
Co-Founder of Asigna
SIP-027 -> multisig improvements
Contents

The Story of Asigna

I hold a masters degree in CS and machine learning, and I’ve worked in crypto as a developer since 2019. In that time, I’ve worked on multiple projects. I’ve developed DeFi protocols, multisig wallets, non-custodial crypto wallets, bridges, staking and LST protocols, and more.

I first began ideating on Asigna back in late 2022 when myself and the founding team discovered Stacks. We pitched in the Ready Layer 2 pitch competition in early 2023 and started to gain partnerships in the ecosystem. Shortly after that, Ordinals and BRC-20 took center stage.

It was clear to us that the emergence of Bitcoin DeFi was on the horizon, and that’s when we decided to make a web-based non-custodial multisig wallet for multiple Bitcoin environments.

Individuals and organizations need secure on-chain multisigs to safely manage funds, deploy contracts, and interact with DeFi apps.

We believed, then and now, that as more institutional adoption comes into Bitcoin DeFi on Stacks, more participants will want to deploy into DeFi apps through the use of a secure non-custodial multisig. We’ve seen that trend play out already in Ethereum, and we believe that the TVL in Bitcoin DeFi will surpass that of Etheruem in the long term.

Whether it’s managing treasuries for teams and funds, securely deploying smart contracts, or actively deploying into DeFi apps, individuals and organizations often need a secure on-chain multisig.

That’s what we’re focused on building at Asigna, and today we have over $350M in TVL across two different multisigs on mainnet (one for Stacks and one for the Bitcoin L1).

The Power of Multisig

Multisig wallets are popular in the world of Web3 because they embody the ethos of decentralization and spread the control of a wallet among multiple different parties. Multisigs require some majority of those parties to sign a transaction before any assets can be transferred or any transaction executed.

Multisig wallets embody the ethos of decentralization.

For example, a multisig with 5 parties could require 3 or 4 of those parties to sign a transaction in order for that transaction to be executed. This ensures that in the event a single private key is compromised, the assets in the multisig still remain safe.

As you can imagine, multisig wallets are well suited for DAOs or organizations that manage significant amounts of crypto assets. Multisigs are also useful for teams that deploy smart contracts, so a protocol cannot be compromised by a single key.

Today, it’s straightforward to spin up a new multisig on Stacks, using any major wallet like Leather, Xverse, or Ledger. After a user connects a wallet to Asigna, they can set the threshold for their new multisig (⅔, ¾, ⅗, etc) and invite the other parties to the wallet. Once all parties accept, a unique public Stacks address is created to be co-managed by the group.

SIP-027: Fixing the Issue of Sequential Signing

However, there was one problem with multisig on Stacks. The original implementation forced multisig parties to sign in a particular order.

For example, in a 3 party multisig, Signer 1 must always sign first, Signer 2 second, and Signer 3 third. If Signer 2 signed before Signer 1, then Signer 1 would be unable to sign the transaction. This makes transaction signing for multisigs cumbersome for the parties involved, and the process isn’t as flexible as it could be.

Along with Jeff Bencin from Hiro Systems and Jude Nelson from the Stacks Foundation, I began working on SIP-027 in April 2023. This SIP introduces a new multisig transaction format that removes the need to have the signing order in place without compromising the security of the multisig. This new format is intended to co-exist alongside the old format, so it doesn’t break any existing logic and instead gives users a choice of which format they’d like to use.

This SIP will go live alongside the Nakamoto hard fork. You can view the Rust implementation details on GitHub.

Diving Into the Code of a Transaction

Let’s take a look at the code to show how a non-sequential multisig works. In this example, we’ll show a simple STX token transfer using the Stacks.js library and the non-sequential multisig transaction type from SIP-027.


import {
 createStacksPrivateKey,
 getPublicKey,
 makeSTXTokenTransfer,
 makeUnsignedSTXTokenTransfer,
 publicKeyToString,
 TransactionSigner
} from "@stacks/transactions";


const createNonSequentialMultisigTx = async () => {
 const pk1 = '04fbae5c79d50dc21c653ed8bf1ad53a43081f839f1ecdda9774d9170e4bb5c501';
 const pk2 = 'f8cefc8e181a06ab004c722cb156e7a24f57d9b08af27f36b15fa1357d572b9301';
 const pk3 = '84e72ac806a425bdef5add21be8771c7498b5e36c235d295d8339a83daf364e3';


// Gathering signers public keys to construct the multisig address
// Remember that the order is important in which signers are added to the script for the address generation logic
 const signers = [pk1, pk2, pk3];
 const publicKeys = signers
   .map(createStacksPrivateKey)
   .map(getPublicKey)
   .map(publicKeyToString);


 const signerKeys = [pk3, pk2];


 const recipient = 'ST1RFD5Q2QPK3E0F08HG9XDX7SSC7CNRS0QR0SGEV';
 const amount = 10000; // amount of STX to be transferred
 const nonce = 0; // multisig address nonce
 const fee = 100; // fee in micro-STX
 const numSignatures = 2; // multisig threshold


 // Make transfer and sign with signer keys


// Making a STX token transfer call. For the final multisig script generation, we need to add a threshold (numSignatures) to the multisig signers list as well as a target network (either testnet or mainnet), and set useNonSequentialMultiSig to true to use new order independent multisig transactions
// makeSTXTokenTransfer not only creates a transaction, but also signs it with signerKeys. Unsigned creation is shown below.
 const txMake = await makeSTXTokenTransfer({
   // the new flag for non-sequential multisig transactions
   useNonSequentialMultiSig: true,
   recipient,
   amount,
   nonce,
   fee,
   network: 'testnet',
   anchorMode: 'any',
   numSignatures,
   publicKeys,
   signerKeys, // "make" will technically ignore these and sign in the sorted order
 });


 // Make unsigned transfer & sign after


 const tx = await makeUnsignedSTXTokenTransfer({
   // The new flag for non-sequential multisig transactions
   useNonSequentialMultiSig: true,
   recipient,
   amount,
   nonce,
   fee,
   network: 'testnet',
   anchorMode: 'any',
   numSignatures,
   publicKeys,
 });


 const signer = new TransactionSigner(tx);


// For unsigned transactions it is possible to sign it in any order with the new non sequential multisig type
 signer.signOrigin(createStacksPrivateKey(pk3));
 signer.signOrigin(createStacksPrivateKey(pk2));
 signer.appendOrigin(getPublicKey(createStacksPrivateKey(pk1)));

As you can see in the code above, this is almost the same process as making a sequential multisig transaction. The only difference is setting the additional <code-rich-text>useNonSequentialMultiSig<code-rich-text> flag to true.

The multisig address generation logic is not changed and doesn’t depend on the multisig spending condition type, which can be non-sequential for multisig transactions.

You can view the Stacks.js library fix in this GitHub PR.

Conclusion

Thanks for reading and learning more about multisigs on Stacks! If you’re interested in learning more, follow Asigna on Twitter and contribute to the Stacks ecosystem with us.

Product updates & dev resources straight to your inbox
Your Email is in an invalid format
Checkbox is required.
Thanks for
subscribing.
Oops! Something went wrong while submitting the form.
Copy link
Mailbox
Hiro news & product updates straight to your inbox
Only relevant communications. We promise we won’t spam.

Related stories