Merge with master

This commit is contained in:
Jorge Izquierdo
2017-05-21 16:08:47 -04:00
parent 929367f0ab
commit a6a2ee2bf1
61 changed files with 1272 additions and 227 deletions

View File

@ -31,7 +31,7 @@ contract('Bounty', function(accounts) {
assert.equal(reward, web3.eth.getBalance(bounty.address).toNumber());
});
it('empties itself when killed', async function(){
it('empties itself when destroyed', async function(){
let owner = accounts[0];
let reward = web3.toWei(1, 'ether');
let bounty = await SecureTargetBounty.new();
@ -39,7 +39,7 @@ contract('Bounty', function(accounts) {
assert.equal(reward, web3.eth.getBalance(bounty.address).toNumber());
await bounty.kill();
await bounty.destroy();
assert.equal(0, web3.eth.getBalance(bounty.address).toNumber());
});
@ -52,7 +52,7 @@ contract('Bounty', function(accounts) {
let bounty = await SecureTargetBounty.new();
let event = bounty.TargetCreated({});
event.watch(async function(err, result) {
let watcher = async function(err, result) {
event.stopWatching();
if (err) { throw err; }
@ -66,8 +66,8 @@ contract('Bounty', function(accounts) {
await bounty.claim(targetAddress, {from:researcher});
assert.isTrue(false); // should never reach here
} catch(error) {
let reClaimedBounty = await bounty.claimed.call();
assert.isFalse(reClaimedBounty);
let reClaimedBounty = await bounty.claimed.call();
assert.isFalse(reClaimedBounty);
}
try {
@ -77,8 +77,9 @@ contract('Bounty', function(accounts) {
assert.equal(reward,
web3.eth.getBalance(bounty.address).toNumber());
}
});
};
bounty.createTarget({from:researcher});
await awaitEvent(event, watcher);
});
});

26
test/Destructible.js Normal file
View File

@ -0,0 +1,26 @@
'use strict';
var Destructible = artifacts.require('../contracts/lifecycle/Destructible.sol');
require('./helpers/transactionMined.js');
contract('Destructible', function(accounts) {
it('should send balance to owner after destruction', async function() {
let destructible = await Destructible.new({from: accounts[0], value: web3.toWei('10','ether')});
let owner = await destructible.owner();
let initBalance = web3.eth.getBalance(owner);
await destructible.destroy({from: owner});
let newBalance = web3.eth.getBalance(owner);
assert.isTrue(newBalance > initBalance);
});
it('should send balance to recepient after destruction', async function() {
let destructible = await Destructible.new({from: accounts[0], value: web3.toWei('10','ether')});
let owner = await destructible.owner();
let initBalance = web3.eth.getBalance(accounts[1]);
await destructible.destroyAndSend(accounts[1], {from: owner} );
let newBalance = web3.eth.getBalance(accounts[1]);
assert.isTrue(newBalance.greaterThan(initBalance));
});
});

35
test/HasNoContracts.js Normal file
View File

@ -0,0 +1,35 @@
'use strict';
import expectThrow from './helpers/expectThrow';
import toPromise from './helpers/toPromise';
const Ownable = artifacts.require('../contracts/ownership/Ownable.sol');
const HasNoContracts = artifacts.require(
'../contracts/ownership/HasNoContracts.sol',
);
contract('HasNoContracts', function(accounts) {
let hasNoContracts = null;
let ownable = null;
beforeEach(async () => {
// Create contract and token
hasNoContracts = await HasNoContracts.new();
ownable = await Ownable.new();
// Force ownership into contract
await ownable.transferOwnership(hasNoContracts.address);
const owner = await ownable.owner();
assert.equal(owner, hasNoContracts.address);
});
it('should allow owner to reclaim contracts', async function() {
await hasNoContracts.reclaimContract(ownable.address);
const owner = await ownable.owner();
assert.equal(owner, accounts[0]);
});
it('should allow only owner to reclaim contracts', async function() {
await expectThrow(
hasNoContracts.reclaimContract(ownable.address, {from: accounts[1]}),
);
});
});

63
test/HasNoEther.js Normal file
View File

@ -0,0 +1,63 @@
'use strict';
import expectThrow from './helpers/expectThrow';
import toPromise from './helpers/toPromise';
const HasNoEther = artifacts.require('../contracts/lifecycle/HasNoEther.sol');
const HasNoEtherTest = artifacts.require('../helpers/HasNoEtherTest.sol');
const ForceEther = artifacts.require('../helpers/ForceEther.sol');
contract('HasNoEther', function(accounts) {
const amount = web3.toWei('1', 'ether');
it('should be constructorable', async function() {
let hasNoEther = await HasNoEtherTest.new();
});
it('should not accept ether in constructor', async function() {
await expectThrow(HasNoEtherTest.new({value: amount}));
});
it('should not accept ether', async function() {
let hasNoEther = await HasNoEtherTest.new();
await expectThrow(
toPromise(web3.eth.sendTransaction)({
from: accounts[1],
to: hasNoEther.address,
value: amount,
}),
);
});
it('should allow owner to reclaim ether', async function() {
// Create contract
let hasNoEther = await HasNoEtherTest.new();
const startBalance = await web3.eth.getBalance(hasNoEther.address);
assert.equal(startBalance, 0);
// Force ether into it
await ForceEther.new(hasNoEther.address, {value: amount});
const forcedBalance = await web3.eth.getBalance(hasNoEther.address);
assert.equal(forcedBalance, amount);
// Reclaim
const ownerStartBalance = await web3.eth.getBalance(accounts[0]);
await hasNoEther.reclaimEther();
const ownerFinalBalance = await web3.eth.getBalance(accounts[0]);
const finalBalance = await web3.eth.getBalance(hasNoEther.address);
assert.equal(finalBalance, 0);
assert.isAbove(ownerFinalBalance, ownerStartBalance);
});
it('should allow only owner to reclaim ether', async function() {
// Create contract
let hasNoEther = await HasNoEtherTest.new({from: accounts[0]});
// Force ether into it
await ForceEther.new(hasNoEther.address, {value: amount});
const forcedBalance = await web3.eth.getBalance(hasNoEther.address);
assert.equal(forcedBalance, amount);
// Reclaim
await expectThrow(hasNoEther.reclaimEther({from: accounts[1]}));
});
});

40
test/HasNoTokens.js Normal file
View File

@ -0,0 +1,40 @@
'use strict';
import expectThrow from './helpers/expectThrow';
import toPromise from './helpers/toPromise';
const HasNoTokens = artifacts.require('../contracts/lifecycle/HasNoTokens.sol');
const ERC23TokenMock = artifacts.require('./helpers/ERC23TokenMock.sol');
contract('HasNoTokens', function(accounts) {
let hasNoTokens = null;
let token = null;
beforeEach(async () => {
// Create contract and token
hasNoTokens = await HasNoTokens.new();
token = await ERC23TokenMock.new(accounts[0], 100);
// Force token into contract
await token.transfer(hasNoTokens.address, 10);
const startBalance = await token.balanceOf(hasNoTokens.address);
assert.equal(startBalance, 10);
});
it('should not accept ERC23 tokens', async function() {
await expectThrow(token.transferERC23(hasNoTokens.address, 10, ''));
});
it('should allow owner to reclaim tokens', async function() {
const ownerStartBalance = await token.balanceOf(accounts[0]);
await hasNoTokens.reclaimToken(token.address);
const ownerFinalBalance = await token.balanceOf(accounts[0]);
const finalBalance = await token.balanceOf(hasNoTokens.address);
assert.equal(finalBalance, 0);
assert.equal(ownerFinalBalance - ownerStartBalance, 10);
});
it('should allow only owner to reclaim tokens', async function() {
await expectThrow(
hasNoTokens.reclaimToken(token.address, {from: accounts[1]}),
);
});
});

View File

@ -1,18 +0,0 @@
'use strict';
var Killable = artifacts.require('../contracts/lifecycle/Killable.sol');
require('./helpers/transactionMined.js');
contract('Killable', function(accounts) {
it('should send balance to owner after death', async function() {
let killable = await Killable.new({from: accounts[0], value: web3.toWei('10','ether')});
let owner = await killable.owner();
let initBalance = web3.eth.getBalance(owner);
await killable.kill({from: owner});
let newBalance = web3.eth.getBalance(owner);
assert.isTrue(newBalance > initBalance);
});
});

35
test/MintableToken.js Normal file
View File

@ -0,0 +1,35 @@
'use strict';
const assertJump = require('./helpers/assertJump');
var MintableToken = artifacts.require('../contracts/Tokens/MintableToken.sol');
contract('Mintable', function(accounts) {
let token;
beforeEach(async function() {
token = await MintableToken.new();
});
it('should start with a totalSupply of 0', async function() {
let totalSupply = await token.totalSupply();
assert.equal(totalSupply, 0);
});
it('should return mintingFinished false after construction', async function() {
let mintingFinished = await token.mintingFinished();
assert.equal(mintingFinished, false);
});
it('should mint a given amount of tokens to a given address', async function() {
await token.mint(accounts[0], 100);
let balance0 = await token.balanceOf(accounts[0]);
assert(balance0, 100);
let totalSupply = await token.totalSupply();
assert(totalSupply, 100);
})
});

View File

@ -22,11 +22,11 @@ contract('MultisigWallet', function(accounts) {
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});
//Call destroy function from two different owner accounts, satisfying owners required
await wallet.destroy(accounts[0], {data: hash});
let txnHash = await wallet.destroy(accounts[0], {from: accounts[1], data: hash});
//Get balances of owner and wallet after kill function is complete, compare with previous values
//Get balances of owner and wallet after destroy function is complete, compare with previous values
let newOwnerBalance = web3.eth.getBalance(accounts[0]);
let newWalletBalance = web3.eth.getBalance(wallet.address);

View File

@ -1,10 +1,11 @@
'use strict';
var PausableMock = artifacts.require('helpers/PausableMock.sol');
const assertJump = require('./helpers/assertJump');
const PausableMock = artifacts.require('helpers/PausableMock.sol');
contract('Pausable', function(accounts) {
it('can perform normal process in non-emergency', async function() {
it('can perform normal process in non-pause', async function() {
let Pausable = await PausableMock.new();
let count0 = await Pausable.count();
assert.equal(count0, 0);
@ -14,39 +15,47 @@ contract('Pausable', function(accounts) {
assert.equal(count1, 1);
});
it('can not perform normal process in emergency', async function() {
it('can not perform normal process in pause', async function() {
let Pausable = await PausableMock.new();
await Pausable.emergencyStop();
await Pausable.pause();
let count0 = await Pausable.count();
assert.equal(count0, 0);
await Pausable.normalProcess();
try {
await Pausable.normalProcess();
} catch(error) {
assertJump(error);
}
let count1 = await Pausable.count();
assert.equal(count1, 0);
});
it('can not take drastic measure in non-emergency', async function() {
it('can not take drastic measure in non-pause', async function() {
let Pausable = await PausableMock.new();
await Pausable.drasticMeasure();
let drasticMeasureTaken = await Pausable.drasticMeasureTaken();
try {
await Pausable.drasticMeasure();
} catch(error) {
assertJump(error);
}
const drasticMeasureTaken = await Pausable.drasticMeasureTaken();
assert.isFalse(drasticMeasureTaken);
});
it('can take a drastic measure in an emergency', async function() {
it('can take a drastic measure in a pause', async function() {
let Pausable = await PausableMock.new();
await Pausable.emergencyStop();
await Pausable.pause();
await Pausable.drasticMeasure();
let drasticMeasureTaken = await Pausable.drasticMeasureTaken();
assert.isTrue(drasticMeasureTaken);
});
it('should resume allowing normal process after emergency is over', async function() {
it('should resume allowing normal process after pause is over', async function() {
let Pausable = await PausableMock.new();
await Pausable.emergencyStop();
await Pausable.release();
await Pausable.pause();
await Pausable.unpause();
await Pausable.normalProcess();
let count0 = await Pausable.count();

73
test/PausableToken.js Normal file
View File

@ -0,0 +1,73 @@
'user strict';
const assertJump = require('./helpers/assertJump');
var PausableTokenMock = artifacts.require('./helpers/PausableTokenMock.sol');
contract('PausableToken', function(accounts) {
let token;
beforeEach(async function() {
token = await PausableTokenMock.new(accounts[0], 100);
});
it('should return paused false after construction', async function() {
let paused = await token.paused();
assert.equal(paused, false);
});
it('should return paused true after pause', async function() {
await token.pause();
let paused = await token.paused();
assert.equal(paused, true);
});
it('should return paused false after pause and unpause', async function() {
await token.pause();
await token.unpause();
let paused = await token.paused();
assert.equal(paused, false);
});
it('should be able to transfer if transfers are unpaused', async function() {
await token.transfer(accounts[1], 100);
let balance0 = await token.balanceOf(accounts[0]);
assert.equal(balance0, 0);
let balance1 = await token.balanceOf(accounts[1]);
assert.equal(balance1, 100);
});
it('should be able to transfer after transfers are paused and unpaused', async function() {
await token.pause();
await token.unpause();
await token.transfer(accounts[1], 100);
let balance0 = await token.balanceOf(accounts[0]);
assert.equal(balance0, 0);
let balance1 = await token.balanceOf(accounts[1]);
assert.equal(balance1, 100);
});
it('should throw an error trying to transfer while transactions are paused', async function() {
await token.pause();
try {
await token.transfer(accounts[1], 100);
} catch (error) {
return assertJump(error);
}
assert.fail('should have thrown before');
});
it('should throw an error trying to transfer from another account while transactions are paused', async function() {
await token.pause();
try {
await token.transferFrom(accounts[0], accounts[1], 100);
} catch (error) {
return assertJump(error);
}
assert.fail('should have thrown before');
});
})

View File

@ -12,7 +12,9 @@ contract('PullPayment', function(accounts) {
let ppce = await PullPaymentMock.new();
let callSend = await ppce.callSend(accounts[0], AMOUNT);
let paymentsToAccount0 = await ppce.payments(accounts[0]);
let totalPayments = await ppce.totalPayments();
assert.equal(totalPayments, AMOUNT);
assert.equal(paymentsToAccount0, AMOUNT);
});
@ -21,7 +23,9 @@ contract('PullPayment', function(accounts) {
let call1 = await ppce.callSend(accounts[0], 200);
let call2 = await ppce.callSend(accounts[0], 300);
let paymentsToAccount0 = await ppce.payments(accounts[0]);
let totalPayments = await ppce.totalPayments();
assert.equal(totalPayments, 500);
assert.equal(paymentsToAccount0, 500);
});
@ -35,6 +39,9 @@ contract('PullPayment', function(accounts) {
let paymentsToAccount1 = await ppce.payments(accounts[1]);
assert.equal(paymentsToAccount1, 300);
let totalPayments = await ppce.totalPayments();
assert.equal(totalPayments, 500);
});
it("can withdraw payment", async function() {
@ -48,10 +55,16 @@ contract('PullPayment', function(accounts) {
let payment1 = await ppce.payments(payee);
assert.equal(payment1, AMOUNT);
let totalPayments = await ppce.totalPayments();
assert.equal(totalPayments, AMOUNT);
let withdraw = await ppce.withdrawPayments({from: payee});
let payment2 = await ppce.payments(payee);
assert.equal(payment2, 0);
totalPayments = await ppce.totalPayments();
assert.equal(totalPayments, 0);
let balance = web3.eth.getBalance(payee);
assert(Math.abs(balance-initialBalance-AMOUNT) < 1e16);
});

31
test/ReentrancyGuard.js Normal file
View File

@ -0,0 +1,31 @@
'use strict';
import expectThrow from './helpers/expectThrow';
const ReentrancyMock = artifacts.require('./helper/ReentrancyMock.sol');
const ReentrancyAttack = artifacts.require('./helper/ReentrancyAttack.sol');
contract('ReentrancyGuard', function(accounts) {
let reentrancyMock;
beforeEach(async function() {
reentrancyMock = await ReentrancyMock.new();
let initialCounter = await reentrancyMock.counter();
assert.equal(initialCounter, 0);
});
it('should not allow remote callback', async function() {
let attacker = await ReentrancyAttack.new();
await expectThrow(reentrancyMock.countAndCall(attacker.address));
});
// The following are more side-effects that intended behaviour:
// I put them here as documentation, and to monitor any changes
// in the side-effects.
it('should not allow local recursion', async function() {
await expectThrow(reentrancyMock.countLocalRecursive(10));
});
it('should not allow indirect local recursion', async function() {
await expectThrow(reentrancyMock.countThisRecursive(10));
});
});

View File

@ -1,26 +1,28 @@
'use strict';
const assertJump = require('./helpers/assertJump');
var StandardTokenMock = artifacts.require("./helpers/StandardTokenMock.sol");
var StandardTokenMock = artifacts.require('./helpers/StandardTokenMock.sol');
contract('StandardToken', function(accounts) {
it("should return the correct totalSupply after construction", async function() {
it('should return the correct totalSupply after construction', async function() {
let token = await StandardTokenMock.new(accounts[0], 100);
let totalSupply = await token.totalSupply();
assert.equal(totalSupply, 100);
})
});
it("should return the correct allowance amount after approval", async function() {
it('should return the correct allowance amount after approval', async function() {
let token = await StandardTokenMock.new();
let approve = await token.approve(accounts[1], 100);
await token.approve(accounts[1], 100);
let allowance = await token.allowance(accounts[0], accounts[1]);
assert.equal(allowance, 100);
});
it("should return correct balances after transfer", async function() {
it('should return correct balances after transfer', async function() {
let token = await StandardTokenMock.new(accounts[0], 100);
let transfer = await token.transfer(accounts[1], 100);
await token.transfer(accounts[1], 100);
let balance0 = await token.balanceOf(accounts[0]);
assert.equal(balance0, 0);
@ -28,20 +30,20 @@ contract('StandardToken', function(accounts) {
assert.equal(balance1, 100);
});
it("should throw an error when trying to transfer more than balance", async function() {
it('should throw an error when trying to transfer more than balance', async function() {
let token = await StandardTokenMock.new(accounts[0], 100);
try {
let transfer = await token.transfer(accounts[1], 101);
await token.transfer(accounts[1], 101);
} catch(error) {
return assertJump(error);
}
assert.fail('should have thrown before');
});
it("should return correct balances after transfering from another account", async function() {
it('should return correct balances after transfering from another account', async function() {
let token = await StandardTokenMock.new(accounts[0], 100);
let approve = await token.approve(accounts[1], 100);
let transferFrom = await token.transferFrom(accounts[0], accounts[2], 100, {from: accounts[1]});
await token.approve(accounts[1], 100);
await token.transferFrom(accounts[0], accounts[2], 100, {from: accounts[1]});
let balance0 = await token.balanceOf(accounts[0]);
assert.equal(balance0, 0);
@ -53,11 +55,11 @@ contract('StandardToken', function(accounts) {
assert.equal(balance2, 0);
});
it("should throw an error when trying to transfer more than allowed", async function() {
it('should throw an error when trying to transfer more than allowed', async function() {
let token = await StandardTokenMock.new();
let approve = await token.approve(accounts[1], 99);
await token.approve(accounts[1], 99);
try {
let transfer = await token.transferFrom(accounts[0], accounts[2], 100, {from: accounts[1]});
await token.transferFrom(accounts[0], accounts[2], 100, {from: accounts[1]});
} catch (error) {
return assertJump(error);
}

32
test/TokenDestructible.js Normal file
View File

@ -0,0 +1,32 @@
'use strict';
var TokenDestructible = artifacts.require('../contracts/lifecycle/TokenDestructible.sol');
var StandardTokenMock = artifacts.require("./helpers/StandardTokenMock.sol");
require('./helpers/transactionMined.js');
contract('TokenDestructible', function(accounts) {
it('should send balance to owner after destruction', async function() {
let destructible = await TokenDestructible.new({from: accounts[0], value: web3.toWei('10','ether')});
let owner = await destructible.owner();
let initBalance = web3.eth.getBalance(owner);
await destructible.destroy([], {from: owner});
let newBalance = web3.eth.getBalance(owner);
assert.isTrue(newBalance > initBalance);
});
it('should send tokens to owner after destruction', async function() {
let destructible = await TokenDestructible.new({from: accounts[0], value: web3.toWei('10','ether')});
let owner = await destructible.owner();
let token = await StandardTokenMock.new(destructible.address, 100);
let initContractBalance = await token.balanceOf(destructible.address);
let initOwnerBalance = await token.balanceOf(owner);
assert.equal(initContractBalance, 100);
assert.equal(initOwnerBalance, 0);
await destructible.destroy([token.address], {from: owner});
let newContractBalance = await token.balanceOf(destructible.address);
let newOwnerBalance = await token.balanceOf(owner);
assert.equal(newContractBalance, 0);
assert.equal(newOwnerBalance, 100);
});
});

View File

@ -40,7 +40,7 @@ contract('VestedToken', function(accounts) {
})
it('all tokens are transferable after vesting', async () => {
assert.equal(await token.transferableTokens(receiver, now + vesting + 1), tokenAmount);
assert.equal(await token.transferableTokens(receiver, now + vesting), tokenAmount);
})
it('throws when trying to transfer non vested tokens', async () => {
@ -84,13 +84,13 @@ contract('VestedToken', function(accounts) {
})
it('can transfer all tokens after vesting ends', async () => {
await timer(vesting + 1);
await timer(vesting);
await token.transfer(accounts[7], tokenAmount, { from: receiver })
assert.equal(await token.balanceOf(accounts[7]), tokenAmount);
})
it('can approve and transferFrom all tokens after vesting ends', async () => {
await timer(vesting + 1);
await timer(vesting);
await token.approve(accounts[7], tokenAmount, { from: receiver })
await token.transferFrom(receiver, accounts[7], tokenAmount, { from: accounts[7] })
assert.equal(await token.balanceOf(accounts[7]), tokenAmount);
@ -104,6 +104,7 @@ contract('VestedToken', function(accounts) {
let newNow = web3.eth.getBlock(web3.eth.blockNumber).timestamp
await token.grantVestedTokens(receiver, tokenAmount, newNow, newNow + cliff, newNow + vesting, false, false, { from: granter })
await token.transfer(accounts[7], 13, { from: receiver })
assert.equal(await token.balanceOf(accounts[7]), tokenAmount / 2);

View File

@ -0,0 +1,33 @@
pragma solidity ^0.4.8;
import '../../contracts/token/BasicToken.sol';
contract ERC23ContractInterface {
function tokenFallback(address _from, uint _value, bytes _data) external;
}
contract ERC23TokenMock is BasicToken {
function ERC23TokenMock(address initialAccount, uint initialBalance) {
balances[initialAccount] = initialBalance;
totalSupply = initialBalance;
}
// ERC23 compatible transfer function (except the name)
function transferERC23(address _to, uint _value, bytes _data)
returns (bool success)
{
transfer(_to, _value);
bool is_contract = false;
assembly {
is_contract := not(iszero(extcodesize(_to)))
}
if(is_contract) {
ERC23ContractInterface receiver = ERC23ContractInterface(_to);
receiver.tokenFallback(msg.sender, _value, _data);
}
return true;
}
}

View File

@ -0,0 +1,13 @@
pragma solidity ^0.4.8;
// @title Force Ether into a contract.
// @notice even
// if the contract is not payable.
// @notice To use, construct the contract with the target as argument.
// @author Remco Bloemen <remco@neufund.org>
contract ForceEther {
function ForceEther(address target) payable {
// Selfdestruct transfers all Ether to the arget address
selfdestruct(target);
}
}

View File

@ -0,0 +1,11 @@
pragma solidity ^0.4.8;
import "../../contracts/ownership/HasNoEther.sol";
contract HasNoEtherTest is HasNoEther {
// Constructor with explicit payable — should still fail
function HasNoEtherTest() payable {
}
}

View File

@ -14,11 +14,11 @@ contract PausableMock is Pausable {
count = 0;
}
function normalProcess() external stopInEmergency {
function normalProcess() external whenNotPaused {
count++;
}
function drasticMeasure() external onlyInEmergency {
function drasticMeasure() external whenPaused {
drasticMeasureTaken = true;
}

View File

@ -0,0 +1,12 @@
pragma solidity ^0.4.8;
import '../../contracts/token/PausableToken.sol';
// mock class using PausableToken
contract PausableTokenMock is PausableToken {
function PausableTokenMock(address initialAccount, uint initialBalance) {
balances[initialAccount] = initialBalance;
}
}

View File

@ -0,0 +1,11 @@
pragma solidity ^0.4.8;
contract ReentrancyAttack {
function callSender(bytes4 data) {
if(!msg.sender.call(data)) {
throw;
}
}
}

View File

@ -0,0 +1,46 @@
pragma solidity ^0.4.8;
import '../../contracts/ReentrancyGuard.sol';
import './ReentrancyAttack.sol';
contract ReentrancyMock is ReentrancyGuard {
uint256 public counter;
function ReentrancyMock() {
counter = 0;
}
function count() private {
counter += 1;
}
function countLocalRecursive(uint n) public nonReentrant {
if(n > 0) {
count();
countLocalRecursive(n - 1);
}
}
function countThisRecursive(uint256 n) public nonReentrant {
bytes4 func = bytes4(keccak256("countThisRecursive(uint256)"));
if(n > 0) {
count();
bool result = this.call(func, n - 1);
if(result != true) {
throw;
}
}
}
function countAndCall(ReentrancyAttack attacker) public nonReentrant {
count();
bytes4 func = bytes4(keccak256("callback()"));
attacker.callSender(func);
}
function callback() external nonReentrant {
count();
}
}

View File

@ -4,18 +4,18 @@ pragma solidity ^0.4.8;
import '../../contracts/SafeMath.sol';
contract SafeMathMock is SafeMath {
contract SafeMathMock {
uint public result;
function multiply(uint a, uint b) {
result = safeMul(a, b);
result = SafeMath.mul(a, b);
}
function subtract(uint a, uint b) {
result = safeSub(a, b);
result = SafeMath.sub(a, b);
}
function add(uint a, uint b) {
result = safeAdd(a, b);
result = SafeMath.add(a, b);
}
}

View File

@ -0,0 +1,20 @@
export default async promise => {
try {
await promise;
} catch (error) {
// TODO: Check jump destination to destinguish between a throw
// and an actual invalid jump.
const invalidJump = error.message.search('invalid JUMP') >= 0;
// TODO: When we contract A calls contract B, and B throws, instead
// of an 'invalid jump', we get an 'out of gas' error. How do
// we distinguish this from an actual out of gas event? (The
// testrpc log actually show an 'invalid jump' event.)
const outOfGas = error.message.search('out of gas') >= 0;
assert(
invalidJump || outOfGas,
"Expected throw, got '" + error + "' instead",
);
return;
}
assert.fail('Expected throw not received');
};

View File

@ -0,0 +1,4 @@
export default func =>
(...args) =>
new Promise((accept, reject) =>
func(...args, (error, data) => error ? reject(error) : accept(data)));