I am currently relearning Solidity to solidify some of the details and create a "WTF Solidity Crash Course" for beginners (advanced programmers may want to find another tutorial). I will update 1-3 lessons weekly.
Twitter: @0xAA_Science
Community: Discord|WeChat Group|Official website wtf.academy
All code and tutorials are open source on Github: github.com/AmazingAng/WTF-Solidity
Vitalik once said that a multisig wallet is safer than a hardware wallet (tweet). In this lesson, we'll introduce multisig wallets and write a simple version of a multisig wallet contract. The teaching code (150 lines of code) is simplified from the Gnosis Safe contract (several thousand lines of code).

Multisig Wallet
A multisig wallet is an electronic wallet where transactions require authorization from multiple private key holders (multisig owners) before they can be executed. For example, if a wallet is managed by three multisig owners, each transaction requires authorization from at least two of them. Multisig wallets can prevent single-point failure (loss of private keys, individual misbehavior), have greater decentralized characteristics, and provide increased security. It is used by many DAOs.
Gnosis Safe is the most popular multisig wallet on Ethereum, managing nearly $40 billion in assets. The contract has undergone auditing and practical testing, supports multiple chains (Ethereum, BSC, Polygon, etc.), and provides comprehensive DAPP support. For more information, you can read the Gnosis Safe tutorial I wrote in December 2021.
Multisig Wallet Contract
A multisig wallet on Ethereum is actually a smart contract, and it is a contract wallet. We'll write a simple version of the MultisigWallet contract, which has a simple logic:
-
Set multisig owners and threshold (on-chain): When deploying a multisig contract, we need to initialize a list of multisig owners and the execution threshold (at least n multisig owners need to sign and authorize a transaction before it can be executed). Gnosis Safe supports adding/removing multisig owners and changing the execution threshold, but we will not consider this feature in our simplified version.
-
Create transactions (off-chain): A transaction waiting for authorization contains the following information:
to
: Target contract.value
: The amount of Ether sent in the transaction.data
: Calldata, which contains the function selector and parameters for the function call.nonce
: Initially set to0
, the value of the nonce increases with each successfully executed transaction of the multisig contract, which can prevent replay attacks.chainid
: The chain id helps prevent replay attacks across different chains.
-
Collect multisig signatures (off-chain): The previous transaction is encoded using ABI and hashed to obtain the transaction hash. Then, the multisig individuals sign it and concatenate the signatures together to obtain the final signed transaction. For those who are not familiar with ABI encoding and hashing, you can refer to the WTF Solidity Tutorial Lesson 27 and Lesson 28.
- Call the execution function of the multisig contract, verify the signature and execute the transaction (on-chain). If you are not familiar with verifying signatures and executing transactions, you can refer to the WTF Solidity Tutorial Lesson 22 and Lesson 37.
Events
The MultisigWallet
contract has two events, ExecutionSuccess
and ExecutionFailure
, which are triggered when the transaction is successfully executed or failed, respectively. The parameters are the transaction hash.
State Variables
The MultisigWallet
contract has five state variables:
owners
: An array of multisig owners.isOwner
: A mapping fromaddress
tobool
which tracks whether an address is a multisig holder.ownerCount
: The total number of multisig owners.threshold
: The minimum number of multisig owners required to execute a transaction.nonce
: Initially set to 0, this variable increments with each successful transaction executed by the multisig contract, which can prevent signature replay attacks.
Functions
The MultisigWallet
contract has 6
functions:
-
Constructor: calls
_setupOwners()
to initialize variables related to multisig owners and execution thresholds. -
_setupOwners()
: Called by the constructor during contract deployment to initialize theowners
,isOwner
,ownerCount
, andthreshold
state variables. The passed-in parameters must have a threshold greater than or equal to1
and less than or equal to the number of multisignature owners. The multisignature addresses cannot be the zero addresses and cannot be duplicated.
execTransaction()
: After collecting enough multisig signatures, it verifies the signatures and executes the transaction. The parameters passed in include the target addressto
, the amount of Ethereum sentvalue
, the datadata
, and the packaged signaturessignatures
. The packaged signature is the signature of the transaction hash collected by the multisig parties, packaged into a [bytes] data in the order of the multisig owners' addresses from small to large. This step callsencodeTransactionData()
to encode the transaction and callscheckSignatures()
to verify the validity of the signatures and whether the number of signatures reaches the execution threshold.
-
checkSignatures()
: checks if the hash of the signature and transaction data matches, and if the number of signatures exceeds the threshold. If not, the transaction will revert. The length of a single signature is 65 bytes, so the length of the packed signatures must be greater thanthreshold * 65
. This function roughly works in the following way:- Get signature address using ECDSA.
- Determine if the signature comes from a different multisignature using
currentOwner > lastOwner
(multisignature addresses increase). - Determine if the signer is a multisignature holder using
isOwner[currentOwner]
.
-
signatureSplit()
function: split a single signature from a packed signature. The function takes two arguments: the packed signaturesignatures
and the position of the signature to be readpos
. The function uses inline assembly to split ther
,s
, andv
values of the signature.
-
encodeTransactionData()
: Packs and calculates the hash of transaction data using theabi.encode()
andkeccak256()
functions. This function can calculate the hash of a transaction, then allow the multisig to sign and collect it off-chain, and finally call theexecTransaction()
function to execute it.
Demo of Remix
-
Deploy a multisig contract with 2 multisig addresses and set the execution threshold to
2
. -
Transfer
1 ETH
to the multisig contract address. -
Call
encodeTransactionData()
, encode and calculate the transaction hash for transferring1 ETH
to the address of the multisig with index 1.

-
Use the note icon next to the ACCOUNT in Remix to sign the transaction. Input the above transaction hash and obtain the signature. Both wallets must be signed.



-
Call the
execTransaction()
function to execute the transaction, passing in the transaction parameters from step 3 and the packaged signature as parameters. You can see that the transaction was executed successfully andETH
was transferred from the multisig wallet.
Summary
In this lesson, we introduced the concept of a multisig wallet and wrote a minimal implementation of a multisig wallet contract, which is less than 150 lines of code.
I have had many opportunities to work with multisig wallets. In 2021, I learned about Gnosis Safe and wrote a tutorial on its usage in both Chinese and English because of the creation of the national treasury by PeopleDAO. Afterwards, I was lucky enough to maintain the assets of three treasury multisig wallets and now I am deeply involved in governing Safes as a guardian. I hope that everyone's assets will be even more secure.