From 10254a4790801763b2291c8979dc2ff919b8a451 Mon Sep 17 00:00:00 2001 From: cgewecke Date: Wed, 14 Dec 2016 13:43:09 -0800 Subject: [PATCH] Draft test suite --- package.json | 2 +- test/function.js | 39 ++++ test/if.js | 44 ++++ test/ifStatements.js | 49 ----- test/return.js | 20 ++ test/sources/function/abstract.sol | 5 + test/sources/function/empty-body.sol | 5 + test/sources/function/function.sol | 7 + test/sources/function/multiple.sol | 15 ++ test/sources/if/else-with-brackets.sol | 11 + test/sources/if/else-without-brackets.sol | 10 + test/sources/if/if-no-brackets.sol | 7 + test/sources/if/if-with-brackets.sol | 7 + test/sources/if/nested-if-missing-else.sol | 11 + test/sources/return/return-null.sol | 7 + test/sources/return/return.sol | 7 + .../statements/fn-argument-multiline.sol | 22 ++ test/sources/statements/fn-argument.sol | 11 + .../if-consequent-no-brackets-multiline.sol | 8 + test/sources/statements/multiple.sol | 8 + test/sources/statements/single.sol | 7 + test/sources/zeppelin/Bounty.sol | 58 ++++++ test/sources/zeppelin/Claimable.sol | 30 +++ test/sources/zeppelin/DayLimit.sol | 73 +++++++ test/sources/zeppelin/Killable.sol | 15 ++ test/sources/zeppelin/LimitBalance.sol | 18 ++ test/sources/zeppelin/Migrations.sol | 15 ++ test/sources/zeppelin/Multisig.sol | 29 +++ test/sources/zeppelin/MultisigWallet.sol | 102 ++++++++++ test/sources/zeppelin/Ownable.sol | 26 +++ test/sources/zeppelin/PullPayment.sol | 30 +++ test/sources/zeppelin/SafeMath.sol | 29 +++ test/sources/zeppelin/Shareable.sol | 165 +++++++++++++++ test/sources/zeppelin/Stoppable.sol | 28 +++ test/sources/zeppelin/token/BasicToken.sol | 29 +++ .../sources/zeppelin/token/CrowdsaleToken.sol | 38 ++++ test/sources/zeppelin/token/ERC20.sol | 18 ++ test/sources/zeppelin/token/ERC20Basic.sol | 14 ++ test/sources/zeppelin/token/SimpleToken.sol | 26 +++ test/sources/zeppelin/token/StandardToken.sol | 49 +++++ test/statements.js | 45 +++++ test/util/util.js | 21 ++ test/zeppelin.js | 188 ++++++++++++++++++ 43 files changed, 1298 insertions(+), 50 deletions(-) create mode 100644 test/function.js create mode 100644 test/if.js delete mode 100644 test/ifStatements.js create mode 100644 test/return.js create mode 100644 test/sources/function/abstract.sol create mode 100644 test/sources/function/empty-body.sol create mode 100644 test/sources/function/function.sol create mode 100644 test/sources/function/multiple.sol create mode 100644 test/sources/if/else-with-brackets.sol create mode 100644 test/sources/if/else-without-brackets.sol create mode 100644 test/sources/if/if-no-brackets.sol create mode 100644 test/sources/if/if-with-brackets.sol create mode 100644 test/sources/if/nested-if-missing-else.sol create mode 100644 test/sources/return/return-null.sol create mode 100644 test/sources/return/return.sol create mode 100644 test/sources/statements/fn-argument-multiline.sol create mode 100644 test/sources/statements/fn-argument.sol create mode 100644 test/sources/statements/if-consequent-no-brackets-multiline.sol create mode 100644 test/sources/statements/multiple.sol create mode 100644 test/sources/statements/single.sol create mode 100644 test/sources/zeppelin/Bounty.sol create mode 100644 test/sources/zeppelin/Claimable.sol create mode 100644 test/sources/zeppelin/DayLimit.sol create mode 100644 test/sources/zeppelin/Killable.sol create mode 100644 test/sources/zeppelin/LimitBalance.sol create mode 100644 test/sources/zeppelin/Migrations.sol create mode 100644 test/sources/zeppelin/Multisig.sol create mode 100644 test/sources/zeppelin/MultisigWallet.sol create mode 100644 test/sources/zeppelin/Ownable.sol create mode 100644 test/sources/zeppelin/PullPayment.sol create mode 100644 test/sources/zeppelin/SafeMath.sol create mode 100644 test/sources/zeppelin/Shareable.sol create mode 100644 test/sources/zeppelin/Stoppable.sol create mode 100644 test/sources/zeppelin/token/BasicToken.sol create mode 100644 test/sources/zeppelin/token/CrowdsaleToken.sol create mode 100644 test/sources/zeppelin/token/ERC20.sol create mode 100644 test/sources/zeppelin/token/ERC20Basic.sol create mode 100644 test/sources/zeppelin/token/SimpleToken.sol create mode 100644 test/sources/zeppelin/token/StandardToken.sol create mode 100644 test/statements.js create mode 100644 test/util/util.js create mode 100644 test/zeppelin.js diff --git a/package.json b/package.json index ba6eab0..be598d3 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "test": "test" }, "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "mocha --timeout 10000" }, "author": "", "license": "ISC", diff --git a/test/function.js b/test/function.js new file mode 100644 index 0000000..3097493 --- /dev/null +++ b/test/function.js @@ -0,0 +1,39 @@ +var solc = require('solc'); +var getInstrumentedVersion = require('./../instrumentSolidity.js'); +var util = require('./util/util.js'); + +/** + * NB: passing '1' to solc as an option activates the optimiser + * NB: solc will throw if there is a compilation error, causing the test to fail + * and passing the error to mocha. + */ +describe('function declarations', function(){ + + it('should compile after instrumenting an ordinary function declaration', function(){ + var contract = util.getCode('function/function.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting an abstract function declaration', function(){ + var contract = util.getCode('function/abstract.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting a function declaration with an empty body', function(){ + var contract = util.getCode('function/empty-body.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting lots of declarations in row', function(){ + var contract = util.getCode('function/multiple.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) +}) diff --git a/test/if.js b/test/if.js new file mode 100644 index 0000000..636faea --- /dev/null +++ b/test/if.js @@ -0,0 +1,44 @@ +var solc = require('solc'); +var getInstrumentedVersion = require('./../instrumentSolidity.js'); +var util = require('./util/util.js') + +/** + * NB: passing '1' to solc as an option activates the optimiser + */ +describe('if, else, and else if statements', function(){ + + it('should compile after instrumenting else statements with brackets',function(){ + var contract = util.getCode('if/else-with-brackets.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting else statements without brackets',function(){ + var contract = util.getCode('if/else-without-brackets.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting if statements with no brackets',function(){ + var contract = util.getCode('if/if-no-brackets.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting if statements with brackets',function(){ + var contract = util.getCode('if/if-with-brackets.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting nested if statements with missing else statements',function(){ + var contract = util.getCode('if/nested-if-missing-else.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) +}) \ No newline at end of file diff --git a/test/ifStatements.js b/test/ifStatements.js deleted file mode 100644 index 17b4940..0000000 --- a/test/ifStatements.js +++ /dev/null @@ -1,49 +0,0 @@ -var solc = require('solc'); - -var getInstrumentedVersion = require('./../instrumentSolidity.js'); - -describe('if statements', function(){ - it('should instrument if statements with no brackets',function(){ - this.timeout(10000) - var contract="contract Test{\n\ - function a(uint x){\n\ - if (x==1) throw;\n\ - }\n\ - }" - var instrumentedContractInfo = getInstrumentedVersion(contract, "test.sol", true); - var output = solc.compile(instrumentedContractInfo.contract, 1); // 1 activates the optimiser - if (output.errors){ - throw new Error("Instrumented solidity invalid: " + output.errors) - } - }) - it('should instrument if statements with brackets',function(){ - this.timeout(10000) - var contract="contract Test{\n\ - function a(uint x){\n\ - if (x==1) { throw; }\n\ - }\n\ - }" - var instrumentedContractInfo = getInstrumentedVersion(contract, "test.sol", true); - var output = solc.compile(instrumentedContractInfo.contract, 1); // 1 activates the optimiser - if (output.errors){ - throw new Error("Instrumented solidity invalid: " + output.errors) - } - }) - it('should instrument nested if statements with missing else statements',function(){ - this.timeout(10000) - var contract="contract Test{\n\ - function a(uint x,uint y, uint z){\n\ - if (x==y){\n\ - }else if ( x==2 ){\n\ - if (y==z){\n\ - }\n\ - }\n\ - }\n\ - }" - var instrumentedContractInfo = getInstrumentedVersion(contract, "test.sol", true); - var output = solc.compile(instrumentedContractInfo.contract, 1); // 1 activates the optimiser - if (output.errors){ - throw new Error("Instrumented solidity invalid: " + output.errors) - } - }) - }) \ No newline at end of file diff --git a/test/return.js b/test/return.js new file mode 100644 index 0000000..385f079 --- /dev/null +++ b/test/return.js @@ -0,0 +1,20 @@ +var solc = require('solc'); +var getInstrumentedVersion = require('./../instrumentSolidity.js'); +var util = require('./util/util.js'); + +describe('return statements', function(){ + + it('should compile after instrumenting function that returns true',function(){ + var contract = util.getCode('return/return.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting function that returns without specifying val (null)',function(){ + var contract = util.getCode('return/return-null.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) +}) \ No newline at end of file diff --git a/test/sources/function/abstract.sol b/test/sources/function/abstract.sol new file mode 100644 index 0000000..f9304b3 --- /dev/null +++ b/test/sources/function/abstract.sol @@ -0,0 +1,5 @@ +pragma solidity ^0.4.3; + +contract Test { + function abstractFn(uint x); +} \ No newline at end of file diff --git a/test/sources/function/empty-body.sol b/test/sources/function/empty-body.sol new file mode 100644 index 0000000..813ec17 --- /dev/null +++ b/test/sources/function/empty-body.sol @@ -0,0 +1,5 @@ +pragma solidity ^0.4.3; + +contract Test { + function emptyBody(uint x){} +} diff --git a/test/sources/function/function.sol b/test/sources/function/function.sol new file mode 100644 index 0000000..fa9cc86 --- /dev/null +++ b/test/sources/function/function.sol @@ -0,0 +1,7 @@ +pragma solidity ^0.4.3; + +contract Test { + function a(bytes32 x) { + x; + } +} diff --git a/test/sources/function/multiple.sol b/test/sources/function/multiple.sol new file mode 100644 index 0000000..089eefe --- /dev/null +++ b/test/sources/function/multiple.sol @@ -0,0 +1,15 @@ +pragma solidity ^0.4.3; + +contract Test { + function f1(bytes32 x) { + x = 1; + } + + function f2(uint x){ x = 2; } + + address a; + + function f3(uint y){ + y = 1; + } +} \ No newline at end of file diff --git a/test/sources/if/else-with-brackets.sol b/test/sources/if/else-with-brackets.sol new file mode 100644 index 0000000..61f0532 --- /dev/null +++ b/test/sources/if/else-with-brackets.sol @@ -0,0 +1,11 @@ +pragma solidity ^0.4.3; + +contract Test { + function a(uint x) { + if (x == 1) { + throw; + } else { + x = 5; + } + } +} \ No newline at end of file diff --git a/test/sources/if/else-without-brackets.sol b/test/sources/if/else-without-brackets.sol new file mode 100644 index 0000000..9fbbaa7 --- /dev/null +++ b/test/sources/if/else-without-brackets.sol @@ -0,0 +1,10 @@ +pragma solidity ^0.4.3; + +contract Test { + function a(uint x) { + if (x == 1) { + throw; + } else + x = 5; + } +} \ No newline at end of file diff --git a/test/sources/if/if-no-brackets.sol b/test/sources/if/if-no-brackets.sol new file mode 100644 index 0000000..01f9211 --- /dev/null +++ b/test/sources/if/if-no-brackets.sol @@ -0,0 +1,7 @@ +pragma solidity ^0.4.3; + +contract Test { + function a(uint x) { + if (x == 1) throw; + } +} \ No newline at end of file diff --git a/test/sources/if/if-with-brackets.sol b/test/sources/if/if-with-brackets.sol new file mode 100644 index 0000000..89000e2 --- /dev/null +++ b/test/sources/if/if-with-brackets.sol @@ -0,0 +1,7 @@ +pragma solidity ^0.4.3; + +contract Test { + function a(uint x) { + if (x == 1) { throw; } + } +} \ No newline at end of file diff --git a/test/sources/if/nested-if-missing-else.sol b/test/sources/if/nested-if-missing-else.sol new file mode 100644 index 0000000..a3a87a8 --- /dev/null +++ b/test/sources/if/nested-if-missing-else.sol @@ -0,0 +1,11 @@ +pragma solidity ^0.4.3; + +contract Test { + function a(uint x,uint y, uint z) { + if (x==y){ + } else if (x==2){ + if (y==z){ + } + } + } +} \ No newline at end of file diff --git a/test/sources/return/return-null.sol b/test/sources/return/return-null.sol new file mode 100644 index 0000000..b35bbb9 --- /dev/null +++ b/test/sources/return/return-null.sol @@ -0,0 +1,7 @@ +pragma solidity ^0.4.3; + +contract Test { + function a(uint x) returns (bool) { + return; + } +} \ No newline at end of file diff --git a/test/sources/return/return.sol b/test/sources/return/return.sol new file mode 100644 index 0000000..3824133 --- /dev/null +++ b/test/sources/return/return.sol @@ -0,0 +1,7 @@ +pragma solidity ^0.4.3; + +contract Test { + function a(uint x) returns (bool) { + return true; + } +} \ No newline at end of file diff --git a/test/sources/statements/fn-argument-multiline.sol b/test/sources/statements/fn-argument-multiline.sol new file mode 100644 index 0000000..f09867b --- /dev/null +++ b/test/sources/statements/fn-argument-multiline.sol @@ -0,0 +1,22 @@ +pragma solidity ^0.4.3; + +contract Test { + + function multiline( + uint a, + uint b, + uint c, + bytes32 d) + { + var x = a; + } + + function Test(){ + multiline( + 1, + 2, + 3, + sha3('hello') + ); + } +} \ No newline at end of file diff --git a/test/sources/statements/fn-argument.sol b/test/sources/statements/fn-argument.sol new file mode 100644 index 0000000..8f3b11d --- /dev/null +++ b/test/sources/statements/fn-argument.sol @@ -0,0 +1,11 @@ +pragma solidity ^0.4.3; + +contract Test { + function a(bytes32 x) { + x; + } + + function b (){ + a(sha3(0)); + } +} \ No newline at end of file diff --git a/test/sources/statements/if-consequent-no-brackets-multiline.sol b/test/sources/statements/if-consequent-no-brackets-multiline.sol new file mode 100644 index 0000000..1d817a8 --- /dev/null +++ b/test/sources/statements/if-consequent-no-brackets-multiline.sol @@ -0,0 +1,8 @@ +pragma solidity ^0.4.3; + +contract Test { + function a(uint x) { + if (x == 1) + throw; + } +} \ No newline at end of file diff --git a/test/sources/statements/multiple.sol b/test/sources/statements/multiple.sol new file mode 100644 index 0000000..397dbd0 --- /dev/null +++ b/test/sources/statements/multiple.sol @@ -0,0 +1,8 @@ +pragma solidity ^0.4.3; + +contract Test { + function a(uint x) { + sha3(x); + sha3(0); + } +} \ No newline at end of file diff --git a/test/sources/statements/single.sol b/test/sources/statements/single.sol new file mode 100644 index 0000000..b7b01f0 --- /dev/null +++ b/test/sources/statements/single.sol @@ -0,0 +1,7 @@ +pragma solidity ^0.4.3; + +contract Test { + function a(uint x) { + sha3(x); + } +} \ No newline at end of file diff --git a/test/sources/zeppelin/Bounty.sol b/test/sources/zeppelin/Bounty.sol new file mode 100644 index 0000000..46699b1 --- /dev/null +++ b/test/sources/zeppelin/Bounty.sol @@ -0,0 +1,58 @@ +pragma solidity ^0.4.4; + + +import './PullPayment.sol'; +import './Killable.sol'; + + +/* + * Bounty + * + * This bounty will pay out to a researcher if they break invariant logic of the contract. + */ +contract Bounty is PullPayment, Killable { + Target target; + bool public claimed; + mapping(address => address) public researchers; + + event TargetCreated(address createdAddress); + + function() payable { + if (claimed) throw; + } + + function createTarget() returns(Target) { + target = Target(deployContract()); + researchers[target] = msg.sender; + TargetCreated(target); + return target; + } + + function deployContract() internal returns(address); + + function checkInvariant() returns(bool){ + return target.checkInvariant(); + } + + function claim(Target target) { + address researcher = researchers[target]; + if (researcher == 0) throw; + // Check Target contract invariants + if (target.checkInvariant()) { + throw; + } + asyncSend(researcher, this.balance); + claimed = true; + } + +} + +/* + * Target + * + * Your main contract should inherit from this class and implement the checkInvariant method. This is a function that should check everything your contract assumes to be true all the time. If this function returns false, it means your contract was broken in some way and is in an inconsistent state. This is what security researchers will try to acomplish when trying to get the bounty. + */ +contract Target { + function checkInvariant() returns(bool); +} + diff --git a/test/sources/zeppelin/Claimable.sol b/test/sources/zeppelin/Claimable.sol new file mode 100644 index 0000000..d51d34f --- /dev/null +++ b/test/sources/zeppelin/Claimable.sol @@ -0,0 +1,30 @@ +pragma solidity ^0.4.0; + + + +import './Ownable.sol'; + + +/* + * Claimable + * + * Extension for the Ownable contract, where the ownership needs to be claimed. This allows the new owner to accept the transfer. + */ +contract Claimable is Ownable { + address public pendingOwner; + + modifier onlyPendingOwner() { + if (msg.sender == pendingOwner) + _; + } + + function transfer(address newOwner) onlyOwner { + pendingOwner = newOwner; + } + + function claimOwnership() onlyPendingOwner { + owner = pendingOwner; + pendingOwner = 0x0; + } + +} diff --git a/test/sources/zeppelin/DayLimit.sol b/test/sources/zeppelin/DayLimit.sol new file mode 100644 index 0000000..e74837f --- /dev/null +++ b/test/sources/zeppelin/DayLimit.sol @@ -0,0 +1,73 @@ +pragma solidity ^0.4.4; + + +import './Shareable.sol'; +/* + * DayLimit + * + * inheritable "property" contract that enables methods to be protected by placing a linear limit (specifiable) + * on a particular resource per calendar day. is multiowned to allow the limit to be altered. resource that method + * uses is specified in the modifier. + */ +contract DayLimit is Shareable { + // FIELDS + + uint public dailyLimit; + uint public spentToday; + uint public lastDay; + + + // MODIFIERS + + // simple modifier for daily limit. + modifier limitedDaily(uint _value) { + if (underLimit(_value)) + _; + } + + + // CONSTRUCTOR + // stores initial daily limit and records the present day's index. + function DayLimit(uint _limit) { + dailyLimit = _limit; + lastDay = today(); + } + + + // METHODS + + // (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today. + function setDailyLimit(uint _newLimit) onlymanyowners(sha3(msg.data)) external { + dailyLimit = _newLimit; + } + + // resets the amount already spent today. needs many of the owners to confirm + function resetSpentToday() onlymanyowners(sha3(msg.data)) external { + spentToday = 0; + } + + + // INTERNAL METHODS + + // checks to see if there is at least `_value` left from the daily limit today. if there is, subtracts it and + // returns true. otherwise just returns false. + function underLimit(uint _value) internal onlyOwner returns (bool) { + // reset the spend limit if we're on a different day to last time. + if (today() > lastDay) { + spentToday = 0; + lastDay = today(); + } + // check to see if there's enough left - if so, subtract and return true. + // overflow protection // dailyLimit check + if (spentToday + _value >= spentToday && spentToday + _value <= dailyLimit) { + spentToday += _value; + return true; + } + return false; + } + + // determines today's index. + function today() private constant returns (uint) { + return now / 1 days; + } +} diff --git a/test/sources/zeppelin/Killable.sol b/test/sources/zeppelin/Killable.sol new file mode 100644 index 0000000..10621d6 --- /dev/null +++ b/test/sources/zeppelin/Killable.sol @@ -0,0 +1,15 @@ +pragma solidity ^0.4.4; + + +import "./Ownable.sol"; + + +/* + * Killable + * Base contract that can be killed by owner. All funds in contract will be sent to the owner. + */ +contract Killable is Ownable { + function kill() onlyOwner { + selfdestruct(owner); + } +} diff --git a/test/sources/zeppelin/LimitBalance.sol b/test/sources/zeppelin/LimitBalance.sol new file mode 100644 index 0000000..d8c29ba --- /dev/null +++ b/test/sources/zeppelin/LimitBalance.sol @@ -0,0 +1,18 @@ +pragma solidity ^0.4.4; +contract LimitBalance { + + uint public limit; + + function LimitBalance(uint _limit) { + limit = _limit; + } + + modifier limitedPayable() { + if (this.balance > limit) { + throw; + } + _; + + } + +} diff --git a/test/sources/zeppelin/Migrations.sol b/test/sources/zeppelin/Migrations.sol new file mode 100644 index 0000000..c8d890b --- /dev/null +++ b/test/sources/zeppelin/Migrations.sol @@ -0,0 +1,15 @@ +pragma solidity ^0.4.4; +import './Ownable.sol'; + +contract Migrations is Ownable { + uint public lastCompletedMigration; + + function setCompleted(uint completed) onlyOwner { + lastCompletedMigration = completed; + } + + function upgrade(address newAddress) onlyOwner { + Migrations upgraded = Migrations(newAddress); + upgraded.setCompleted(lastCompletedMigration); + } +} diff --git a/test/sources/zeppelin/Multisig.sol b/test/sources/zeppelin/Multisig.sol new file mode 100644 index 0000000..561bfe0 --- /dev/null +++ b/test/sources/zeppelin/Multisig.sol @@ -0,0 +1,29 @@ +pragma solidity ^0.4.4; + + +/* + * Multisig + * Interface contract for multisig proxy contracts; see below for docs. + */ +contract Multisig { + // EVENTS + + // logged events: + // Funds has arrived into the wallet (record how much). + event Deposit(address _from, uint value); + // Single transaction going out of the wallet (record who signed for it, how much, and to whom it's going). + event SingleTransact(address owner, uint value, address to, bytes data); + // Multi-sig transaction going out of the wallet (record who signed for it last, the operation hash, how much, and to whom it's going). + event MultiTransact(address owner, bytes32 operation, uint value, address to, bytes data); + // Confirmation still needed for a transaction. + event ConfirmationNeeded(bytes32 operation, address initiator, uint value, address to, bytes data); + + + // FUNCTIONS + + // TODO: document + function changeOwner(address _from, address _to) external; + function execute(address _to, uint _value, bytes _data) external returns (bytes32); + function confirm(bytes32 _h) returns (bool); +} + diff --git a/test/sources/zeppelin/MultisigWallet.sol b/test/sources/zeppelin/MultisigWallet.sol new file mode 100644 index 0000000..1eb24c0 --- /dev/null +++ b/test/sources/zeppelin/MultisigWallet.sol @@ -0,0 +1,102 @@ +pragma solidity ^0.4.4; + + +import "./Multisig.sol"; +import "./Shareable.sol"; +import "./DayLimit.sol"; + + +/* + * MultisigWallet + * usage: + * bytes32 h = Wallet(w).from(oneOwner).execute(to, value, data); + * Wallet(w).from(anotherOwner).confirm(h); + */ +contract MultisigWallet is Multisig, Shareable, DayLimit { + // TYPES + + // Transaction structure to remember details of transaction lest it need be saved for a later call. + struct Transaction { + address to; + uint value; + bytes data; + } + + + // CONSTRUCTOR + + // just pass on the owner array to the multiowned and + // the limit to daylimit + function MultisigWallet(address[] _owners, uint _required, uint _daylimit) + Shareable(_owners, _required) + DayLimit(_daylimit) { } + + + // METHODS + + // kills the contract sending everything to `_to`. + function kill(address _to) onlymanyowners(sha3(msg.data)) external { + suicide(_to); + } + + // gets called when no other function matches + function() payable { + // just being sent some cash? + if (msg.value > 0) + Deposit(msg.sender, msg.value); + } + + // Outside-visible transact entry point. Executes transaction immediately if below daily spend limit. + // If not, goes into multisig process. We provide a hash on return to allow the sender to provide + // shortcuts for the other confirmations (allowing them to avoid replicating the _to, _value + // and _data arguments). They still get the option of using them if they want, anyways. + function execute(address _to, uint _value, bytes _data) external onlyOwner returns (bytes32 _r) { + // first, take the opportunity to check that we're under the daily limit. + if (underLimit(_value)) { + SingleTransact(msg.sender, _value, _to, _data); + // yes - just execute the call. + if (!_to.call.value(_value)(_data)) { + throw; + } + return 0; + } + // determine our operation hash. + _r = sha3(msg.data, block.number); + if (!confirm(_r) && txs[_r].to == 0) { + txs[_r].to = _to; + txs[_r].value = _value; + txs[_r].data = _data; + ConfirmationNeeded(_r, msg.sender, _value, _to, _data); + } + } + + // confirm a transaction through just the hash. we use the previous transactions map, txs, in order + // to determine the body of the transaction from the hash provided. + function confirm(bytes32 _h) onlymanyowners(_h) returns (bool) { + if (txs[_h].to != 0) { + if (!txs[_h].to.call.value(txs[_h].value)(txs[_h].data)) { + throw; + } + MultiTransact(msg.sender, _h, txs[_h].value, txs[_h].to, txs[_h].data); + delete txs[_h]; + return true; + } + } + + + // INTERNAL METHODS + + function clearPending() internal { + uint length = pendingsIndex.length; + for (uint i = 0; i < length; ++i) { + delete txs[pendingsIndex[i]]; + } + super.clearPending(); + } + + + // FIELDS + + // pending transactions we have at present. + mapping (bytes32 => Transaction) txs; +} diff --git a/test/sources/zeppelin/Ownable.sol b/test/sources/zeppelin/Ownable.sol new file mode 100644 index 0000000..40fc081 --- /dev/null +++ b/test/sources/zeppelin/Ownable.sol @@ -0,0 +1,26 @@ +pragma solidity ^0.4.4; + + +/* + * Ownable + * + * Base contract with an owner. + * Provides onlyOwner modifier, which prevents function from running if it is called by anyone other than the owner. + */ +contract Ownable { + address public owner; + + function Ownable() { + owner = msg.sender; + } + + modifier onlyOwner() { + if (msg.sender == owner) + _; + } + + function transfer(address newOwner) onlyOwner { + if (newOwner != address(0)) owner = newOwner; + } + +} diff --git a/test/sources/zeppelin/PullPayment.sol b/test/sources/zeppelin/PullPayment.sol new file mode 100644 index 0000000..9bee81e --- /dev/null +++ b/test/sources/zeppelin/PullPayment.sol @@ -0,0 +1,30 @@ +pragma solidity ^0.4.4; + + +/* + * PullPayment + * Base contract supporting async send for pull payments. + * Inherit from this contract and use asyncSend instead of send. + */ +contract PullPayment { + mapping(address => uint) public payments; + + // store sent amount as credit to be pulled, called by payer + function asyncSend(address dest, uint amount) internal { + payments[dest] += amount; + } + + // withdraw accumulated balance, called by payee + function withdrawPayments() { + address payee = msg.sender; + uint payment = payments[payee]; + + if (payment == 0) throw; + if (this.balance < payment) throw; + + payments[payee] = 0; + if (!payee.send(payment)) { + throw; + } + } +} diff --git a/test/sources/zeppelin/SafeMath.sol b/test/sources/zeppelin/SafeMath.sol new file mode 100644 index 0000000..8568ddd --- /dev/null +++ b/test/sources/zeppelin/SafeMath.sol @@ -0,0 +1,29 @@ +pragma solidity ^0.4.4; + + +/** + * Math operations with safety checks + */ +contract SafeMath { + function safeMul(uint a, uint b) internal returns (uint) { + uint c = a * b; + assert(a == 0 || c / a == b); + return c; + } + + function safeSub(uint a, uint b) internal returns (uint) { + assert(b <= a); + return a - b; + } + + function safeAdd(uint a, uint b) internal returns (uint) { + uint c = a + b; + assert(c>=a && c>=b); + return c; + } + + function assert(bool assertion) internal { + if (!assertion) throw; + } +} + diff --git a/test/sources/zeppelin/Shareable.sol b/test/sources/zeppelin/Shareable.sol new file mode 100644 index 0000000..b73f31e --- /dev/null +++ b/test/sources/zeppelin/Shareable.sol @@ -0,0 +1,165 @@ +pragma solidity ^0.4.4; + + +/* + * Shareable + * + * Based on https://github.com/ethereum/dapp-bin/blob/master/wallet/wallet.sol + * + * inheritable "property" contract that enables methods to be protected by requiring the acquiescence of either a single, or, crucially, each of a number of, designated owners. + * + * usage: + * use modifiers onlyowner (just own owned) or onlymanyowners(hash), whereby the same hash must be provided by some number (specified in constructor) of the set of owners (specified in the constructor) before the interior is executed. + */ +contract Shareable { + // TYPES + + // struct for the status of a pending operation. + struct PendingState { + uint yetNeeded; + uint ownersDone; + uint index; + } + + + // FIELDS + + // the number of owners that must confirm the same operation before it is run. + uint public required; + + // list of owners + uint[256] owners; + uint constant c_maxOwners = 250; + // index on the list of owners to allow reverse lookup + mapping(uint => uint) ownerIndex; + // the ongoing operations. + mapping(bytes32 => PendingState) pendings; + bytes32[] pendingsIndex; + + + // EVENTS + + // this contract only has six types of events: it can accept a confirmation, in which case + // we record owner and operation (hash) alongside it. + event Confirmation(address owner, bytes32 operation); + event Revoke(address owner, bytes32 operation); + + + // MODIFIERS + + // simple single-sig function modifier. + modifier onlyOwner { + if (isOwner(msg.sender)) + _; + } + + // multi-sig function modifier: the operation must have an intrinsic hash in order + // that later attempts can be realised as the same underlying operation and + // thus count as confirmations. + modifier onlymanyowners(bytes32 _operation) { + if (confirmAndCheck(_operation)) + _; + } + + + // CONSTRUCTOR + + // constructor is given number of sigs required to do protected "onlymanyowners" transactions + // as well as the selection of addresses capable of confirming them. + function Shareable(address[] _owners, uint _required) { + owners[1] = uint(msg.sender); + ownerIndex[uint(msg.sender)] = 1; + for (uint i = 0; i < _owners.length; ++i) { + owners[2 + i] = uint(_owners[i]); + ownerIndex[uint(_owners[i])] = 2 + i; + } + required = _required; + } + + + // METHODS + + // Revokes a prior confirmation of the given operation + function revoke(bytes32 _operation) external { + uint index = ownerIndex[uint(msg.sender)]; + // make sure they're an owner + if (index == 0) return; + uint ownerIndexBit = 2**index; + var pending = pendings[_operation]; + if (pending.ownersDone & ownerIndexBit > 0) { + pending.yetNeeded++; + pending.ownersDone -= ownerIndexBit; + Revoke(msg.sender, _operation); + } + } + + // Gets an owner by 0-indexed position (using numOwners as the count) + function getOwner(uint ownerIndex) external constant returns (address) { + return address(owners[ownerIndex + 1]); + } + + function isOwner(address _addr) returns (bool) { + return ownerIndex[uint(_addr)] > 0; + } + + function hasConfirmed(bytes32 _operation, address _owner) constant returns (bool) { + var pending = pendings[_operation]; + uint index = ownerIndex[uint(_owner)]; + + // make sure they're an owner + if (index == 0) return false; + + // determine the bit to set for this owner. + uint ownerIndexBit = 2**index; + return !(pending.ownersDone & ownerIndexBit == 0); + } + + // INTERNAL METHODS + + function confirmAndCheck(bytes32 _operation) internal returns (bool) { + // determine what index the present sender is: + uint index = ownerIndex[uint(msg.sender)]; + // make sure they're an owner + if (index == 0) return; + + var pending = pendings[_operation]; + // if we're not yet working on this operation, switch over and reset the confirmation status. + if (pending.yetNeeded == 0) { + // reset count of confirmations needed. + pending.yetNeeded = required; + // reset which owners have confirmed (none) - set our bitmap to 0. + pending.ownersDone = 0; + pending.index = pendingsIndex.length++; + pendingsIndex[pending.index] = _operation; + } + // determine the bit to set for this owner. + uint ownerIndexBit = 2**index; + // make sure we (the message sender) haven't confirmed this operation previously. + if (pending.ownersDone & ownerIndexBit == 0) { + Confirmation(msg.sender, _operation); + // ok - check if count is enough to go ahead. + if (pending.yetNeeded <= 1) { + // enough confirmations: reset and run interior. + delete pendingsIndex[pendings[_operation].index]; + delete pendings[_operation]; + return true; + } + else + { + // not enough: record that this owner in particular confirmed. + pending.yetNeeded--; + pending.ownersDone |= ownerIndexBit; + } + } + } + + function clearPending() internal { + uint length = pendingsIndex.length; + for (uint i = 0; i < length; ++i) + if (pendingsIndex[i] != 0) + delete pendings[pendingsIndex[i]]; + delete pendingsIndex; + } + +} + diff --git a/test/sources/zeppelin/Stoppable.sol b/test/sources/zeppelin/Stoppable.sol new file mode 100644 index 0000000..5c01884 --- /dev/null +++ b/test/sources/zeppelin/Stoppable.sol @@ -0,0 +1,28 @@ +pragma solidity ^0.4.4; + + +import "./Ownable.sol"; + + +/* + * Stoppable + * Abstract contract that allows children to implement an + * emergency stop mechanism. + */ +contract Stoppable is Ownable { + bool public stopped; + + modifier stopInEmergency { if (!stopped) _; } + modifier onlyInEmergency { if (stopped) _; } + + // called by the owner on emergency, triggers stopped state + function emergencyStop() external onlyOwner { + stopped = true; + } + + // called by the owner on end of emergency, returns to normal state + function release() external onlyOwner onlyInEmergency { + stopped = false; + } + +} diff --git a/test/sources/zeppelin/token/BasicToken.sol b/test/sources/zeppelin/token/BasicToken.sol new file mode 100644 index 0000000..b0ad1e4 --- /dev/null +++ b/test/sources/zeppelin/token/BasicToken.sol @@ -0,0 +1,29 @@ +pragma solidity ^0.4.4; + + +import './ERC20Basic.sol'; +import '../SafeMath.sol'; + + +/* + * Basic token + * Basic version of StandardToken, with no allowances + */ +contract BasicToken is ERC20Basic, SafeMath { + + mapping(address => uint) balances; + + function transfer(address _to, uint _value) { + if (balances[msg.sender] < _value) { + throw; + } + balances[msg.sender] = safeSub(balances[msg.sender], _value); + balances[_to] = safeAdd(balances[_to], _value); + Transfer(msg.sender, _to, _value); + } + + function balanceOf(address _owner) constant returns (uint balance) { + return balances[_owner]; + } + +} diff --git a/test/sources/zeppelin/token/CrowdsaleToken.sol b/test/sources/zeppelin/token/CrowdsaleToken.sol new file mode 100644 index 0000000..f786546 --- /dev/null +++ b/test/sources/zeppelin/token/CrowdsaleToken.sol @@ -0,0 +1,38 @@ +pragma solidity ^0.4.4; + + +import "./StandardToken.sol"; + + +/* + * CrowdsaleToken + * + * Simple ERC20 Token example, with crowdsale token creation + */ +contract CrowdsaleToken is StandardToken { + + string public name = "CrowdsaleToken"; + string public symbol = "CRW"; + uint public decimals = 18; + + // 1 ether = 500 example tokens + uint PRICE = 500; + + function () payable { + createTokens(msg.sender); + } + + function createTokens(address recipient) payable { + if (msg.value == 0) throw; + + uint tokens = safeMul(msg.value, getPrice()); + + totalSupply = safeAdd(totalSupply, tokens); + balances[recipient] = safeAdd(balances[recipient], tokens); + } + + // replace this with any other price function + function getPrice() constant returns (uint result){ + return PRICE; + } +} diff --git a/test/sources/zeppelin/token/ERC20.sol b/test/sources/zeppelin/token/ERC20.sol new file mode 100644 index 0000000..4ac0bb1 --- /dev/null +++ b/test/sources/zeppelin/token/ERC20.sol @@ -0,0 +1,18 @@ +pragma solidity ^0.4.4; + + +/* + * ERC20 interface + * see https://github.com/ethereum/EIPs/issues/20 + */ +contract ERC20 { + uint public totalSupply; + function balanceOf(address who) constant returns (uint); + function allowance(address owner, address spender) constant returns (uint); + + function transfer(address to, uint value) returns (bool ok); + function transferFrom(address from, address to, uint value) returns (bool ok); + function approve(address spender, uint value) returns (bool ok); + event Transfer(address indexed from, address indexed to, uint value); + event Approval(address indexed owner, address indexed spender, uint value); +} diff --git a/test/sources/zeppelin/token/ERC20Basic.sol b/test/sources/zeppelin/token/ERC20Basic.sol new file mode 100644 index 0000000..b42d457 --- /dev/null +++ b/test/sources/zeppelin/token/ERC20Basic.sol @@ -0,0 +1,14 @@ +pragma solidity ^0.4.4; + + +/* + * ERC20Basic + * Simpler version of ERC20 interface + * see https://github.com/ethereum/EIPs/issues/20 + */ +contract ERC20Basic { + uint public totalSupply; + function balanceOf(address who) constant returns (uint); + function transfer(address to, uint value); + event Transfer(address indexed from, address indexed to, uint value); +} diff --git a/test/sources/zeppelin/token/SimpleToken.sol b/test/sources/zeppelin/token/SimpleToken.sol new file mode 100644 index 0000000..8b59438 --- /dev/null +++ b/test/sources/zeppelin/token/SimpleToken.sol @@ -0,0 +1,26 @@ +pragma solidity ^0.4.4; + + +import "./StandardToken.sol"; + + +/* + * SimpleToken + * + * Very simple ERC20 Token example, where all tokens are pre-assigned + * to the creator. Note they can later distribute these tokens + * as they wish using `transfer` and other `StandardToken` functions. + */ +contract SimpleToken is StandardToken { + + string public name = "SimpleToken"; + string public symbol = "SIM"; + uint public decimals = 18; + uint public INITIAL_SUPPLY = 10000; + + function SimpleToken() { + totalSupply = INITIAL_SUPPLY; + balances[msg.sender] = INITIAL_SUPPLY; + } + +} diff --git a/test/sources/zeppelin/token/StandardToken.sol b/test/sources/zeppelin/token/StandardToken.sol new file mode 100644 index 0000000..2f3e301 --- /dev/null +++ b/test/sources/zeppelin/token/StandardToken.sol @@ -0,0 +1,49 @@ +pragma solidity ^0.4.4; + +import './ERC20.sol'; +import '../SafeMath.sol'; + +/** + * ERC20 token + * + * https://github.com/ethereum/EIPs/issues/20 + * Based on code by FirstBlood: + * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol + */ +contract StandardToken is ERC20, SafeMath { + + mapping(address => uint) balances; + mapping (address => mapping (address => uint)) allowed; + + function transfer(address _to, uint _value) returns (bool success) { + balances[msg.sender] = safeSub(balances[msg.sender], _value); + balances[_to] = safeAdd(balances[_to], _value); + Transfer(msg.sender, _to, _value); + return true; + } + + function transferFrom(address _from, address _to, uint _value) returns (bool success) { + var _allowance = allowed[_from][msg.sender]; + + balances[_to] = safeAdd(balances[_to], _value); + balances[_from] = safeSub(balances[_from], _value); + allowed[_from][msg.sender] = safeSub(_allowance, _value); + Transfer(_from, _to, _value); + return true; + } + + function balanceOf(address _owner) constant returns (uint balance) { + return balances[_owner]; + } + + function approve(address _spender, uint _value) returns (bool success) { + allowed[msg.sender][_spender] = _value; + Approval(msg.sender, _spender, _value); + return true; + } + + function allowance(address _owner, address _spender) constant returns (uint remaining) { + return allowed[_owner][_spender]; + } + +} diff --git a/test/statements.js b/test/statements.js new file mode 100644 index 0000000..5f0580d --- /dev/null +++ b/test/statements.js @@ -0,0 +1,45 @@ +var solc = require('solc'); +var getInstrumentedVersion = require('./../instrumentSolidity.js'); +var util = require('./util/util.js'); + +/** + * NB: passing '1' to solc as an option activates the optimiser + * NB: solc will throw if there is a compilation error, causing the test to fail + * and passing the error to mocha. + */ +describe('generic statements', function(){ + it('should compile after instrumenting a single statement (first line of function)', function(){ + var contract = util.getCode('statements/single.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting multiple statements', function(){ + var contract = util.getCode('statements/multiple.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting a statement that is a function argument (single line)', function(){ + var contract = util.getCode('statements/fn-argument.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting a statement that is a function argument (multi-line)', function(){ + var contract = util.getCode('statements/fn-argument-multiline.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting a statement that is an unbracketed "if" consequent (multi-line)', function(){ + var contract = util.getCode('statements/if-consequent-no-brackets-multiline.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) +}) diff --git a/test/util/util.js b/test/util/util.js new file mode 100644 index 0000000..6722c07 --- /dev/null +++ b/test/util/util.js @@ -0,0 +1,21 @@ +var fs = require('fs'); +var path = require('path'); + +/** + * Retrieves code at source//.sol + * @param {String} _path path relative to `./source` + * @return {String} contents of a .sol file + */ +module.exports.getCode = function(_path){ + return fs.readFileSync (path.join (__dirname, './../sources/' + _path), 'utf8') +} + +module.exports.report = function(errors){ + if (errors){ + throw new Error("Instrumented solidity invalid: " + errors) + } +} + + + + diff --git a/test/zeppelin.js b/test/zeppelin.js new file mode 100644 index 0000000..071ce84 --- /dev/null +++ b/test/zeppelin.js @@ -0,0 +1,188 @@ +var solc = require('solc'); +var getInstrumentedVersion = require('./../instrumentSolidity.js'); +var util = require('./util/util.js'); + +describe('Battery test of production contracts: OpenZeppelin', function(){ + + it('should compile after instrumenting zeppelin-solidity/Bounty.sol',function(){ + var contract = util.getCode('zeppelin/Bounty.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var inputs = { + 'PullPayment.sol': util.getCode('zeppelin/PullPayment.sol'), + 'Killable.sol': util.getCode('zeppelin/Killable.sol'), + 'Bounty.sol': info.contract + }; + var output = solc.compile(inputs, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting zeppelin-solidity/Claimable.sol',function(){ + var contract = util.getCode('zeppelin/Claimable.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var inputs = { + 'Ownable.sol': util.getCode('zeppelin/Ownable.sol'), + 'Claimable.sol': info.contract + }; + var output = solc.compile(inputs, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting zeppelin-solidity/DayLimit.sol',function(){ + var contract = util.getCode('zeppelin/DayLimit.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var inputs = { + 'Ownable.sol': util.getCode('zeppelin/Shareable.sol'), + 'DayLimit.sol': info.contract + }; + var output = solc.compile(inputs, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting zeppelin-solidity/Killable.sol',function(){ + var contract = util.getCode('zeppelin/Killable.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var inputs = { + 'Ownable.sol': util.getCode('zeppelin/Ownable.sol'), + 'Killable.sol': info.contract + }; + var output = solc.compile(inputs, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting zeppelin-solidity/LimitBalance.sol',function(){ + var contract = util.getCode('zeppelin/LimitBalance.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting zeppelin-solidity/Migrations.sol',function(){ + var contract = util.getCode('zeppelin/Migrations.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var inputs = { + 'Ownable.sol': util.getCode('zeppelin/Ownable.sol'), + 'Migrations.sol': info.contract + }; + var output = solc.compile(inputs, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting zeppelin-solidity/Multisig.sol',function(){ + var contract = util.getCode('zeppelin/Multisig.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting zeppelin-solidity/MultisigWallet.sol',function(){ + var contract = util.getCode('zeppelin/MultisigWallet.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var inputs = { + 'Multisig.sol': util.getCode('zeppelin/Multisig.sol'), + 'Shareable.sol': util.getCode('zeppelin/Shareable.sol'), + 'DayLimit.sol': util.getCode('zeppelin/DayLimit.sol'), + 'MultisigWallet.sol': info.contract + }; + var output = solc.compile(inputs, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting zeppelin-solidity/Ownable.sol',function(){ + var contract = util.getCode('zeppelin/Ownable.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting zeppelin-solidity/PullPayment.sol',function(){ + var contract = util.getCode('zeppelin/PullPayment.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting zeppelin-solidity/SafeMath.sol',function(){ + var contract = util.getCode('zeppelin/SafeMath.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting zeppelin-solidity/Shareable.sol',function(){ + var contract = util.getCode('zeppelin/Shareable.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting zeppelin-solidity/Stoppable.sol',function(){ + var contract = util.getCode('zeppelin/Stoppable.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var inputs = { + 'Ownable.sol': util.getCode('zeppelin/Ownable.sol'), + 'Stoppable.sol': info.contract + }; + var output = solc.compile(inputs, 1); + util.report(output.errors); + }) + //--- Tokens --- + it('should compile after instrumenting zeppelin-solidity/BasicToken.sol',function(){ + var contract = util.getCode('zeppelin/token/BasicToken.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var inputs = { + 'ERC20Basic.sol': util.getCode('zeppelin/token/ERC20Basic.sol'), + 'SafeMath.sol': util.getCode('zeppelin/SafeMath.sol'), + 'BasicToken.sol': info.contract + }; + var output = solc.compile(inputs, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting zeppelin-solidity/CrowdsaleToken.sol',function(){ + var contract = util.getCode('zeppelin/token/CrowdsaleToken.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var inputs = { + 'StandardToken.sol': util.getCode('zeppelin/token/StandardToken.sol'), + 'CrowdsaleToken.sol': info.contract + }; + var output = solc.compile(inputs, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting zeppelin-solidity/ERC20.sol',function(){ + var contract = util.getCode('zeppelin/token/ERC20.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting zeppelin-solidity/ERC20Basic.sol',function(){ + var contract = util.getCode('zeppelin/token/ERC20Basic.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var output = solc.compile(info.contract, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting zeppelin-solidity/SimpleToken.sol',function(){ + var contract = util.getCode('zeppelin/token/SimpleToken.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var inputs = { + 'StandardToken.sol': util.getCode('zeppelin/token/StandardToken.sol'), + 'SimpleToken.sol': info.contract + }; + var output = solc.compile(inputs, 1); + util.report(output.errors); + }) + + it('should compile after instrumenting zeppelin-solidity/StandardToken.sol',function(){ + var contract = util.getCode('zeppelin/token/StandardToken.sol'); + var info = getInstrumentedVersion(contract, "test.sol", true); + var inputs = { + 'ERC20Basic.sol': util.getCode('zeppelin/token/ERC20Basic.sol'), + 'SafeMath.sol': util.getCode('zeppelin/SafeMath.sol'), + 'StandardToken.sol': info.contract + }; + var output = solc.compile(inputs, 1); + util.report(output.errors); + }) +}) \ No newline at end of file