MultiSigWallet
A multi-signature wallet requiring M of N owner approvals to execute any transaction.
MultiSigWallet.sol
// SPDX-License-Identifier: MITpragma solidity ^0.8.20; contract MultiSigWallet { address[] public owners; uint256 public required; mapping(address => bool) public isOwner; mapping(uint256 => mapping(address => bool)) public confirmed; struct Tx { address to; uint256 value; bytes data; bool executed; uint256 confirmations; } Tx[] public txs; event Submit(uint256 indexed id); event Confirm(address indexed owner, uint256 indexed id); event Execute(uint256 indexed id); modifier onlyOwner() { require(isOwner[msg.sender], "NOT_OWNER"); _; } constructor(address[] memory _owners, uint256 _required) { require(_owners.length > 0 && _required > 0 && _required <= _owners.length, "BAD_CONFIG"); for (uint256 i = 0; i < _owners.length; i++) { require(_owners[i] != address(0) && !isOwner[_owners[i]], "BAD_OWNER"); isOwner[_owners[i]] = true; } owners = _owners; required = _required; } function submit(address to, uint256 value, bytes calldata data) external onlyOwner returns (uint256) { txs.push(Tx(to, value, data, false, 0)); uint256 id = txs.length - 1; emit Submit(id); return id; } function confirm(uint256 id) external onlyOwner { require(!confirmed[id][msg.sender], "ALREADY"); confirmed[id][msg.sender] = true; txs[id].confirmations++; emit Confirm(msg.sender, id); } function execute(uint256 id) external onlyOwner { Tx storage t = txs[id]; require(t.confirmations >= required && !t.executed, "NOT_READY"); t.executed = true; (bool ok, ) = t.to.call{value: t.value}(t.data); require(ok, "CALL_FAILED"); emit Execute(id); } receive() external payable {}}