-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Wallet Contract
When deployed with n
owners, wallet contracts are multisignature vaults that require m
of n
owners to sign transactions that exceed a daily threshold.
To initiate a transaction from a wallet contract, first you must create an instance of the wallet contract. The example below is for an example v2 Wallet Contract deployed at the address "0x92fb112698b377023F3d076007B04608c03CF9d0":
myABI = [ { "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", "value": "4" } ], "type": "function" }, { "constant": true, "inputs": [], "name": "m_lastDay", "outputs": [ { "name": "", "type": "uint256", "value": "17013" } ], "type": "function" }, { "constant": true, "inputs": [], "name": "version", "outputs": [ { "name": "", "type": "uint256", "value": "2" } ], "type": "function" }, { "constant": false, "inputs": [], "name": "resetSpentToday", "outputs": [], "type": "function" }, { "constant": true, "inputs": [], "name": "m_spentToday", "outputs": [ { "name": "", "type": "uint256", "value": "1000000000000000000" } ], "type": "function" }, { "constant": false, "inputs": [ { "name": "_owner", "type": "address" } ], "name": "addOwner", "outputs": [], "type": "function" }, { "constant": true, "inputs": [], "name": "m_required", "outputs": [ { "name": "", "type": "uint256", "value": "2" } ], "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", "value": false } ], "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", "value": "1000000000000000000" } ], "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" } ]
var myAddress = "0x92fb112698b377023F3d076007B04608c03CF9d0";
var myContract = eth.contract(myABI);
var myInstance = myContract.at(myAddress);
Typing myInstance.
and hitting tab displays the contract's available functions as described in the ABI. For instance, for the wallet contract above:
myInstance.m_dailyLimit();
myInstance.m_lastDay()
myInstance.m_numOwners()
myInstance.m_required()
myInstance.m_spentToday()
The wallet contract will happily take all of the money that's sent to its address. No additional transaction metadata is required to make a deposit. To transfer 10 ether from your coinbase to the wallet contract described above:
eth.sendTransaction( { from: eth.coinbase, to: "0x92fb112698b377023F3d076007B04608c03CF9d0", value: web3.toWei(10, "ether") } )
To make a withdrawal, the execute() function can be called; a destination address, amount, and (optional) data are supplied, and the account that is submitting the withdrawal request (and paying the gas cost to do so) must be indicated in the transaction. For instance, for "0x7c468346f38261f26974575595b1ece2636d6c17" to initiate a withdrawal of 1 ether from the contract into "0x6c6212c1eea2f2b7d38b1062e408a73e35cc14b9":
toAddress = "0x6c6212c1eea2f2b7d38b1062e408a73e35cc14b9";
requestAddress = "0x7c468346f38261f26974575595b1ece2636d6c17";
valueWithdrawn = web3.toWei(1, "ether");
amtGas = 100000;
myInstance.execute(toAddress, valueWithdrawn, "", { from: requestAddress, gas: amtGas } );
The transaction will take 50,000+ gas, so allocate accordingly.
If an owner request a withdrawal over the daily spend limit or executes another function that requires other contract owners to sign, the other owners must:
- scan the blockchain for
ConfirmationNeeded
events associated with the request - parse the operation hash associated with the request
- call the contract's
confirm
function from an owner account, referencing the request's operation hash
Here is a simple example that will get you the just the transaction hashes of transactions that contain events "ConfirmationNeeded" events from multisignature wallet contract transactions. The first step creates a filter; the second step uses 'watch' to scan the blockchain with that filter.
var myFilter = web3.eth.filter({fromBlock:0, toBlock: 'latest', address: myInstance.address, topics:myInstance.ConfirmationNeeded().options.topics}, function(error, result) {
if (!error)
console.log(result.transactionHash);
});
myFilter.watch(function(error,result) {
console.log(error);
console.log(result);
})
In a single step, here is an example that will scan the blockchain and return the operation hashes associated with "ConfirmationNeeded" events created by multisignature wallet contract transactions. This will also find the operation hashes of operations that have already been confirmed, so you'll need to combine this with additional filtering!
var myFilter = web3.eth.filter({fromBlock:0, toBlock: 'latest', address: myInstance.address, topics:myInstance.ConfirmationNeeded().options.topics}, function(error, result) {
if (!error)
tx = String(result.transactionHash);
tx_r = eth.getTransactionReceipt(tx);
console.log(tx_r.logs[1].data.substring(0,66));
});
Using the operation hash from above, one of other multisig addresses can now confirm the transaction request:
ohash = "0xc8df8e62cfc44eb4cd6db0d28026eddfb8f1920027a9549145b42362d9c9282f"
addSender = "0x6c6212c1eea2f2b7d38b1062e408a73e35cc14b9"
myInstance.confirm(ohash, { from:addSender, gas: 200000 } )
Once a sufficient number of owners have confirmed, the operation will proceed.
I was robbed :((( please refer … PLEASE HELP ME !
https://www.ethereum.org/ I was using your wallet
PLEASE HELP ME
https://etherscan.io/address/0x195229d13249C12d2643085D4907c191742c5eb0 eth= 43.3
https://etherscan.io/address/0xBF3198787a839ac3C49a3c5F6A837c0a41B3E7c0 eth= 2.55
PLEASE HELP ME
this is all my presence☹ I have no other assets ☹
pleasee