1

I am trying to implement multisig wallet, where one contract address is set as a wallet with multiple owners. I want to show multisig transactions on MetaMask. Is it possible to do that? My contract is added below. I am using a private network.

pragma solidity ^0.4.20;

interface tokenInterface {
    function transfer(address reciever, uint amount) external;
    function balanceOf(address owner) external returns (uint256);
}

contract dapMultisig {

    /*
    * Types
    */
    struct Transaction {
        uint id;
        address destination;
        uint value;
        bytes data;
        TxnStatus status;
        address[] confirmed;
        address creator;
    }

    struct tokenTransaction {
        uint id;
        tokenInterface token;
        address reciever;
        uint value;
        address[] confirmed;
        TxnStatus status;
        address creator;
    }

    struct Log {
        uint amount;
        address sender;
    }

    enum TxnStatus { Unconfirmed, Pending, Executed }

    /*
    * Modifiers
    */
    modifier onlyOwner () {
        bool found;
        for (uint i = 0;i<owners.length;i++){
            if (owners[i] == msg.sender){
                found = true;
            }
        }
        if (found){
            _;
        }
    }

    /*
    * Events
    */
    event WalletCreated(address creator, address[] owners);
    event TxnSumbitted(uint id, uint value);
    event TxnConfirmed(uint id, uint len);
    event TxnExecuted(TxnStatus status, uint amt);
    event topUpBalance(uint value);
    event LogAmount(uint256 value);
    event tokenTxnConfirmed(uint id, address owner);
    event tokenTxnExecuted(address token, uint256 value, address reciever);
    /*
    * Storage
    */
    bytes32 public name;
    address public creator;
    uint public allowance;
    address[] public owners;
    Log[] logs;
    Transaction[] transactions;
    tokenTransaction[] tokenTransactions;
    uint public approvalsreq;


    function createWallet(uint _approvals, address[] _owners, bytes32 _name) public payable {
        name = _name;
        creator = msg.sender;
        allowance = msg.value;
        owners = _owners;
        approvalsreq = _approvals;
        emit WalletCreated(msg.sender, _owners);
    }

    function getBalance() public view returns (uint256) {
        return address(this).balance;
    }
    /*
    * Getters
    */

    function getOwners() external view returns (address[]){
        return owners;
    }

    function getTxnNum() external view returns (uint){
        return transactions.length;
    }

    function getTxn(uint _id) external view returns (uint, address, uint, bytes, TxnStatus, address[], address){
        Transaction storage txn = transactions[_id];
        return (txn.id, txn.destination, txn.value, txn.data, txn.status, txn.confirmed, txn.creator);
    }

    function getLogsNum() external view returns (uint){
        return logs.length;
    }

    function getLog(uint logId) external view returns (address, uint){
        return(logs[logId].sender, logs[logId].amount);
    }

    function getTokenTxnNum() external view returns (uint){
        return tokenTransactions.length;
    }

    function getTokenTxn(uint _id) external view returns(uint, address, address, uint256, address[], TxnStatus, address){
        tokenTransaction storage txn = tokenTransactions[_id];
        return (txn.id, txn.token, txn.reciever, txn.value, txn.confirmed, txn.status, txn.creator);
    }

    /*
    * Methods
    */

    function topBalance() external payable {
        require (msg.value > 0 wei);
        allowance += msg.value;

        /* create new log entry */
        uint loglen = logs.length++;
        logs[loglen].amount = msg.value;
        logs[loglen].sender = msg.sender;
        emit topUpBalance(msg.value);
    }

    function submitTransaction(address _destination, uint _value, bytes _data) external payable returns (bool) {
        uint newTxId = transactions.length++;
        transactions[newTxId].id = newTxId;
        transactions[newTxId].destination = _destination;
        transactions[newTxId].value = _value*1000000000000000000;
        transactions[newTxId].data = _data;
        transactions[newTxId].creator = msg.sender;
        if (transactions[newTxId].confirmed.length == approvalsreq){
            transactions[newTxId].status = TxnStatus.Pending;
        }
        emit TxnSumbitted(newTxId,_value);
        return true;
    }

    function confirmTransaction(uint txId) onlyOwner() external payable returns (bool){
        Transaction storage txn = transactions[txId];

        //check whether this owner has already confirmed this txn
        bool f;
        for (uint8 i = 0; i<txn.confirmed.length;i++){
            if (txn.confirmed[i] == msg.sender){
                f = true;
            }
        }
        //push sender address into confirmed array if haven't found
        require(!f);
        txn.confirmed.push(msg.sender);

        if (txn.confirmed.length == approvalsreq){
            txn.status = TxnStatus.Pending;
            require(txn.status == TxnStatus.Pending);

        /* check whether wallet has sufficient balance to send this transaction */
            require(allowance >= txn.value);

        /* send transaction */
            address dest = txn.destination;
            uint val = txn.value;
            bytes storage dat = txn.data;
            assert(dest.call.value(val)(dat));

        /* change transaction's status to executed */
            txn.status = TxnStatus.Executed;

        /* change wallet's balance */
            allowance = allowance - txn.value;
            emit TxnExecuted(txn.status,allowance);
            return true;
        }

        //fire event
        emit TxnConfirmed(txId,txn.confirmed.length);

        return true;
    }

    // token transactions
    function submitTokenTransaction(address _tokenAddress, address _receiever, uint _value) onlyOwner() external returns (bool) {
        uint newTxId = tokenTransactions.length++;
        tokenTransactions[newTxId].id = newTxId;
        tokenTransactions[newTxId].token = tokenInterface(_tokenAddress);
        tokenTransactions[newTxId].reciever = _receiever;
        tokenTransactions[newTxId].value = _value;
        tokenTransactions[newTxId].confirmed.push(msg.sender);
        if (tokenTransactions[newTxId].confirmed.length == approvalsreq){
            tokenTransactions[newTxId].status = TxnStatus.Pending;
        }
        emit TxnSumbitted(newTxId,_value);
        return true;
    }

    function confirmTokenTransaction(uint txId) onlyOwner() external returns (bool){
        tokenTransaction storage txn = tokenTransactions[txId];

        //check whether this owner has already confirmed this txn
        bool f;
        for (uint8 i = 0; i<txn.confirmed.length;i++){
            if (txn.confirmed[i] == msg.sender){
                f = true;
            }
        }
        //push sender address into confirmed array if haven't found
        require(!f);
        txn.confirmed.push(msg.sender);

        if (txn.confirmed.length == approvalsreq){
            txn.status = TxnStatus.Pending;
        }

        //fire event
        emit tokenTxnConfirmed(txId, msg.sender);

        return true;
    }

    function executeTokenTxn(uint txId) onlyOwner() external returns (bool){

        tokenTransaction storage txn = tokenTransactions[txId];

        /* check txn status */
        require(txn.status == TxnStatus.Pending);

        /* check whether wallet has sufficient balance to send this transaction */
        uint256 balance = txn.token.balanceOf(address(this));
        require (txn.value <= balance);

        /* Send tokens */
        txn.token.transfer(txn.reciever, txn.value);

        /* change transaction's status to executed */
        txn.status = TxnStatus.Executed;

        /* Fire event */
        emit tokenTxnExecuted(address(txn.token), txn.value, txn.reciever);

        return true;
    }
}
0

No, it is not possible to do it at this time.

MetaMask only allows an interface for wallets, as opposed to contracts. While your contract may behave similarly to a wallet, MetaMask does not have an interface to show the actions of the contract.

This would be difficult to do, seeing as there are a number of bespoke multisigs, and providing an interface for them all would be daunting.

Your best bet is to write your own custom interface for the contract itself and allow your users to use this interface rather than rely on MetaMask.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.