# MultiSig Wallet

By [gachengoh](https://paragraph.com/@gachengoh) · 2022-12-04

---

*   This post is implementing a multisig wallet in solidity,where there must be a number of people to authorize transfer of funds from the wallet.
    

    // SPDX-License-Identifier: GPL-3.0
    
    pragma solidity >=0.7.0 <0.9.0;
    
    contract MultisigWallet {
    
        event Deposit (address indexed sender,uint amount,uint balance);
        event SubmitingTransaction(address indexed owner, uint indexed txIndex, address indexed to, uint value, bytes data);
        event ConfirmingTransaction( address indexed owner, uint indexed txIndex);
        event RevokingConfirmation(address indexed owner, uint indexed txIndex);
        event ExecutingTransaction(address indexed owner, uint indexed txIndex);
    
        //State Variables.
        address[] public owners;
        mapping(address => bool) public isOwner;
        uint public numConfirmationsRequired;
    
        struct Transaction {
            address to;
            uint value;
            bytes data;
            bool executed;
            uint numConfirmations;
        }
        Transaction [] public transactions;
    
        // mapping from tx index => owner => bool
        mapping(uint => mapping(address => bool)) public isConfirmed;
    
        constructor(address [] memory _owners, uint _numConfirmationsRequired)  {
            require(_owners.length > 0,"Owners Required");
            require(_numConfirmationsRequired > 0 && _numConfirmationsRequired <= _owners.length, "Invalid number of required Confirmations");
    
            for (uint i = 0; i < _owners.length; i++){
                address owner = _owners[i];
    
                require(owner != address(0), "invalid Owner");
                require(!isOwner[owner], "Owner is not unique");
    
                isOwner[owner] = true;
                owners.push(owner);
            }
    
            numConfirmationsRequired = _numConfirmationsRequired;
        }
    
        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, "Transactions already executed");
            _;
        }
    
        modifier notconfirmed(uint _txIndex){
            require(!isConfirmed[_txIndex][msg.sender], "tx already confirmed");
            _;
        }
    
        receive() external payable {
            emit Deposit(msg.sender, msg.value, address(this).balance);
        }
    
        function deposit() external payable {
            emit Deposit (msg.sender,msg.value,address(this).balance);
        }
    
        function submitTransaction(address _to, uint _value, bytes memory _data) public onlyOwner {
    
            uint txIndex = transactions.length;
            transactions.push(Transaction({
                to: _to,
                value: _value,
                data: _data,
                executed: false,
                numConfirmations: 0
            }));
            emit SubmitingTransaction(msg.sender, txIndex, _to, _value, _data);
        }
        function confirmTransaction(uint _txIndex) public onlyOwner txExists(_txIndex) notExecuted(_txIndex) notconfirmed(_txIndex){
    
            Transaction storage transaction = transactions[_txIndex];
            isConfirmed[_txIndex][msg.sender] = true;
            transaction.numConfirmations += 1;
    
            emit ConfirmingTransaction( msg.sender, _txIndex);
        }
        function executeTransaction(uint _txIndex) public onlyOwner txExists(_txIndex) notExecuted(_txIndex) {
    
            Transaction storage transaction = transactions[_txIndex];
            require(transaction.numConfirmations >= numConfirmationsRequired,"Cannot Execute Transaction");
    
            transaction.executed = true;
            (bool success,) = transaction.to.call{value: transaction.value}(transaction.data);
            require(success, "tx failed");
    
            emit ExecutingTransaction(msg.sender, _txIndex);
    
        }
        function revokeConfirmation(uint _txIndex) public onlyOwner txExists(_txIndex) notExecuted(_txIndex){
    
            Transaction storage transaction = transactions [_txIndex];
            require(isConfirmed[_txIndex][msg.sender], "Transaction not confirmed");
    
            transaction.numConfirmations -= 1;
            isConfirmed[_txIndex][msg.sender] = false;
    
            emit RevokingConfirmation(msg.sender, _txIndex);
        }
        
        function getOwners() public view returns (address[] memory) {
            return owners;
        }
        function getTransactionCount() public view returns (uint) {
            return transactions.length;
        }
    }

---

*Originally published on [gachengoh](https://paragraph.com/@gachengoh/multisig-wallet)*
