Merge pull request #8 from cgewecke/draft-tests

Draft test suite
uport
area 8 years ago committed by GitHub
commit fe42d147b9
  1. 2
      package.json
  2. 39
      test/function.js
  3. 44
      test/if.js
  4. 49
      test/ifStatements.js
  5. 20
      test/return.js
  6. 5
      test/sources/function/abstract.sol
  7. 5
      test/sources/function/empty-body.sol
  8. 7
      test/sources/function/function.sol
  9. 15
      test/sources/function/multiple.sol
  10. 11
      test/sources/if/else-with-brackets.sol
  11. 10
      test/sources/if/else-without-brackets.sol
  12. 7
      test/sources/if/if-no-brackets.sol
  13. 7
      test/sources/if/if-with-brackets.sol
  14. 11
      test/sources/if/nested-if-missing-else.sol
  15. 7
      test/sources/return/return-null.sol
  16. 7
      test/sources/return/return.sol
  17. 22
      test/sources/statements/fn-argument-multiline.sol
  18. 11
      test/sources/statements/fn-argument.sol
  19. 8
      test/sources/statements/if-consequent-no-brackets-multiline.sol
  20. 8
      test/sources/statements/multiple.sol
  21. 7
      test/sources/statements/single.sol
  22. 58
      test/sources/zeppelin/Bounty.sol
  23. 30
      test/sources/zeppelin/Claimable.sol
  24. 73
      test/sources/zeppelin/DayLimit.sol
  25. 15
      test/sources/zeppelin/Killable.sol
  26. 18
      test/sources/zeppelin/LimitBalance.sol
  27. 15
      test/sources/zeppelin/Migrations.sol
  28. 29
      test/sources/zeppelin/Multisig.sol
  29. 102
      test/sources/zeppelin/MultisigWallet.sol
  30. 26
      test/sources/zeppelin/Ownable.sol
  31. 30
      test/sources/zeppelin/PullPayment.sol
  32. 29
      test/sources/zeppelin/SafeMath.sol
  33. 165
      test/sources/zeppelin/Shareable.sol
  34. 28
      test/sources/zeppelin/Stoppable.sol
  35. 29
      test/sources/zeppelin/token/BasicToken.sol
  36. 38
      test/sources/zeppelin/token/CrowdsaleToken.sol
  37. 18
      test/sources/zeppelin/token/ERC20.sol
  38. 14
      test/sources/zeppelin/token/ERC20Basic.sol
  39. 26
      test/sources/zeppelin/token/SimpleToken.sol
  40. 49
      test/sources/zeppelin/token/StandardToken.sol
  41. 45
      test/statements.js
  42. 21
      test/util/util.js
  43. 188
      test/zeppelin.js

@ -7,7 +7,7 @@
"test": "test"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "mocha --timeout 10000"
},
"author": "",
"license": "ISC",

@ -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);
})
})

@ -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);
})
})

@ -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)
}
})
})

@ -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);
})
})

@ -0,0 +1,5 @@
pragma solidity ^0.4.3;
contract Test {
function abstractFn(uint x);
}

@ -0,0 +1,5 @@
pragma solidity ^0.4.3;
contract Test {
function emptyBody(uint x){}
}

@ -0,0 +1,7 @@
pragma solidity ^0.4.3;
contract Test {
function a(bytes32 x) {
x;
}
}

@ -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;
}
}

@ -0,0 +1,11 @@
pragma solidity ^0.4.3;
contract Test {
function a(uint x) {
if (x == 1) {
throw;
} else {
x = 5;
}
}
}

@ -0,0 +1,10 @@
pragma solidity ^0.4.3;
contract Test {
function a(uint x) {
if (x == 1) {
throw;
} else
x = 5;
}
}

@ -0,0 +1,7 @@
pragma solidity ^0.4.3;
contract Test {
function a(uint x) {
if (x == 1) throw;
}
}

@ -0,0 +1,7 @@
pragma solidity ^0.4.3;
contract Test {
function a(uint x) {
if (x == 1) { throw; }
}
}

@ -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){
}
}
}
}

@ -0,0 +1,7 @@
pragma solidity ^0.4.3;
contract Test {
function a(uint x) returns (bool) {
return;
}
}

@ -0,0 +1,7 @@
pragma solidity ^0.4.3;
contract Test {
function a(uint x) returns (bool) {
return true;
}
}

@ -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')
);
}
}

@ -0,0 +1,11 @@
pragma solidity ^0.4.3;
contract Test {
function a(bytes32 x) {
x;
}
function b (){
a(sha3(0));
}
}

@ -0,0 +1,8 @@
pragma solidity ^0.4.3;
contract Test {
function a(uint x) {
if (x == 1)
throw;
}
}

@ -0,0 +1,8 @@
pragma solidity ^0.4.3;
contract Test {
function a(uint x) {
sha3(x);
sha3(0);
}
}

@ -0,0 +1,7 @@
pragma solidity ^0.4.3;
contract Test {
function a(uint x) {
sha3(x);
}
}

@ -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);
}

@ -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;
}
}

@ -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;
}
}

@ -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);
}
}

@ -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;
}
_;
}
}

@ -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);
}
}

@ -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);
}

@ -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;
}

@ -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;
}
}

@ -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;
}
}
}

@ -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;
}
}

@ -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;
}
}

@ -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;
}
}

@ -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];
}
}

@ -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;
}
}

@ -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);
}

@ -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);
}

@ -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;
}
}

@ -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];
}
}

@ -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);
})
})

@ -0,0 +1,21 @@
var fs = require('fs');
var path = require('path');
/**
* Retrieves code at source/<testType>/<test>.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)
}
}

@ -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);
})
})
Loading…
Cancel
Save