π©βπ©βπ§βπ§ A multisig wallet is a smart contract that acts like a wallet, allowing us to secure assets by requiring multiple accounts to "vote" on transactions. Think of it as a treasure chest that can only be opened when all key parties agree.
π The contract keeps track of all transactions. Each transaction can be confirmed or rejected by the signers (smart contract owners). Only transactions that receive enough confirmations can be "executed" by the signers.
π The final deliverable is a multisig wallet where you can propose adding and removing signers, transferring funds to other accounts, and updating the required number of signers to execute a transaction. After any of the signers propose a transaction, it's up to the signers to confirm and execute it. Deploy your contracts to a testnet, then build and upload your app to a public web server.
π¬ Meet other builders working on this challenge and get help in the Multisig Build Cohort telegram.
In this challenge you'll have access to a fully functional Multisig Wallet for inspiration, unlike previous challenges where certain code sections were intentionally left incomplete.
The objective is to allow builders to create their unique versions while referring to this existing build when encountering difficulties.
- Can you edit and deploy the contract with a 2/3 multisig with two of your addresses and the buidlguidl multisig as the third signer? (buidlguidl.eth is like your backup recovery.)
- Can you propose basic transactions with the frontend that sends them to the backend?
- Can you βvoteβ on the transaction as other signers?
- Can you execute the transaction and does it do the right thing?
- Can you add and remove signers with a custom dialog (that just sends you to the create transaction dialog with the correct calldata)
-
Multisig as a service
Create a deploy button with a copy-paste dialog for sharing so anyone can make a multisig at your URL with your frontend. -
Create custom signer roles for your Wallet
You may not want every signer to create new transfers, only allow them to sign existing transactions or a mega-admin role who will be able to veto any transaction. -
Integrate this MultiSig wallet into other Scaffold ETH-2 builds
Find a Scaffold ETH-2 build that could make use of a Multisig wallet and try to integrate it!
This is a smart contract that acts as an offchain signature-based shared wallet amongst different signers that showcases use of meta-transaction knowledge and ECDSA recover()
.
If you are unfamiliar with these concepts, check out all the ETH.BUILD videos by Austin Griffith, especially the Meta Transactions one!
β OpenZepplin's ECDSA Library provides an easy way to verify signed messages, in this challenge we'll be using it to verify the signatures of the signers of the multisig wallet.
At a high-level, the contract core functions are carried out as follows:
Offchain: βπ
π»ββοΈ - Generation of a packed hash (bytes32) for a function call with specific parameters through a public view function . - It is signed by one of the signers associated to the multisig, and added to an array of signatures (bytes[] memory signatures
)
Onchain: βππ»ββοΈ
bytes[] memory signatures
is then passed intoexecuteTransaction
as well as the necessary info to userecover()
to obtain the public address that ought to line up with one of the signers of the wallet.- This method, plus some conditional logic to avoid any duplicate entries from a single signer, is how votes for a specific transaction (hashed tx) are assessed.
- If it's a success, the tx is passed to the
call(){}
function of the deployed MetaMultiSigWallet contract (this contract), thereby passing theonlySelf
modifier for any possible calls to internal txs such as (addSigner()
,removeSigner()
,transferFunds()
,updateSignaturesRequired()
).
Cool Stuff that is Showcased: π
- Showcases how the
call(){}
function is an external call that ought to increase the nonce of an external contract, as they increment differently from user accounts. - Normal internal functions, such as changing the signers, and adding or removing signers, are treated as external function calls when
call()
is used with the respective transaction hash. - Showcases use of an array (see constructor) populating a mapping to store pertinent information within the deployed smart contract storage location within the EVM in a more efficient manner.
Before you begin, you need to install the following tools:
- Node (v18 LTS)
- Yarn (v1 or v2+)
- Git
Then download the challenge to your computer and install dependencies by running:
git clone https://github.com/scaffold-eth/se-2-challenges.git challenge-6-multisig
cd challenge-6-multisig
git checkout challenge-6-multisig
yarn install
in the same terminal, start your local network (a blockchain emulator in your computer):
yarn chain
in a second terminal window, π° deploy your contract (locally):
cd challenge-6-multisig
yarn deploy
in a third terminal window, start your π± frontend:
cd challenge-6-multisig
yarn start
π± Open http://localhost:3000 to see the app.
In a fourth terminal window:
β This command is only required in your local environment (Hardhat chain).
yarn backend-local
When deployed to any other chain, it will automatically use our deployed backend (repo) from https://backend.multisig.holdings:49832/
.
π©βπ» Rerun
yarn deploy --reset
whenever you want to deploy new contracts to the frontend, update your current contracts with changes, or re-deploy it to get a fresh contract address.
π Now you are ready to edit your smart contract MetaMultiSigWallet.sol
in packages/hardhat/contracts
π The first step for this multisig wallet is to configure the owners, who will be able to propose, sign and execute transactions.
ποΈ This is done in the constructor of the contract, where you can pass in an array of addresses that will be the signers of the wallet, and a number of signatures required to execute a transaction.
π οΈ Modify the contract constructor arguments at the deploy script
00_deploy_meta_multisig_wallet.ts
inpackages/hardhat/deploy
. Just set the first signer using your frontend address.
π Will need to run
yarn deploy --reset
to deploy a fresh contract with the first signer configured.
You can set the rest of the signers in the frontend, using the "Owners" tab:
In this tab you can start your transaction proposal to either add or remove owners.
π Fill the form and click on "Create Tx".
This will take you to a populated transaction at "Create" page:
Create & sign the new transaction, clicking in the "Create" button:
You will see the new transaction in the pool (this is all offchain).
You won't be able to sign it because on creation it already has one signature (from the frontend account).
Click on the ellipsses button [...] to read the details of the transaction.
β½οΈ Give your account some gas at the faucet and execute the transaction.
β Click on "Exec" to execute it, will be marked as "Completed" on the "Pool" tab, and will appear in the "Multisig" tab with the rest of executed transactions.
π° Use the faucet to send your multisig contract some funds. You can find the address in the "Multisig" and "Debug Contracts" tabs.
Create a transaction in the "Create" tab to send some funds to one of your signers, or to any other address of your choice:
π This time we will need a second signature (remember we've just updated the number of signatures required to execute a transaction to 2).
Open another browser and access with a different owner of the multisig. Sign the transaction with enough owners:
(You'll notice you don't need β½οΈgas to sign transactions).
Execute the transaction to transfer the funds:
π‘ Edit the defaultNetwork
to your choice of public EVM networks in packages/hardhat/hardhat.config.ts
π You will need to generate a deployer address using yarn generate
This creates a mnemonic and saves it locally.
π©βπ Use yarn account
to view your deployer account balances.
β½οΈ You will need to send ETH to your deployer address with your wallet, or get it from a public faucet of your chosen network.
π Run yarn deploy
to deploy your smart contract to a public network (selected in hardhat.config.ts
)
π¬ Hint: You can set the
defaultNetwork
inhardhat.config.ts
tosepolia
OR you canyarn deploy --network sepolia
.
π¬ Hint: For faster loading of the Multisig tabs, consider updating the
fromBlock
passed touseScaffoldEventHistory
(in the different components we're using it) toblocknumber - 10
at which your contract was deployed. Example:fromBlock: 3750241n
(wheren
represents its a BigInt). To find this blocknumber, search your contract's address on Etherscan and find theContract Creation
transaction line.
βοΈ Edit your frontend config in packages/nextjs/scaffold.config.ts
to change the targetNetwork
to chains.sepolia
or any other public network.
π» View your frontend at http://localhost:3000 and verify you see the correct network.
π‘ When you are ready to ship the frontend app...
π¦ Run yarn vercel
to package up your frontend and deploy.
Follow the steps to deploy to Vercel. Once you log in (email, github, etc), the default options should work. It'll give you a public URL.
If you want to redeploy to the same production URL you can run
yarn vercel --prod
. If you omit the--prod
flag it will deploy it to a preview/test URL.
π¦ Since we have deployed to a public testnet, you will now need to connect using a wallet you own or use a burner wallet. By default π₯
burner wallets
are only available onhardhat
. You can enable them on every chain by settingonlyLocalBurnerWallet: false
in your frontend config (scaffold.config.ts
inpackages/nextjs/
)
By default, π Scaffold-ETH 2 provides predefined API keys for popular services such as Alchemy and Etherscan. This allows you to begin developing and testing your applications more easily, avoiding the need to register for these services. This is great to complete your SpeedRunEthereum.
For production-grade applications, it's recommended to obtain your own API keys (to prevent rate limiting issues). You can configure these at:
-
π·
ALCHEMY_API_KEY
variable inpackages/hardhat/.env
andpackages/nextjs/.env.local
. You can create API keys from the Alchemy dashboard. -
π
ETHERSCAN_API_KEY
variable inpackages/hardhat/.env
with your generated API key. You can get your key here.
π¬ Hint: It's recommended to store env's for nextjs in Vercel/system env config for live apps and use .env.local for local testing.
Run the yarn verify --network your_network
command to verify your contracts on etherscan π°
π©ββ€οΈβπ¨ Share your public url with friends, add signers and send some tasty ETH to a few lucky ones π!!
π Head to your next challenge here.
π¬ Problems, questions, comments on the stack? Post them to the π scaffold-eth developers chat