Skip to content

Latest commit

 

History

History
1047 lines (841 loc) · 27.8 KB

MultiSigWallet.md

File metadata and controls

1047 lines (841 loc) · 27.8 KB

Multisignature wallet - Allows multiple parties to agree on

transactions before execution.

  • (MultiSigWallet.sol)

View Source: contracts/multisig/MultiSigWallet.sol

MultiSigWallet contract

Structs

Transaction

struct Transaction {
 address destination,
 uint256 value,
 bytes data,
 bool executed
}

Contract Members

Constants & Variables

uint256 public constant MAX_OWNER_COUNT;
mapping(uint256 => struct MultiSigWallet.Transaction) public transactions;
mapping(uint256 => mapping(address => bool)) public confirmations;
mapping(address => bool) public isOwner;
address[] public owners;
uint256 public required;
uint256 public transactionCount;

Events

event Confirmation(address indexed sender, uint256 indexed transactionId);
event Revocation(address indexed sender, uint256 indexed transactionId);
event Submission(uint256 indexed transactionId);
event Execution(uint256 indexed transactionId);
event ExecutionFailure(uint256 indexed transactionId);
event Deposit(address indexed sender, uint256  value);
event OwnerAddition(address indexed owner);
event OwnerRemoval(address indexed owner);
event RequirementChange(uint256  required);

Modifiers

onlyWallet

modifier onlyWallet() internal

ownerDoesNotExist

modifier ownerDoesNotExist(address owner) internal

Arguments

Name Type Description
owner address

ownerExists

modifier ownerExists(address owner) internal

Arguments

Name Type Description
owner address

transactionExists

modifier transactionExists(uint256 transactionId) internal

Arguments

Name Type Description
transactionId uint256

confirmed

modifier confirmed(uint256 transactionId, address owner) internal

Arguments

Name Type Description
transactionId uint256
owner address

notConfirmed

modifier notConfirmed(uint256 transactionId, address owner) internal

Arguments

Name Type Description
transactionId uint256
owner address

notExecuted

modifier notExecuted(uint256 transactionId) internal

Arguments

Name Type Description
transactionId uint256

notNull

modifier notNull(address _address) internal

Arguments

Name Type Description
_address address

validRequirement

modifier validRequirement(uint256 ownerCount, uint256 _required) internal

Arguments

Name Type Description
ownerCount uint256
_required uint256

Functions


constructor

Fallback function allows to deposit ether.

function () external payable
Source Code
function() external payable {
        if (msg.value > 0) emit Deposit(msg.sender, msg.value);
    }

constructor

Contract constructor sets initial owners and required number of confirmations. *

function (address[] _owners, uint256 _required) public nonpayable validRequirement 

Arguments

Name Type Description
_owners address[] List of initial owners.
_required uint256 Number of required confirmations.
Source Code
constructor(address[] memory _owners, uint256 _required)
        public
        validRequirement(_owners.length, _required)
    {
        for (uint256 i = 0; i < _owners.length; i++) {
            require(!isOwner[_owners[i]] && _owners[i] != address(0));
            isOwner[_owners[i]] = true;
        }
        owners = _owners;
        required = _required;
    }

addOwner

Allows to add a new owner. Transaction has to be sent by wallet.

function addOwner(address owner) public nonpayable onlyWallet ownerDoesNotExist notNull validRequirement 

Arguments

Name Type Description
owner address Address of new owner.
Source Code
function addOwner(address owner)
        public
        onlyWallet
        ownerDoesNotExist(owner)
        notNull(owner)
        validRequirement(owners.length + 1, required)
    {
        isOwner[owner] = true;
        owners.push(owner);
        emit OwnerAddition(owner);
    }

removeOwner

Allows to remove an owner. Transaction has to be sent by wallet.

function removeOwner(address owner) public nonpayable onlyWallet ownerExists 

Arguments

Name Type Description
owner address Address of owner.
Source Code
function removeOwner(address owner) public onlyWallet ownerExists(owner) {
        isOwner[owner] = false;
        for (uint256 i = 0; i < owners.length - 1; i++)
            if (owners[i] == owner) {
                owners[i] = owners[owners.length - 1];
                break;
            }
        owners.length -= 1;
        if (required > owners.length) changeRequirement(owners.length);
        emit OwnerRemoval(owner);
    }

replaceOwner

Allows to replace an owner with a new owner. Transaction has to be sent by wallet. *

function replaceOwner(address owner, address newOwner) public nonpayable onlyWallet ownerExists ownerDoesNotExist 

Arguments

Name Type Description
owner address Address of owner to be replaced.
newOwner address Address of new owner.
Source Code
function replaceOwner(address owner, address newOwner)
        public
        onlyWallet
        ownerExists(owner)
        ownerDoesNotExist(newOwner)
    {
        for (uint256 i = 0; i < owners.length; i++)
            if (owners[i] == owner) {
                owners[i] = newOwner;
                break;
            }
        isOwner[owner] = false;
        isOwner[newOwner] = true;
        emit OwnerRemoval(owner);
        emit OwnerAddition(newOwner);
    }

changeRequirement

Allows to change the number of required confirmations. Transaction has to be sent by wallet. *

function changeRequirement(uint256 _required) public nonpayable onlyWallet validRequirement 

Arguments

Name Type Description
_required uint256 Number of required confirmations.
Source Code
function changeRequirement(uint256 _required)
        public
        onlyWallet
        validRequirement(owners.length, _required)
    {
        required = _required;
        emit RequirementChange(_required);
    }

submitTransaction

Allows an owner to submit and confirm a transaction. *

function submitTransaction(address destination, uint256 value, bytes data) public nonpayable
returns(transactionId uint256)

Arguments

Name Type Description
destination address Transaction target address.
value uint256 Transaction ether value.
data bytes Transaction data payload. *

Returns

Returns transaction ID.

Source Code
function submitTransaction(
        address destination,
        uint256 value,
        bytes memory data
    ) public returns (uint256 transactionId) {
        transactionId = addTransaction(destination, value, data);
        confirmTransaction(transactionId);
    }

confirmTransaction

Allows an owner to confirm a transaction.

function confirmTransaction(uint256 transactionId) public nonpayable ownerExists transactionExists notConfirmed 

Arguments

Name Type Description
transactionId uint256 Transaction ID.
Source Code
function confirmTransaction(uint256 transactionId)
        public
        ownerExists(msg.sender)
        transactionExists(transactionId)
        notConfirmed(transactionId, msg.sender)
    {
        confirmations[transactionId][msg.sender] = true;
        emit Confirmation(msg.sender, transactionId);
        executeTransaction(transactionId);
    }

revokeConfirmation

Allows an owner to revoke a confirmation for a transaction.

function revokeConfirmation(uint256 transactionId) public nonpayable ownerExists confirmed notExecuted 

Arguments

Name Type Description
transactionId uint256 Transaction ID.
Source Code
function revokeConfirmation(uint256 transactionId)
        public
        ownerExists(msg.sender)
        confirmed(transactionId, msg.sender)
        notExecuted(transactionId)
    {
        confirmations[transactionId][msg.sender] = false;
        emit Revocation(msg.sender, transactionId);
    }

executeTransaction

Allows anyone to execute a confirmed transaction.

function executeTransaction(uint256 transactionId) public nonpayable ownerExists confirmed notExecuted 

Arguments

Name Type Description
transactionId uint256 Transaction ID.
Source Code
function executeTransaction(uint256 transactionId)
        public
        ownerExists(msg.sender)
        confirmed(transactionId, msg.sender)
        notExecuted(transactionId)
    {
        if (isConfirmed(transactionId)) {
            Transaction storage txn = transactions[transactionId];
            txn.executed = true;
            if (external_call(txn.destination, txn.value, txn.data.length, txn.data))
                emit Execution(transactionId);
            else {
                emit ExecutionFailure(transactionId);
                txn.executed = false;
            }
        }
    }

external_call

Low level transaction execution. *

function external_call(address destination, uint256 value, uint256 dataLength, bytes data) internal nonpayable
returns(bool)

Arguments

Name Type Description
destination address The address of the Smart Contract to call.
value uint256 The amout of rBTC to send w/ the transaction.
dataLength uint256 The size of the payload.
data bytes Length The size of the payload.

Returns

Success or failure.

Source Code
function external_call(
        address destination,
        uint256 value,
        uint256 dataLength,
        bytes memory data
    ) internal returns (bool) {
        bool result;
        assembly {
            let x := mload(0x40) /// "Allocate" memory for output (0x40 is where "free memory" pointer is stored by convention)
            let d := add(data, 32) /// First 32 bytes are the padded length of data, so exclude that
            result := call(
                sub(gas, 34710), /// 34710 is the value that solidity is currently emitting
                /// It includes callGas (700) + callVeryLow (3, to pay for SUB) + callValueTransferGas (9000) +
                /// callNewAccountGas (25000, in case the destination address does not exist and needs creating)
                destination,
                value,
                d,
                dataLength, /// Size of the input (in bytes) - this is what fixes the padding problem
                x,
                0 /// Output is ignored, therefore the output size is zero
            )
        }
        return result;
    }

isConfirmed

Returns the confirmation status of a transaction.

function isConfirmed(uint256 transactionId) public view
returns(bool)

Arguments

Name Type Description
transactionId uint256 Transaction ID.

Returns

Confirmation status.

Source Code
function isConfirmed(uint256 transactionId) public view returns (bool) {
        uint256 count = 0;
        for (uint256 i = 0; i < owners.length; i++) {
            if (confirmations[transactionId][owners[i]]) count += 1;
            if (count == required) return true;
        }

        return false;
    }

addTransaction

Adds a new transaction to the transaction mapping, if transaction does not exist yet. *

function addTransaction(address destination, uint256 value, bytes data) internal nonpayable notNull 
returns(transactionId uint256)

Arguments

Name Type Description
destination address Transaction target address.
value uint256 Transaction ether value.
data bytes Transaction data payload. *

Returns

Returns transaction ID.

Source Code
function addTransaction(
        address destination,
        uint256 value,
        bytes memory data
    ) internal notNull(destination) returns (uint256 transactionId) {
        transactionId = transactionCount;
        transactions[transactionId] = Transaction({
            destination: destination,
            value: value,
            data: data,
            executed: false
        });
        transactionCount += 1;
        emit Submission(transactionId);
    }

getConfirmationCount

Get the number of confirmations of a transaction.

function getConfirmationCount(uint256 transactionId) public view
returns(count uint256)

Arguments

Name Type Description
transactionId uint256 Transaction ID.

Returns

Number of confirmations.

Source Code
function getConfirmationCount(uint256 transactionId) public view returns (uint256 count) {
        for (uint256 i = 0; i < owners.length; i++)
            if (confirmations[transactionId][owners[i]]) count += 1;
    }

getTransactionCount

Get the total number of transactions after filers are applied.

function getTransactionCount(bool pending, bool executed) public view
returns(count uint256)

Arguments

Name Type Description
pending bool Include pending transactions.
executed bool Include executed transactions.

Returns

Total number of transactions after filters are applied.

Source Code
function getTransactionCount(bool pending, bool executed) public view returns (uint256 count) {
        for (uint256 i = 0; i < transactionCount; i++)
            if ((pending && !transactions[i].executed) || (executed && transactions[i].executed))
                count += 1;
    }

getOwners

Get the list of owners.

function getOwners() public view
returns(address[])
Source Code
function getOwners() public view returns (address[] memory) {
        return owners;
    }

getConfirmations

Get the array with owner addresses, which confirmed transaction.

function getConfirmations(uint256 transactionId) public view
returns(_confirmations address[])

Arguments

Name Type Description
transactionId uint256 Transaction ID.

Returns

Returns array of owner addresses.

Source Code
function getConfirmations(uint256 transactionId)
        public
        view
        returns (address[] memory _confirmations)
    {
        address[] memory confirmationsTemp = new address[](owners.length);
        uint256 count = 0;
        uint256 i;
        for (i = 0; i < owners.length; i++)
            if (confirmations[transactionId][owners[i]]) {
                confirmationsTemp[count] = owners[i];
                count += 1;
            }
        _confirmations = new address[](count);
        for (i = 0; i < count; i++) _confirmations[i] = confirmationsTemp[i];
    }

getTransactionIds

Get the list of transaction IDs in defined range. *

function getTransactionIds(uint256 from, uint256 to, bool pending, bool executed) public view
returns(_transactionIds uint256[])

Arguments

Name Type Description
from uint256 Index start position of transaction array.
to uint256 Index end position of transaction array.
pending bool Include pending transactions.
executed bool Include executed transactions. *

Returns

Returns array of transaction IDs.

Source Code
function getTransactionIds(
        uint256 from,
        uint256 to,
        bool pending,
        bool executed
    ) public view returns (uint256[] memory _transactionIds) {
        uint256[] memory transactionIdsTemp = new uint256[](transactionCount);
        uint256 count = 0;
        uint256 i;
        for (i = 0; i < transactionCount; i++)
            if ((pending && !transactions[i].executed) || (executed && transactions[i].executed)) {
                transactionIdsTemp[count] = i;
                count += 1;
            }
        _transactionIds = new uint256[](to - from);
        for (i = from; i < to; i++) _transactionIds[i - from] = transactionIdsTemp[i];
    }

Contracts