Ether.js

How can I create a multisignature wallet using Ethersjs


Overview

A multi-signature wallet requires multiple signatures to authorize a transaction. This enhances security by ensuring that no single person can control the funds. In this guide, we will create a simple multi-signature wallet smart contract, deploy it, and interact with it using Ethers.js.

1. Writing the Multi-Signature Wallet Smart Contract

First, we need to write a smart contract for the multi-signature wallet. Below is a simple implementation in Solidity:

        
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.0;
            contract MultiSigWallet {
                address[] public owners;
                mapping(address => bool) public isOwner;
                uint public required;
                struct Transaction {
                    address to;
                    uint value;
                    bool executed;
                    uint confirmations;
                    mapping(address => bool) isConfirmed;
                }
                Transaction[] public transactions;
                modifier onlyOwner() {
                    require(isOwner[msg.sender], `Not an owner`);
                    _;
                }
                constructor(address[] memory _owners, uint _required) {
                    require(_owners.length > 0, `Owners required`);
                    require(_required > 0 && _required <= _owners.length, `Invalid required number of owners`);
                    for (uint i = 0; i < _owners.length; i++) {
                        address owner = _owners[i];
                        require(owner != address(0), `Invalid owner`);
                        require(!isOwner[owner], `Owner not unique`);
                        isOwner[owner] = true;
                        owners.push(owner);
                    }
                    required = _required;
                }
                function submitTransaction(address _to, uint _value) public onlyOwner {
                    transactions.push(Transaction({
                        to: _to,
                        value: _value,
                        executed: false,
                        confirmations: 0
                    }));
                }
                function confirmTransaction(uint _txIndex) public onlyOwner {
                    Transaction storage transaction = transactions[_txIndex];
                    require(!transaction.isConfirmed[msg.sender], `Transaction already confirmed`);
                    transaction.isConfirmed[msg.sender] = true;
                    transaction.confirmations++;
                }
                function executeTransaction(uint _txIndex) public onlyOwner {
                    Transaction storage transaction = transactions[_txIndex];
                    require(transaction.confirmations >= required, `Not enough confirmations`);
                    require(!transaction.executed, `Transaction already executed`);
                    transaction.executed = true;
                    (bool success, ) = transaction.to.call{value: transaction.value}(``);
                    require(success, `Transaction failed`);
                }
                receive() external payable {}
            }
            

2. Deploying the Smart Contract

To deploy the smart contract, you can use Ethers.js. Below is an example of how to deploy the contract:

        
            // deploy.js
            const { ethers } = require(`ethers`);
            async function main() {
                const provider = new ethers.providers.JsonRpcProvider(`https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID`);
                const wallet = new ethers.Wallet(`YOUR_PRIVATE_KEY`, provider);
                const MultiSigWallet = await ethers.getContractFactory(`MultiSigWallet`, wallet);
                const owners = [`0xOwnerAddress1`, `0xOwnerAddress2`, `0xOwnerAddress3`];
                const required = 2;
                const multiSigWallet = await MultiSigWallet.deploy(owners, required);
                console.log(`MultiSigWallet deployed to:`, multiSigWallet.address);
            }
            main().catch((error) => {
                console.error(error);
                process.exit (1);
            });
            

3. Interacting with the Multi-Signature Wallet

Once the contract is deployed, you can interact with it using Ethers.js. Below is an example of how to submit, confirm, and execute a transaction:

        
            // interact.js
            const { ethers } = require(`ethers`);
            async function main() {
                const provider = new ethers.providers.JsonRpcProvider(`https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID`);
                const wallet = new ethers.Wallet(`YOUR_PRIVATE_KEY`, provider);
                const multiSigWalletAddress = `DEPLOYED_CONTRACT_ADDRESS`;
                const multiSigWallet = new ethers.Contract(multiSigWalletAddress, [
                    `function submitTransaction(address _to, uint _value)`,
                    `function confirmTransaction(uint _txIndex)`,
                    `function executeTransaction(uint _txIndex)`
                ], wallet);
                // Submit a transaction
                const txTo = `0xRecipientAddress`;
                const txValue = ethers.utils.parseEther(`0.1`);
                await multiSigWallet.submitTransaction(txTo, txValue);
                console.log(`Transaction submitted`);
                // Confirm the transaction (repeat this for each owner)
                await multiSigWallet.confirmTransaction(0);
                console.log(`Transaction confirmed`);
                // Execute the transaction after enough confirmations
                await multiSigWallet.executeTransaction(0);
                console.log(`Transaction executed`);
            }
            main().catch((error) => {
                console.error(error);
                process.exit(1);
            });
            

Conclusion

In this guide, we created a simple multi-signature wallet using Ethers.js. We wrote a smart contract that requires multiple confirmations to execute transactions, deployed it to the Ethereum blockchain, and interacted with it using Ethers.js. This approach enhances security for managing funds, making it a valuable tool for groups or organizations that require shared control over assets.

Written by Surfside Media

Senior Full Stack Developer specializing in Web Technologies.