🔮
Ethereum
  • General
    • What is Ethereum
      • Ethereum & Bitcoin General Comparison
      • Singleton State
      • The Ethereum Virtual Machine (EVM)
      • Opcodes (operation codes) EVM
      • Ethereum Client
      • Forks
      • Gas (wei)
        • EIP-1559
        • Table Conversion (wei)
      • Proof of Stake (PoS)
      • Proof of Authority (PoA)
      • The Beacon Chain
      • Networks
        • Ethereum mainnet
        • Goerli
      • Account-based model & UTXO-based model
      • Externally Owned Account (EOA)
      • Node Clients
        • Geth
        • Nethermind
      • Contract Account
      • Smart Contract Upgradeability
      • Ultrasound Money
      • Merkle Trees
        • Patricia Merkle Tree
      • Tries
        • State Trie
        • Storage Trie
        • Transactions Trie
        • Receipts Trie
      • Transactions
        • Ethereum Transaction Architecture
      • World State
        • Chain of States
        • Chain of Blocks
        • Stack of Transactions / Mempool
      • Contract Creation
      • Message Call Transaction
      • P2P Network
      • Web3.js
      • Ether.js
        • Smart Contract Interaction Example
      • Web3.js vs Ether.js
      • Node Providers
      • ENS (Ethereum Name Service)
      • Web3 dapp
      • Escrow
      • Multi-signature
      • ERC-20 tokens
        • Send ERC20s to Contracts
      • NFTs
        • ERC-721 and ERC-1155
      • Solidity
        • State Variables
        • Data Location
        • Numbers
        • Modifiers
        • View & Pure Modifiers
        • Data Types
          • Modifiers
          • Modifiers (Functions)
          • Address & Address Payable
        • Hardhat
        • Payable Functions
        • Receive Function
        • Fallback Function
        • Global Variables
        • Self Destruct
        • Create2 Function
        • Revert function
        • Require function
        • Assert Function
        • Calldata
        • Interface
        • Mapping
        • Array
        • Struct
        • Inheritance
          • Virtual & Overwrite
          • Multiple inheritance
          • Hierarchical Inheritance
        • Events
          • Indexed (keyword)
          • LOG0 - LOG4
        • Multi-signature Example
        • Smart Contracts
          • Context
      • Application Binary Interface (ABI )
  • Extras
    • Terminology
      • Bytecode
      • Keccak-256
      • Turing complete
Powered by GitBook
On this page
  • Intro
  • Example
  1. General
  2. What is Ethereum
  3. Solidity

Multi-signature Example

PreviousLOG0 - LOG4NextSmart Contracts

Last updated 2 years ago

Intro

Example

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract MultiSigWallet {
    address[] public owners;
    uint public numConfirmationsRequired;

    struct Transaction {
        address to;
        uint value;
        bytes data;
        bool executed;
        uint numConfirmations;
    }

    mapping(uint => mapping(address => bool)) public confirmations;
    mapping(uint => Transaction) public transactions;
    uint public transactionCount;

    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++) {
            require(_owners[i] != address(0), "Invalid owner");
            for (uint j = i + 1; j < _owners.length; j++) {
                require(_owners[i] != _owners[j], "Duplicate owner");
            }
            owners.push(_owners[i]);
        }
        numConfirmationsRequired = _numConfirmationsRequired;
    }

    function addTransaction(address _to, uint _value, bytes memory _data)
        public
        returns (uint)
    {
        uint transactionId = transactionCount;
        transactions[transactionId] = Transaction({
            to: _to,
            value: _value,
            data: _data,
            executed: false,
            numConfirmations: 0
        });
        transactionCount++;
        return transactionId;
    }

    function confirmTransaction(uint _transactionId) public {
        require(confirmations[_transactionId][msg.sender] == false, "Transaction already confirmed");
        require(transactions[_transactionId].executed == false, "Transaction already executed");

        confirmations[_transactionId][msg.sender] = true;
        transactions[_transactionId].numConfirmations++;

        if (transactions[_transactionId].numConfirmations >= numConfirmationsRequired) {
            executeTransaction(_transactionId);
        }
    }

    function executeTransaction(uint _transactionId) public {
        require(transactions[_transactionId].executed == false, "Transaction already executed");

        if (isConfirmed(_transactionId)) {
            Transaction storage transaction = transactions[_transactionId];
            transaction.executed = true;
            (bool success, ) = transaction.to.call{value: transaction.value}(transaction.data);
            require(success, "Transaction failed");
        }
    }

    function isConfirmed(uint _transactionId) public view returns (bool) {
        uint count = 0;
        for (uint i = 0; i < owners.length; i++) {
            if (confirmations[_transactionId][owners[i]]) {
                count++;
            }
            if (count == numConfirmationsRequired) {
                return true;
            }
        }
        return false;
    }
}

In this contract, multiple owners are able to create and confirm transactions before they can be executed. The contract stores the list of owners, the number of required confirmations, and each transaction's data. It also keeps track of which transactions have been confirmed and executed. To create a transaction, an owner calls the addTransaction function, which creates a new transaction with the provided information. Owners can then confirm the transaction using the confirmTransaction function. Once the required number of confirmations has been reached, any owner can execute the transaction by calling the executeTransaction function. The isConfirmed function is used to check whether a transaction has been confirmed by the required number of owners.

GitBook
Logo