👛 Multisig transactions with Gnosis Safe
In this post, we’ll explore what multisig wallets are and how to use Gnosis Safe to manage your funds and transactions.
Type of accounts in Ethereum
Let’s start with some basics. Accounts are fundamental Ethereum components that can hold funds and execute transactions, read or write. If you think of Ethereum as a state machine then a write transaction can modify its state. In order to execute a transaction, you need to pay a fee (gas) to the miners who will update the blockchain.
In Ethereum we have 2 types of accounts:
- Externally Owned Accounts (EOA) or simply wallets. These wallet are identified by a private/public key pair. They can hold funds and execute transactions, for example they can transfer ETH to another wallet or call a smart contract to create an NFT. MetaMask is the most popular Ethereum software wallet.
- Contract Accounts, simply called smart contracts, don’t have private keys but they have code that can be executed calling their methods. If you’re new to smart contracts take a break here and go read this https://ethereum.org/en/developers/docs/smart-contracts/.
⚠️ Lose your private key and you lose access to your wallet for 👏 ever 👏. How can we avoid that? Introducing multisig wallets.
A clever way to use smart contracts is to create a new type of accounts called Multi-signature wallets. These wallets have multiple keys. A typical multisig configuration has 3 owners and it needs 2 keys to move the funds:
In our example above each owner has a key, but due their flexibility multisigs can be configured in different ways.
Multisig wallets are very flexible and are used by companies and individuals in different ways:
- Companies and protocols can hold their funds safely and require a majority of owners to accept to transfer them. So not one owner can run with the money.
- Companies can execute sensitive transactions with the consensus of a majority of owners.
- Individuals can use multisig to have keys redundancy. One property of multisig is that if you lose one key you can recover the wallet with the remaining 2 keys. But lose 2 keys and you’re f****d.
In this blog post we’ll focus on Gnosis Safe, a multisig wallet for Ethereum trusted by several companies. At the moment of writing it secures a whopping 22 billion dollars in assets:
Knowledge of spiritual mysteries
Gnosis is the common Greek noun for knowledge and it’s being used by Hellenistic religions and philosophy.
Gnosis started as a cryptocurrency in 2017 with an ICO attracting 250,000 ETH, $14M at the time, ~$800M today!
Gnosis was the first decentralized prediction market. It was also the first cryptocurrency to introduce the “utility token” concept for creating a dual token economy — you probably remember these from the 2017 ICO boom.
Since then the Gnosis tech team started releasing some of their tools open source, of them Gnosis Safe received the most traction in the crypto space.
🔐 Gnosis Safe
You can think of Gnosis Safe as a collection of tools to create and to manage multisig wallets, think of them as lego pieces:
- Safe Contracts, we’ll see more in the details of the contracts, but for now just know that Safe is the multisig contract that allows for holding and transferring of funds such as ETH, ERC20, NFTs, as well as to execute transactions. A Safe can execute a transaction on-chain and off-chain.
- Safe UI is a simple React UI, so simple it takes just 60 seconds to create a multisig. Currently deployed on Mainnet and Rinkeby.
- Safe transaction service is an API maintained by the Gnosis team and it is used by the Safe UI to store off-chain signatures.
- Safe Apps, Gnosis allows to extends its functionality by adding custom apps that allow to manage governance, fair Auctions, and much more.
In Gnosis Safe there are 2 signature flows: on-chain and off-chain. Both use EIP712, a standard signing method that creates a struct with the transaction arguments, hashes them with keccak256 and then signs them with secp256k1.
The owners can sign the transaction and call the method
Safe.approveHash. When the threshold is reached the last signer can call the method
Safe.executeTransaction. Each transaction costs gas, and so this signing flow is the most expensive.
In the off-chain signing flow the owners sign the transaction and store it somewhere. The last signer can execute the transaction calling the method
Safe.executeTransaction passing all the signatures.
This solution uses much less gas, but it requires some coordination to collect the signatures, and that’s what the Safe Transaction Service is for.
⚠️ The Safe Transaction Service is a public API, this means everyone can see all the transactions of a Safe before they’re executed on-chain. Someone can use this info to front-run the transactions.
Demo — Create a Safe and exec a multisig transaction
In this demo we’ll learn how to create a new Safe on Rinkeby and use it to execute a transaction.
We’ll deploy a simple contract, let’s call it PokemonTaco because who doesn’t love Pokemon and Tacos. This contract has a simple uint num property that can be updated calling the updateNum method:
- Here’s a video showing how to deploy our contract:
2. We create a Safe with 2 out of 2 owner:
3. Let’s now execute our multisig transaction:
How we use Gnosis Safe at Gauntlet
At Gauntlet we use Gnosis Safe both to manage our funds and to execute transactions created through automation.
At Gauntlet we run simulations to analyze DeFi protocols, suggesting parameters adjustments to keep them healthy under any market conditions.
We use Gnosis Safe to update those parameters on-chain:
You may ask: “Fed, how the heck does the simulation create a transaction?”
Well, the safe-transaction-service allows the owners to delegate other public keys to become a delegated signer and to create a new transaction, but not to sign it or execute it. This means that the transaction will show up in the Safe UI, and that 2 out of 3 owners are still required to sign it. Everyone’s happy!
🌱 Gnosis Safe Contracts
Let’s go more into the weeds and look at the main Gnosis Safe contracts https://github.com/gnosis/safe-contracts:
- GnosisSafe.sol contains all the core functionality required to set up and execute Gnosis Safe transactions. It contains the logic to use the optional token payment feature.
- OwnerManager.sol controls owner management of a safe along with setting the signature threshold.
- ModuleManager.sol, it allows to add modules to the safe, extending its functionality. A module can for example set the number of signature required for a specific amount transfer, or set daily limit allowances and so on.
- GnosisSafeProxy.sol and GnosisSafeProxyFactory.sol are used because deploying a contract is quite expensive. Gnosis Safe implements the proxy pattern to reduce costs and to make the contract upgradable. The ProxyFactory is used to create a new safe that connects to the proxy.
- FallbackManager.sol, Ethereum fallback functions are executed when a called function signature does not match any defined function. Certain use cases require those fallback functions to contain some logic. For instance, this is required for making the Safe 100% compatible with the ERC-721 token standard. Note: don’t confuse ERC-721 with ERC-712.
The Gnosis Safe smart contract was written with the usage of a proxy contract in mind. Because of that, there is no constructor and calling an initialize function (
setup) on the contract is required before it can be used.
While the easiest way to create a Safe is by using the Safe UI, you may need to create one via code to test your code. Here’s what the EthersJS + Hardhat code to deploy a Safe looks like:
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";const safeContract = await ethers.getContractAt(GnosisSafeSol.abi, GnosisSafeSol.address);const safeAccounts = [pubKey1, pubKey2, pubKey3];
const DEFAULT_FALLBACK_HANDLER_ADDRESS = "0x...";
const params = [
];// proxy deployment
const safeAbi = safeContract.interface.encodeFunctionData(
const ProxyFactoryContract = await ethers.getContractAt(ProxyFactorySol.abi, ProxyFactorySol.address);
const signer = ProxyFactoryContract.connect(myWallet);
const saltNonce = Date.now();
const txResponse = await signer.createProxyWithNonce(
safeContract.address, safeAbi, saltNonce
const txReceipt = await txResponse.wait();// address of the newly deployed Safe
🚀 Executing a transaction
The easiest way to execute a multisig transaction is to use the Safe UI. At Gauntlet we need to create automated transactions according to our continuous simulation results. In order to do that we sign the transaction with the delegate signer and submit it to the Safe Transaction Service.
One way to do that is by using the Contract Proxy Kit, an SDK allowing interaction with the Safe Contract and Safe Transaction Service: https://docs.gnosis.io/safe/docs/sdks_cpk, but currently, only batch transactions are directly supported by the CPK.
In Gauntlet’s case we decided to reverse engineer the Safe-React (Safe UI) to extract the off-chain signature code, allowing us to sign with EIP-712 and to call the Safe Transaction Service to create a transaction in the Safe UI. Here’s the code we reverse engineered, if you’re curious: https://github.com/gnosis/safe-react/blob/5020c0daa31ecc0f26520f206deda5393502ad30/src/logic/safe/store/actions/createTransaction.ts#L53.
Gnosis Safe is an incredibly powerful tool you should consider to manage your protocol, project, or company funds and any transaction automation — just like we do at Gauntlet. Individuals should also consider it if you participate in DAO governance, yield farming, and much more.