From 8aa06bda3821f98468dd0448ba7d799a107b975a Mon Sep 17 00:00:00 2001 From: Arseniy Klempner Date: Thu, 8 Dec 2016 18:01:35 -0800 Subject: [PATCH 1/2] Create tests for MultisigWallet --- contracts/test-helpers/MultisigWalletMock.sol | 12 ++ test/MultisigWallet.js | 163 ++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 contracts/test-helpers/MultisigWalletMock.sol create mode 100644 test/MultisigWallet.js diff --git a/contracts/test-helpers/MultisigWalletMock.sol b/contracts/test-helpers/MultisigWalletMock.sol new file mode 100644 index 000000000..75ab67dbb --- /dev/null +++ b/contracts/test-helpers/MultisigWalletMock.sol @@ -0,0 +1,12 @@ +pragma solidity ^0.4.4; +import "../MultisigWallet.sol"; + +contract MultisigWalletMock is MultisigWallet { + uint public totalSpending; + + function MultisigWalletMock(address[] _owners, uint _required, uint _daylimit) + MultisigWallet(_owners, _required, _daylimit) { } + + function changeOwner(address _from, address _to) external { } + +} diff --git a/test/MultisigWallet.js b/test/MultisigWallet.js new file mode 100644 index 000000000..32c1ec781 --- /dev/null +++ b/test/MultisigWallet.js @@ -0,0 +1,163 @@ +contract('MultisigWallet', function(accounts) { + //from https://gist.github.com/xavierlepretre/88682e871f4ad07be4534ae560692ee6 + web3.eth.getTransactionReceiptMined = function (txnHash, interval) { + var transactionReceiptAsync; + interval = interval ? interval : 500; + transactionReceiptAsync = function(txnHash, resolve, reject) { + try { + var receipt = web3.eth.getTransactionReceipt(txnHash); + if (receipt == null) { + setTimeout(function () { + transactionReceiptAsync(txnHash, resolve, reject); + }, interval); + } else { + resolve(receipt); + } + } catch(e) { + reject(e); + } + }; + + if (Array.isArray(txnHash)) { + var promises = []; + txnHash.forEach(function (oneTxHash) { + promises.push(web3.eth.getTransactionReceiptMined(oneTxHash, interval)); + }); + return Promise.all(promises); + } else { + return new Promise(function (resolve, reject) { + transactionReceiptAsync(txnHash, resolve, reject); + }); + } +}; + + + it('should send balance to passed address upon death', async function() { + //Give account[0] 20 ether + web3.eth.sendTransaction({from: web3.eth.coinbase, to: accounts[0], value: web3.toWei('20','ether')}, function(err, result) { + if(err) + console.log("ERROR:" + err); + }); + + let dailyLimit = 10; + let ownersRequired = 2; + + //Create MultisigWallet contract with 10 ether + let wallet = await MultisigWalletMock.new(accounts, ownersRequired, dailyLimit, {value: web3.toWei('10', 'ether')}); + + //Get balances of owner and wallet after wallet creation. + let ownerBalance = web3.eth.getBalance(accounts[0]); + let walletBalance = web3.eth.getBalance(wallet.address); + let hash = 1234; + + //Call kill function from two different owner accounts, satisfying owners required + await wallet.kill(accounts[0], {data: hash}); + let txnHash = await wallet.kill(accounts[0], {from: accounts[1], data: hash}); + + let receiptMined = await web3.eth.getTransactionReceiptMined(txnHash); + + //Get balances of owner and wallet after kill function is complete, compare with previous values + let newOwnerBalance = web3.eth.getBalance(accounts[0]); + let newWalletBalance = web3.eth.getBalance(wallet.address); + + assert.isTrue(newOwnerBalance > ownerBalance); + assert.isTrue(newWalletBalance < walletBalance); + }); + + it('should execute transaction if below daily limit', async function() { + //Give account[0] 20 ether + web3.eth.sendTransaction({from: web3.eth.coinbase, to: accounts[0], value: web3.toWei('20','ether')}, function(err, result) { + if(err) + console.log("ERROR:" + err); + }); + + let dailyLimit = 10; + let ownersRequired = 2; + + //Create MultisigWallet contract with 10 ether + let wallet = await MultisigWalletMock.new(accounts, ownersRequired, dailyLimit, {value: web3.toWei('10', 'ether')}); + + let accountBalance = web3.eth.getBalance(accounts[2]); + let hash = 1234; + + //Owner account0 commands wallet to send 9 wei to account2 + let txnHash = await wallet.execute(accounts[2], 9, hash); + let receiptMined = await web3.eth.getTransactionReceiptMined(txnHash); + + //Balance of account2 should have increased + let newAccountBalance = web3.eth.getBalance(accounts[2]); + assert.isTrue(newAccountBalance > accountBalance); + }); + + it('should prevent execution of transaction if above daily limit', async function() { + //Give account[0] 20 ether + web3.eth.sendTransaction({from: web3.eth.coinbase, to: accounts[0], value: web3.toWei('20','ether')}, function(err, result) { + if(err) + console.log("ERROR:" + err); + }); + + let dailyLimit = 10; + let ownersRequired = 2; + + //Create MultisigWallet contract with 10 ether + let wallet = await MultisigWalletMock.new(accounts, ownersRequired, dailyLimit, {value: web3.toWei('10', 'ether')}); + + let accountBalance = web3.eth.getBalance(accounts[2]); + let hash = 1234; + + //Owner account0 commands wallet to send 9 wei to account2 + let txnHash = await wallet.execute(accounts[2], 9, hash); + let receiptMined = await web3.eth.getTransactionReceiptMined(txnHash); + + //Balance of account2 should have increased + let newAccountBalance = web3.eth.getBalance(accounts[2]); + assert.isTrue(newAccountBalance > accountBalance); + + accountBalance = newAccountBalance; + hash = 4567; + + //Owner account0 commands wallet to send 2 more wei to account2, going over the daily limit of 10 + txnHash = await wallet.execute(accounts[2], 2, hash); + receiptMined = await web3.eth.getTransactionReceiptMined(txnHash); + + //Balance of account2 should not change + newAccountBalance = web3.eth.getBalance(accounts[2]); + assert.equal(newAccountBalance.toString(), accountBalance.toString()); + }); + + it('should execute transaction if above daily limit and enough owners approve', async function() { + //Give account[0] 20 ether + web3.eth.sendTransaction({from: web3.eth.coinbase, to: accounts[0], value: web3.toWei('20','ether')}, function(err, result) { + if(err) + console.log("ERROR:" + err); + }); + + let dailyLimit = 10; + let ownersRequired = 2; + + //Create MultisigWallet contract with 10 ether + let wallet = await MultisigWalletMock.new(accounts, ownersRequired, dailyLimit, {value: web3.toWei('10', 'ether')}); + + let accountBalance = web3.eth.getBalance(accounts[2]); + let hash = 1234; + + //Owner account0 commands wallet to send 11 wei to account2 + let txnHash = await wallet.execute(accounts[2], 11, hash); + let receiptMined = await web3.eth.getTransactionReceiptMined(txnHash); + + //Balance of account2 should not change + let newAccountBalance = web3.eth.getBalance(accounts[2]); + assert.equal(newAccountBalance.toString(), accountBalance.toString()); + + accountBalance = newAccountBalance; + + //Owner account1 commands wallet to send 11 wei to account2 + txnHash = await wallet.execute(accounts[2], 2, hash); + receiptMined = await web3.eth.getTransactionReceiptMined(txnHash); + + //Balance of account2 should change + newAccountBalance = web3.eth.getBalance(accounts[2]); + assert.isTrue(newAccountBalance > accountBalance); + }); + +}); From 813c1ff0cd990a63519993d71aa8dfcec77cf131 Mon Sep 17 00:00:00 2001 From: Arseniy Klempner Date: Tue, 20 Dec 2016 13:12:45 -0800 Subject: [PATCH 2/2] Add payable to MultisigWalletMock() --- contracts/test-helpers/MultisigWalletMock.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/test-helpers/MultisigWalletMock.sol b/contracts/test-helpers/MultisigWalletMock.sol index 75ab67dbb..19adc558d 100644 --- a/contracts/test-helpers/MultisigWalletMock.sol +++ b/contracts/test-helpers/MultisigWalletMock.sol @@ -5,7 +5,7 @@ contract MultisigWalletMock is MultisigWallet { uint public totalSpending; function MultisigWalletMock(address[] _owners, uint _required, uint _daylimit) - MultisigWallet(_owners, _required, _daylimit) { } + MultisigWallet(_owners, _required, _daylimit) payable { } function changeOwner(address _from, address _to) external { }