Implementing a Multisignature Wallet in Web3.js
A multisignature wallet requires multiple signatures to authorize a transaction, increasing security. In this guide, we'll walk through how to implement a multisignature wallet using Web3.js and a simple smart contract.
1. Prerequisites
Before you start, ensure you have the following:
- Node.js and npm installed on your machine
- Web3.js library
- A local Ethereum node or access to a test network (e.g., Ganache)
2. Create a Multisignature Smart Contract
Below is a simple multisignature wallet contract written in Solidity:
pragma solidity ^0.8.0;
contract MultiSigWallet {
address[] public owners;
uint public required;
struct Transaction {
address to;
uint value;
bool executed;
mapping(address => bool) confirmations;
}
Transaction[] public transactions;
event SubmitTransaction(address indexed owner, uint indexed txIndex, address indexed to, uint value);
event ConfirmTransaction(address indexed owner, uint indexed txIndex);
event ExecuteTransaction(address indexed owner, uint indexed txIndex);
modifier onlyOwner() {
require(isOwner(msg.sender), "Not owner");
_;
}
modifier txExists(uint txIndex) {
require(txIndex < transactions.length, "Transaction does not exist");
_;
}
modifier notExecuted(uint txIndex) {
require(!transactions[txIndex].executed, "Transaction already executed");
_;
}
constructor(address[] memory _owners, uint _required) {
owners = _owners;
required = _required;
}
function isOwner(address owner) public view returns (bool) {
for (uint i = 0; i < owners.length; i++) {
if (owners[i] == owner) return true;
}
return false;
}
function submitTransaction(address to, uint value) public onlyOwner {
uint txIndex = transactions.length;
transactions.push(Transaction({to: to, value: value, executed: false}));
emit SubmitTransaction(msg.sender, txIndex, to, value);
}
function confirmTransaction(uint txIndex) public onlyOwner txExists(txIndex) notExecuted(txIndex) {
transactions[txIndex].confirmations[msg.sender] = true;
emit ConfirmTransaction(msg.sender, txIndex);
}
function executeTransaction(uint txIndex) public onlyOwner txExists(txIndex) notExecuted(txIndex) {
require(getConfirmationCount(txIndex) >= required, "Not enough confirmations");
Transaction storage txn = transactions[txIndex];
txn.executed = true;
(bool success, ) = txn.to.call{value: txn.value}("");
require(success, "Transaction failed");
emit ExecuteTransaction(msg.sender, txIndex);
}
function getConfirmationCount(uint txIndex) public view returns (uint count) {
for (uint i = 0; i < owners.length; i++) {
if (transactions[txIndex].confirmations[owners[i]]) {
count += 1;
}
}
}
}
3. Deploy the Smart Contract
Use Remix IDE to compile and deploy the contract. Make sure to provide an array of owner addresses and the required number of confirmations during deployment.
4. Set Up Your Web3.js Environment
In your project directory, initialize a new Node.js project and install Web3.js:
mkdir multisig-wallet
cd multisig-wallet
npm init -y
npm install web3
5. Interact with the Multisignature Wallet
Create a JavaScript file (e.g., app.js
) to interact with your multisignature wallet:
const Web3 = require('web3');
// Connect to your local Ethereum node or test network
const web3 = new Web3('http://localhost:8545'); // Change to your node URL
const contractABI = [ /* ABI from Remix */ ];
const contractAddress = '0xYourContractAddress'; // Replace with your deployed contract address
const multiSigWallet = new web3.eth.Contract(contractABI, contractAddress);
// Example: Submit a transaction
async function submitTransaction(fromAddress, toAddress, value) {
const tx = await multiSigWallet.methods.submitTransaction(toAddress, value).send({ from: fromAddress });
console.log('Transaction submitted:', tx);
}
// Example: Confirm a transaction
async function confirmTransaction(fromAddress, txIndex) {
const tx = await multiSigWallet.methods.confirmTransaction(txIndex).send({ from: fromAddress });
console.log('Transaction confirmed:', tx);
}
// Example: Execute a transaction
async function executeTransaction(fromAddress, txIndex) {
const tx = await multiSigWallet.methods.executeTransaction(txIndex).send({ from: fromAddress });
console.log('Transaction executed:', tx);
}
// Replace with actual addresses and values
const fromAddress = '0xYourAddress'; // Replace with the address of the owner
const toAddress = '0xRecipientAddress'; // Replace with the recipient's address
const value = web3.utils.toWei('0.1', 'ether'); // Amount to send in Ether
// Submit a transaction
submitTransaction(fromAddress, toAddress, value);
// Confirm a transaction (replace txIndex with the actual index)
// confirmTransaction(fromAddress, txIndex);
// Execute a transaction (replace txIndex with the actual index)
// executeTransaction(fromAddress, txIndex);
6. Conclusion
By following these steps, you can implement a multisignature wallet using Web3.js. This setup enhances security by requiring multiple confirmations for transactions, making it a robust solution for managing funds in a decentralized manner.