Multisignature Smart-Contract Wallets
Overview
BitGo enables multisignature wallets for account-based assets on programmable blockchains, such as Ethereum, using smart contracts. Like all Bitgo wallets, when you make multisignature smart-contract wallets, BitGo creates 3 keys (user, backup, and BitGo). In addition, the smart contracts enable creating multiple receive addresses, a feature that isn't native to most account-based assets. The 2-of-3 key scheme and the ability to create multiple receive addresses may appear similar to their UTXO counterparts. However, the mechanisms of how they work for smart-contract wallets differ.
To explore the smart contract yourself, see the GitHub repo.
Keys
Each key controls an address on the Ethereum blockchain. The user-key and backup-key addresses typically aren't funded, other than for disaster recovery. However, the BitGo-key address is funded, because it's the gas tank. You can shard each key using Shamir's Secret Sharing (SSS) to create more complicated key distributions. This is often done for the user key.
When you instantiate a multisignature smart-contract wallet, BitGo stores the 3 addresses in the allowedSigners
array. Every method on the smart contract requires a certain number of allowed signers to prevent reverting. For example, sending a native token to another address using SendMultiSig
requires 2-of-3 signatures, but flushing ERC20 tokens from a forwarder using flushForwarderTokens
only requires 1 signature. This enables BitGo to flush ERC20 tokens from your forwarder addresses without your signature and is also why BitGo can't withdraw assets from your wallet.
Signing
The smart contract enables collecting 2-of-3 signatures all on a single on-chain transaction. Typically, the user key signs some fields, including, but not limited to:
- Unique identifier for the chain
- Amount
- Final destination address
- Any contract data being forwarded
- Expire time
- Contract sequence ID
This is done by creating a hash on those fields, and signing that hash. BitGo takes those fields, along with the hash and signature, and places them in the data section of an unsigned transaction. The unsigned transaction has a value of 0, and a destination of the base address of the wallet smart contract. BitGo adds a nonce to the unsigned transaction and sends it to the BitGo hardware security module (HSM) for final signing.
At this stage, Bitgo refers to the transaction as a half-signed, because 1-of-3 keys applied a signature. However, from a protocol level, it's an unsigned transaction that just contains cryptographic proof that 1-of-3 keys signed parts of the data section.
Lastly, BitGo uses the HSM to sign the transaction using the BitGo key, creating a fully signed transaction from both the perspective of BitGo and the protocol. BitGo then broadcasts the transaction to the base address of the wallet. The smart contract verifies the transaction was signed by 1-of-3 keys (typically the BitGo key) and that the operationHash
was signed by another key (typically the user key).