DevStation / LaunchKit / Templates / MultiSigWallet

MultiSigWallet

A multi-signature wallet requiring M of N owner approvals to execute any transaction.

Deploy This Template
MultiSigWallet.sol
solidity
1// SPDX-License-Identifier: MIT
2pragma solidity ^0.8.20;
3 
4contract MultiSigWallet {
5 address[] public owners;
6 uint256 public required;
7 mapping(address => bool) public isOwner;
8 mapping(uint256 => mapping(address => bool)) public confirmed;
9 
10 struct Tx { address to; uint256 value; bytes data; bool executed; uint256 confirmations; }
11 Tx[] public txs;
12 
13 event Submit(uint256 indexed id);
14 event Confirm(address indexed owner, uint256 indexed id);
15 event Execute(uint256 indexed id);
16 
17 modifier onlyOwner() {
18 require(isOwner[msg.sender], "NOT_OWNER");
19 _;
20 }
21 
22 constructor(address[] memory _owners, uint256 _required) {
23 require(_owners.length > 0 && _required > 0 && _required <= _owners.length, "BAD_CONFIG");
24 for (uint256 i = 0; i < _owners.length; i++) {
25 require(_owners[i] != address(0) && !isOwner[_owners[i]], "BAD_OWNER");
26 isOwner[_owners[i]] = true;
27 }
28 owners = _owners;
29 required = _required;
30 }
31 
32 function submit(address to, uint256 value, bytes calldata data) external onlyOwner returns (uint256) {
33 txs.push(Tx(to, value, data, false, 0));
34 uint256 id = txs.length - 1;
35 emit Submit(id);
36 return id;
37 }
38 
39 function confirm(uint256 id) external onlyOwner {
40 require(!confirmed[id][msg.sender], "ALREADY");
41 confirmed[id][msg.sender] = true;
42 txs[id].confirmations++;
43 emit Confirm(msg.sender, id);
44 }
45 
46 function execute(uint256 id) external onlyOwner {
47 Tx storage t = txs[id];
48 require(t.confirmations >= required && !t.executed, "NOT_READY");
49 t.executed = true;
50 (bool ok, ) = t.to.call{value: t.value}(t.data);
51 require(ok, "CALL_FAILED");
52 emit Execute(id);
53 }
54 
55 receive() external payable {}
56}
DevStation
Loading console…