2

I have a 1.5 years old multisig wallet contract. I am able to import it to Ethereum Wallet (version 0.11.1) through Contracts -> Watch Contract menu and that way I can run some functions on it ("Add owner", "Execute", etc.). After reading the contract code, it would appear that "Execute" is the function that is used to transfer Ether out of the contract. I'm quite hesitant to use it, though.

"Execute" takes three parameters, address, value and data. Is it safe to leave data empty? And is the unit of value wei or ETH? In the contract there is daily limit of 100000000000000000000000000(!). I assume this is wei, which would mean it's 100 million ETH. The contract also has multiple security warnings on it, if there's something there I should take into account, i'd be supper happy to know.

Any help is appreciated! Here's the contract info: https://etherscan.io/address/0x5248e5fd5d3b43126e5352807f75d6a7d6d7eafb

SOLVED

The solution in this case turned out to be pretty simple. After syncing geth (fastsync) I was able to import wallet contract by using older version of Ethereum Wallet (0.8.9).

See also this issue: https://github.com/ethereum/mist/issues/4032

12
  • Where's the code??? Dec 12, 2018 at 10:27
  • Well it's here. Dec 12, 2018 at 10:28
  • It looks like function execute merely performs dynamic invoking, i.e., it takes byte-code as input (bytes _data) and executes it. This doesn't have anything to do with withdrawing ether from the contract, and as a matter of fact, since none of the functions in this contract is payable, I doubt that there is any ether in it to begin with. Is it possible that the ether funds that you refer to are actually located in a contract owned by this MultiSigWalllet contract (whose functions can be executed only by the authorized signers of this MultiSigWalllet contract)? Dec 12, 2018 at 10:33
  • Thank you for the answer! If there is another contract owned by this contract, I wonder how can I find it. As the Internal Txns show, i have been able to move funds from the contract before. In previous versions of Ethereum Wallet I could simply import the contract and there was user friendly UI on transacting the funds.
    – JussiR
    Dec 12, 2018 at 11:27
  • If it helps, i can add monetary bounty for successful retrievement of funds from the contract. Lets start with 0.5 ETH.
    – JussiR
    Dec 12, 2018 at 11:29

1 Answer 1

1
+50

Here is an answer that I'm completely unsure of, so wait for some responses before you try it...

Implement, compile and deploy the follow contract:

pragma solidity 0.4.24;

contract MyContract {
    address public myWallet;

    constructor() public {
        myWallet = msg.sender;
    }

    function() public payable {
        myWallet.transfer(address(this).balance);
    }
}

Then, from the off-chain, call function execute with the address of this contract and the value that you want to withdraw. Needless to say, all amounts are always in WEI.

Here is a web3.js-v1 example:

let fs = require("fs");
let Web3 = require("web3");
let web3 = new Web3(NODE_ADDRESS);

function deployed(contractName, contractAddr) {
    let abi = fs.readFileSync(contractName + ".abi").toString();
    return new web3.eth.Contract(JSON.parse(abi), contractAddr);
}

async function send(transaction) {
    let block = await web3.eth.getBlock("latest");
    let options = {
        to  : transaction._parent._address,
        data: transaction.encodeABI(),
        gas : block.gasLimit
    };
    let signedTransaction = await web3.eth.accounts.signTransaction(options, PRIVATE_KEY);
    return await web3.eth.sendSignedTransaction(signedTransaction.rawTransaction);
}

async function withdraw(amount) {
    let multiOwned = deployed("MultiOwned", "0x5248e5fd5d3b43126e5352807f75d6a7d6d7eafb");
    let myContract = deployed("MyContract", "0xThePublicAddressOfMyContractOnTheMainNet");
    let receipt = await send(multiOwned.methods.execute(myContract._address, amount, []));
    console.log(JSON.stringify(receipt, null, 4));
}

Like I said, I'm unsure of this answer, so wait for some comments, feedback and suggestions...


UPDATE:

You can withdraw your funds with a few modifications to the code above.

Step #1 - create a file called withdraw.js with the following contents:

// These parameters serve as an example:
let ETH_NODE_ADDRESS    = "http://localhost:8545";
let WITHDRAW_WEI_AMOUNT = "1000000000000000000"; // 1 ether
let WALLET_PUBLIC_ADDR  = "0x7e5f4552091a69125d5dfcb7b8c2659029395bdf";
let WALLET_PRIVATE_KEY  = "0000000000000000000000000000000000000000000000000000000000000001";
let REQUIRED_CONFIRMS   = 3;
let SIGNER_PRIVATE_KEYS = [
    "0000000000000000000000000000000000000000000000000000000000000002",
    "0000000000000000000000000000000000000000000000000000000000000003",
    "0000000000000000000000000000000000000000000000000000000000000004",
    "0000000000000000000000000000000000000000000000000000000000000005",
];


let MS_CONTRACT_ADDR = "0x5248e5fd5d3b43126e5352807f75d6a7d6d7eafb";
let MS_CONTRACT_ABI  = '[{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"removeOwner","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_addr","type":"address"}],"name":"isOwner","outputs":[{"name":"","type":"bool"}],"type":"function"},{"constant":true,"inputs":[],"name":"m_numOwners","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"m_lastDay","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[],"name":"resetSpentToday","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"m_spentToday","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"addOwner","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"m_required","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"_h","type":"bytes32"}],"name":"confirm","outputs":[{"name":"","type":"bool"}],"type":"function"},{"constant":false,"inputs":[{"name":"_newLimit","type":"uint256"}],"name":"setDailyLimit","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"},{"name":"_data","type":"bytes"}],"name":"execute","outputs":[{"name":"_r","type":"bytes32"}],"type":"function"},{"constant":false,"inputs":[{"name":"_operation","type":"bytes32"}],"name":"revoke","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_newRequired","type":"uint256"}],"name":"changeRequirement","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"_operation","type":"bytes32"},{"name":"_owner","type":"address"}],"name":"hasConfirmed","outputs":[{"name":"","type":"bool"}],"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"}],"name":"kill","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"}],"name":"changeOwner","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"m_dailyLimit","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"inputs":[{"name":"_owners","type":"address[]"},{"name":"_required","type":"uint256"},{"name":"_daylimit","type":"uint256"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"operation","type":"bytes32"}],"name":"Confirmation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"operation","type":"bytes32"}],"name":"Revoke","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"oldOwner","type":"address"},{"indexed":false,"name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newOwner","type":"address"}],"name":"OwnerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"oldOwner","type":"address"}],"name":"OwnerRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newRequirement","type":"uint256"}],"name":"RequirementChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"from","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"value","type":"uint256"},{"indexed":false,"name":"to","type":"address"},{"indexed":false,"name":"data","type":"bytes"}],"name":"SingleTransact","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"operation","type":"bytes32"},{"indexed":false,"name":"value","type":"uint256"},{"indexed":false,"name":"to","type":"address"},{"indexed":false,"name":"data","type":"bytes"}],"name":"MultiTransact","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"operation","type":"bytes32"},{"indexed":false,"name":"initiator","type":"address"},{"indexed":false,"name":"value","type":"uint256"},{"indexed":false,"name":"to","type":"address"},{"indexed":false,"name":"data","type":"bytes"}],"name":"ConfirmationNeeded","type":"event"}]';
let MY_CONTRACT_ABI  = '[{"constant":true,"inputs":[],"name":"myWallet","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"}]';
let MY_CONTRACT_BIN  = "0x608060405234801561001057600080fd5b5060008054600160a060020a0319163317905561010b806100326000396000f300608060405260043610603e5763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663b880b69a81146088575b6000805460405173ffffffffffffffffffffffffffffffffffffffff90911691303180156108fc02929091818181858888f193505050501580156085573d6000803e3d6000fd5b50005b348015609357600080fd5b50609a60c3565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b60005473ffffffffffffffffffffffffffffffffffffffff16815600a165627a7a72305820b8ebc070e327daa9cddc13ee6bd5b4035c70358eaaeaf527728c3c5f5c61806d0029";


let Web3 = require("web3");
let web3 = new Web3(ETH_NODE_ADDRESS);


function deployed(abi, address) {
    return new web3.eth.Contract(JSON.parse(abi), address);
}


async function deploy(abi, bin, args, key) {
    let contract = new web3.eth.Contract(JSON.parse(abi));
    let handle = await send(contract.deploy({data: bin, arguments: args}), key);
    return new web3.eth.Contract(JSON.parse(abi), handle.contractAddress);
}


async function send(transaction, key) {
    let block = await web3.eth.getBlock("latest");
    let options = {
        to  : transaction._parent._address,
        data: transaction.encodeABI(),
        gas : block.gasLimit
    };
    let signedTransaction = await web3.eth.accounts.signTransaction(options, key);
    return await web3.eth.sendSignedTransaction(signedTransaction.rawTransaction);
}


async function withdraw() {
    let msContract = deployed(MS_CONTRACT_ABI, MS_CONTRACT_ADDR);
    let myContract = await deploy(MY_CONTRACT_ABI, MY_CONTRACT_BIN, [], WALLET_PRIVATE_KEY);
    let balanceBefore = await web3.eth.getBalance(WALLET_PUBLIC_ADDR);
    for (let i = 0; i < REQUIRED_CONFIRMS; i++)
        await send(msContract.methods.execute(myContract._address, WITHDRAW_WEI_AMOUNT, "0x00"), SIGNER_PRIVATE_KEYS[i]);
    let balanceAfter = await web3.eth.getBalance(WALLET_PUBLIC_ADDR);
    console.log("balanceBefore =", balanceBefore);
    console.log("balanceAfter  =", balanceAfter );
}


withdraw();

Step #2 - set the parameters at the top of this file to whatever you have on your system:

let ETH_NODE_ADDRESS    = "http://localhost:8545";
let WITHDRAW_WEI_AMOUNT = "1000000000000000000"; // 1 ether
let WALLET_PUBLIC_ADDR  = "0x7e5f4552091a69125d5dfcb7b8c2659029395bdf";
let WALLET_PRIVATE_KEY  = "0000000000000000000000000000000000000000000000000000000000000001";
let REQUIRED_CONFIRMS   = 3;
let SIGNER_PRIVATE_KEYS = [
    "0000000000000000000000000000000000000000000000000000000000000002",
    "0000000000000000000000000000000000000000000000000000000000000003",
    "0000000000000000000000000000000000000000000000000000000000000004",
    "0000000000000000000000000000000000000000000000000000000000000005",
];

Note that you'll be using this wallet (WALLET_PUBLIC_ADDR and WALLET_PRIVATE_KEY) for:

  • Deploying the MyContract contract that I have described at the top of this answer to mainnet
  • Withdrawing the funds from the multi-sig wallet that you have previously deployed to mainnet

So be sure to load some funds into this wallet (I'd say 0.2 Ether should do).

Step #3 - download Node.js and npm from https://nodejs.org/en/, and then install them.

Step #4 - open a command line at the same path where you saved the file withdraw.js, and then:

  • Run npm install web3
  • Run node withdraw.js

UPDATE #2:

A few notes on the solution above:

  1. Be sure to load some funds into each one of the signer-wallets, in particularly the last one (e.g., suppose that you need 3 out of 5 signers, then the 3rd wallet on the list requires a little more than the first two). My script requires only the private keys of the signer-wallets, but you'll need their public addresses as well of course, in order to load funds into them.

  2. Note that I am using the compiled code of both my contract (provided at the top of this answer) and your contract (deployed to mainnet), in order to save you the hustle of doing it yourself (compiling my contract and importing your compiled contract). Nevertheless, you shouldn't trust me with this piece of data, or even suppose someone has hacked this answer and changed it.

So here is how you can do it yourself, in case you decide not to trust me:

let MS_CONTRACT_ADDR = "Paste your contract address here, preceded by 0x"
let MS_CONTRACT_ABI  = 'Copy your contract abi from etherscan and paste it here'
let MY_CONTRACT_ABI  = 'Compile my contract and paste its abi here'
let MY_CONTRACT_BIN  = "Compile my contract and paste its bin here, preceded by 0x"
17
  • Wow, this turned out to be quite a lot more complex than i hoped it would be. Thank you for the effort! Seems like i have some research to do.
    – JussiR
    Dec 13, 2018 at 12:59
  • @JussiR: No problem, so do I get my 0.5 ether? :) Dec 13, 2018 at 14:11
  • If this helps me to retrieve the funds then definitely! Probably in any case :) I will look into this later (can't say for sure how soon). But feel free to send me your ethereum address.
    – JussiR
    Dec 13, 2018 at 16:59
  • @JussiR: Technically, I thought I could actually try it myself, make sure that it works (on a test-net of course, so free of charge). Since I'm interested to know if it works, I just might do that as soon as I have a free hour or so... Dec 13, 2018 at 18:26
  • 1
    @JussiR: I'm not sure about that. Assuming that this contract of yours has been deployed for a long time, you might need archive data. But like I said, I am not too sure about this. I suppose that you can just give it a try and see what happens. Perhaps archive is not necessary in this case. Jan 6, 2019 at 13:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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