Compare commits

..

88 Commits

Author SHA1 Message Date
e2fdf09e9b v1.2.0 2017-07-18 15:07:10 -03:00
4f44427966 Added function helper, few changes on ECRecover lib 2017-07-18 11:31:30 -03:00
f8c0fab5d8 Fixed tests and few changes on contract comments 2017-07-18 11:31:30 -03:00
478d1b1a93 Removed safeRecover, using ecrecover method instead, recovering signature from entire hash 2017-07-18 11:31:30 -03:00
a68eaa4e2d Added NatSpec documentation on ECRecovery contract 2017-07-18 11:31:30 -03:00
68c2bcb9dd Removed .only on ECRecovery tests 2017-07-18 11:31:30 -03:00
635c04378d Removed ECRecovery mock contract, ECRecovery funcions are public constants 2017-07-18 11:31:30 -03:00
227c7aae0f added check to ret boolean on ECRecovery 2017-07-18 11:31:30 -03:00
641b751385 Fix ECRecovery contract indentation
Fix ident on github

Fix ident github

Fix ident on github
2017-07-18 11:31:30 -03:00
4201d50dcf ECRecovery library added with test and docs 2017-07-18 11:31:30 -03:00
b05fb9c200 Update ownable.rst
Change the name of the function in the docs to the actual name in the contract source To prevent misunderstandings.
2017-07-17 21:37:59 -03:00
4f34d41523 Fixing typo. 2017-07-17 21:37:32 -03:00
91fc295a42 Updated reference to Ownable contract. 2017-07-17 21:37:32 -03:00
67d3a759a7 leave weiAmount after PR comments 2017-07-17 21:36:09 -03:00
950b6a5e56 sanity check for RefundableCrowdsale: goal > 0 2017-07-17 21:36:09 -03:00
db40fd314a sanity check for CappedCrowdsale: cap > 0 2017-07-17 21:36:09 -03:00
6035bd522b simplify crowdsale weiRaised update 2017-07-17 21:36:09 -03:00
b8884687df fix off by one error in VestedToken 2017-07-17 21:34:38 -03:00
18581f138f converted if() throw convention to require()/assert()/revert() 2017-07-17 15:35:09 -03:00
f3867f8477 Merge pull request #315 from joeykrug/patch-1
Added Constant to SafeMath functions as they don't modify storage
2017-07-15 15:52:36 -03:00
353285e5d9 Added Constant to SafeMath functions as they don't modify storage 2017-07-15 11:37:35 -07:00
a56bcbf8fd Correctly call super.transferableTokens
Fix #307
2017-07-14 18:17:09 -03:00
81297fac88 Merge pull request #308 from frangio/fix/erc20
Make ERC20 and token contracts conform to standard
2017-07-13 17:28:50 -03:00
6331dd125d fix ERC20 to conform to standard 2017-07-13 12:05:45 -03:00
f8790c1ed7 Merge pull request #304 from cgewecke/fix-coveralls
Fix coverage
2017-07-10 23:24:45 -03:00
5afbdf00db Fix coverage 2017-07-10 15:45:12 -07:00
322a9598ab Merge pull request #289 from ezynda3/master
update according to changes in #288
2017-07-06 11:07:13 -03:00
ba86e8e095 Merge pull request #296 from frangio/fix/293-tokentimelock-claim
Add TokenTimelock#release function that anyone can call
2017-07-05 11:47:15 -03:00
5e423bc353 add release function, deprecate claim 2017-07-05 11:24:59 -03:00
f2c2c01f8e Merge branch 'master' of github.com:OpenZeppelin/zeppelin-solidity 2017-07-02 15:50:40 -07:00
7434b3d6d2 v1.1.0 2017-07-02 18:53:32 -03:00
63b5fc5971 Merge pull request #290 from frangio/fix/safemath-references
Fix references to SafeMath in crowdsale contracts
2017-07-02 18:50:29 -03:00
f507a0ea29 fix references to SafeMath in crowdsale contracts 2017-07-02 18:39:51 -03:00
c254d8703d update according to changes in #288 2017-07-02 14:33:15 -07:00
981ec2dbdc v1.1.0 2017-07-02 18:27:18 -03:00
d5a75362ec Merge pull request #288 from frangio/refactor/math
Move SafeMath and create Math library for assorted operations
2017-07-02 18:13:47 -03:00
e748c3ea36 Merge pull request #283 from OpenZeppelin/crowdsale
Add Crowdsale contracts
2017-07-02 17:59:19 -03:00
421ed4f8ab fix references to max and min functions 2017-07-02 17:56:34 -03:00
0b1f08043b change Math to a library instead of a contract 2017-07-02 17:56:10 -03:00
759f8de81f fix import directories 2017-07-02 17:52:44 -03:00
96b550b722 Merge pull request #287 from jakub-wojciechowski/test/day-limit
Added new test for a day passed scenario to the DayLimit contract
2017-07-02 17:37:28 -03:00
b961eea89d fix claimRefund precondition 2017-07-02 17:10:11 -03:00
d2dd6e40b6 added new test for a day passed scenario to the DayLimit contract 2017-07-02 21:06:58 +01:00
070bcbcdbd rename purchaseValid to validPurchase 2017-07-02 17:05:06 -03:00
46fe7ee76d guard against beneficiary == 0x0 2017-07-02 16:51:26 -03:00
ba383a6d20 refactor max and min out of SafeMath 2017-07-02 13:01:55 -03:00
a66f5f8f03 format SafeMath documentation as NatSpec 2017-07-02 13:00:23 -03:00
262b7dd7dd Merge pull request #285 from frangio/feature/token-timelock
Add a TokenTimelock contract
2017-06-30 23:14:24 -03:00
5d847ed4d9 tweak TokenTimelock documentation 2017-06-30 21:28:45 -03:00
b3ca0c73b3 add a TokenTimelock contract 2017-06-30 21:25:59 -03:00
d6a45ef14e Merge pull request #282 from jasonbellamy/fix/standard-contract-docs-typo
fix(token): typo in documentation
2017-06-30 18:31:53 -03:00
54d74b1c26 rename canBuy to purchaseValid 2017-06-30 17:54:26 -03:00
657c56c650 remove unecessary whitespace 2017-06-30 17:54:07 -03:00
50a903a62d use npm test script for travis 2017-06-30 17:40:34 -03:00
0791e6639a add extra arguments to test command for development testing 2017-06-30 15:52:11 -03:00
59e9609926 remove CrowdsaleToken
it is superseded by the new crowdsale contracts
2017-06-30 15:50:47 -03:00
fadb2cf47e add tests for crowdsale contracts 2017-06-30 15:50:47 -03:00
4d55d8fa8e give more balance to testrpc accounts
includes fix to MultisigWallet test because bigger balances result in
floating point errors (see #204)
2017-06-30 15:50:47 -03:00
e31abffcb6 fix(token): typo in documentation
Implemantation -> Implementation
2017-06-30 14:40:15 -04:00
cd47fbe953 Improve Crowdsale#rate documentation 2017-06-30 11:23:28 -03:00
42c6392533 fix(token): typo in documentation 2017-06-30 00:41:12 -04:00
3430c7a289 Merge pull request #280 from rstormsf/fix/revert_inheritance_order
change inheritance order for StandardToken and PausableToken
2017-06-29 10:40:43 -03:00
daf1784be4 change inheritance order for StandardToken and PausableToken 2017-06-28 22:15:51 -07:00
de92a02127 Add Crowdsale contracts 2017-06-27 18:34:04 -03:00
82ca385725 Merge pull request #277 from frangio/fix-261
Remove all checks for short address attack
2017-06-26 15:32:56 -03:00
e33d9bb41b remove all checks for short address attack (fixes #261) 2017-06-26 15:11:54 -03:00
79b3a1b1a2 Merge pull request #273 from jooray/patch-1
Fix typo in StandardToken allowance documentation
2017-06-22 13:15:28 -03:00
c6a3c29eb4 Merge pull request #272 from rstormsf/Removal-of-install-script
Removes install script
2017-06-22 10:34:07 -03:00
dd34d8df0f Fix typo in StandardToken allowance documentation 2017-06-22 15:33:34 +02:00
80d052d43f Fixes #253 2017-06-21 17:34:43 -07:00
710f77dfe1 Merge pull request #269 from rstormsf/uint256
change uint to uint256
2017-06-20 12:23:52 -03:00
b1e504d6c6 change uint to uint256 2017-06-19 18:55:09 -07:00
7deaee04c8 Merge pull request #263 from DaveAppleton/master
assert is now built in
2017-06-17 16:36:56 -03:00
2020d56ba4 assert is now built in 2017-06-17 11:10:30 +08:00
a49fe53fa1 Merge pull request #258 from mbrix/master
fixed typo
2017-06-15 13:52:34 -03:00
403e7336a9 fixed typo 2017-06-14 16:31:12 -04:00
fea2a8383c Merge pull request #256 from DavidKnott/refactor-mintable-token
Refactor MintableToken Contract
2017-06-14 16:12:23 -03:00
ffe464a43e Refactors the Mintable Token contract 2017-06-14 10:38:32 -06:00
3fbcb1b282 Merge pull request #250 from jdkanani/yarn-setup
Add yarn support and use it for Travis CI
2017-06-12 12:11:14 -03:00
28b2a0c881 Move npm to yarn 2017-06-11 12:50:26 +05:30
7b9c1429d9 v1.0.7 2017-06-09 19:31:09 -03:00
d53ddd4a95 Merge pull request #242 from DavidKnott/upgrade-truffle-and-solidity
Upgrade to Truffle version 3.2.2 and Solidity version 0.4.11
2017-06-07 15:04:57 -03:00
6ede3d9001 Upgrade to Truffle version 3.2.2 and Solidity version 0.4.11 2017-06-06 21:41:54 -06:00
c3cb0dcf80 Merge pull request #238 from DaveAppleton/master
remove redundant return
2017-06-06 11:02:46 -03:00
f214dccab9 removed redundant returns 2017-06-06 17:10:55 +08:00
c0cce27703 remove redundant return 2017-06-02 00:27:16 +08:00
2eded7a337 Merge pull request #237 from maraoz/coveralls
Add coveralls
2017-05-31 20:30:50 -03:00
41a6f1cd84 add coveralls 2017-05-31 17:15:50 -03:00
98 changed files with 8362 additions and 468 deletions

1
.coveralls.yml Normal file
View File

@ -0,0 +1 @@
repo_token: AelGMv47LJ85e3KF1PhYBsjyduSjDmP0h

5
.solcover.js Normal file
View File

@ -0,0 +1,5 @@
module.exports = {
norpc: true,
testCommand: 'node --max-old-space-size=4096 ../node_modules/.bin/truffle test --network coverage',
skipFiles: ['lifecycle/Migrations.sol']
}

View File

@ -1,12 +1,12 @@
dist: trusty
sudo: false
sudo: required
group: beta
language: node_js
node_js:
- "6"
before_install:
- npm install truffle@3.1.9 -g
- npm i -g ethereumjs-testrpc
cache:
yarn: true
script:
- testrpc > /dev/null &
- truffle test
- yarn test
after_script:
- yarn run coveralls

View File

@ -1,6 +1,7 @@
# Zeppelin Solidity
[![NPM Package](https://img.shields.io/npm/v/zeppelin-solidity.svg?style=flat-square)](https://www.npmjs.org/package/zeppelin-solidity)
[![Build Status](https://img.shields.io/travis/OpenZeppelin/zeppelin-solidity.svg?branch=master&style=flat-square)](https://travis-ci.org/OpenZeppelin/zeppelin-solidity)
[![Coverage Status](https://coveralls.io/repos/github/OpenZeppelin/zeppelin-solidity/badge.svg?branch=coveralls)](https://coveralls.io/github/OpenZeppelin/zeppelin-solidity?branch=coveralls)
OpenZeppelin is a library for writing secure [Smart Contracts](https://en.wikipedia.org/wiki/Smart_contract) on Ethereum.
@ -23,6 +24,9 @@ truffle init
To install the OpenZeppelin library, run:
```sh
npm install zeppelin-solidity
# If you are using yarn, add dependency like this -
yarn add zeppelin-solidity
```
After that, you'll get all the library's contracts in the `node_modules/zeppelin-solidity/contracts` folder. You can use the contracts in the library like so:

View File

@ -48,7 +48,7 @@ We think much more could be done here, and recommend the OpenZeppelin team keep
## Solidity Version Updates Recommended
Most of the code uses Solidity 0.4.8, but some files under `Ownership` are marked 0.4.0. These should be updated.
Most of the code uses Solidity 0.4.11, but some files under `Ownership` are marked 0.4.0. These should be updated.
Solidity 0.4.10 will add several features which could be useful in these contracts:

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import './payment/PullPayment.sol';
@ -19,13 +19,11 @@ contract Bounty is PullPayment, Destructible {
* @dev Fallback function allowing the contract to recieve funds, if they haven't already been claimed.
*/
function() payable {
if (claimed) {
throw;
}
require(!claimed);
}
/**
* @dev Create and deploy the target contract (extension of Target contract), and sets the
* @dev Create and deploy the target contract (extension of Target contract), and sets the
* msg.sender as a researcher
* @return A target contract
*/
@ -48,13 +46,9 @@ contract Bounty is PullPayment, Destructible {
*/
function claim(Target target) {
address researcher = researchers[target];
if (researcher == 0) {
throw;
}
require(researcher != 0);
// Check Target contract invariants
if (target.checkInvariant()) {
throw;
}
require(!target.checkInvariant());
asyncSend(researcher, this.balance);
claimed = true;
}
@ -69,10 +63,10 @@ contract Bounty is PullPayment, Destructible {
contract Target {
/**
* @dev Checks all values a contract assumes to be true all the time. If this function returns
* false, the contract is broken in some way and is in an inconsistent state.
* In order to win the bounty, security researchers will try to cause this broken state.
* @return True if all invariant values are correct, false otherwise.
* @dev Checks all values a contract assumes to be true all the time. If this function returns
* false, the contract is broken in some way and is in an inconsistent state.
* In order to win the bounty, security researchers will try to cause this broken state.
* @return True if all invariant values are correct, false otherwise.
*/
function checkInvariant() returns(bool);
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
/**
* @title DayLimit
@ -7,24 +7,24 @@ pragma solidity ^0.4.8;
*/
contract DayLimit {
uint public dailyLimit;
uint public spentToday;
uint public lastDay;
uint256 public dailyLimit;
uint256 public spentToday;
uint256 public lastDay;
/**
* @dev Constructor that sets the passed value as a dailyLimit.
* @param _limit Uint to represent the daily limit.
* @param _limit uint256 to represent the daily limit.
*/
function DayLimit(uint _limit) {
function DayLimit(uint256 _limit) {
dailyLimit = _limit;
lastDay = today();
}
/**
* @dev sets the daily limit. Does not alter the amount already spent today.
* @param _newLimit Uint to represent the new limit.
* @param _newLimit uint256 to represent the new limit.
*/
function _setDailyLimit(uint _newLimit) internal {
function _setDailyLimit(uint256 _newLimit) internal {
dailyLimit = _newLimit;
}
@ -37,10 +37,10 @@ contract DayLimit {
/**
* @dev Checks to see if there is enough resource to spend today. If true, the resource may be expended.
* @param _value Uint representing the amount of resource to spend.
* @param _value uint256 representing the amount of resource to spend.
* @return A boolean that is True if the resource was spended and false otherwise.
*/
function underLimit(uint _value) internal returns (bool) {
function underLimit(uint256 _value) internal returns (bool) {
// reset the spend limit if we're on a different day to last time.
if (today() > lastDay) {
spentToday = 0;
@ -57,19 +57,17 @@ contract DayLimit {
/**
* @dev Private function to determine today's index
* @return Uint of today's index.
* @return uint256 of today's index.
*/
function today() private constant returns (uint) {
function today() private constant returns (uint256) {
return now / 1 days;
}
/**
* @dev Simple modifier for daily limit.
*/
modifier limitedDaily(uint _value) {
if (!underLimit(_value)) {
throw;
}
modifier limitedDaily(uint256 _value) {
require(underLimit(_value));
_;
}
}

47
contracts/ECRecovery.sol Normal file
View File

@ -0,0 +1,47 @@
pragma solidity ^0.4.11;
/**
* @title Eliptic curve signature operations
*
* @dev Based on https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d
*/
library ECRecovery {
/**
* @dev Recover signer address from a message by using his signature
* @param hash bytes32 message, the hash is the signed message. What is recovered is the signer address.
* @param sig bytes signature, the signature is generated using web3.eth.sign()
*/
function recover(bytes32 hash, bytes sig) constant returns (address) {
bytes32 r;
bytes32 s;
uint8 v;
//Check the signature length
if (sig.length != 65) {
return (address(0));
}
// Divide the signature in r, s and v variables
assembly {
r := mload(add(sig, 32))
s := mload(add(sig, 64))
v := byte(0, mload(add(sig, 96)))
}
// Version of signature should be 27 or 28, but 0 and 1 are also possible versions
if (v < 27) {
v += 27;
}
// If the version is correct return the signer address
if (v != 27 && v != 28) {
return (address(0));
} else {
return ecrecover(hash, v, r, s);
}
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
/**
@ -9,13 +9,13 @@ pragma solidity ^0.4.8;
*/
contract LimitBalance {
uint public limit;
uint256 public limit;
/**
* @dev Constructor that sets the passed value as a limit.
* @param _limit Uint to represent the limit.
* @dev Constructor that sets the passed value as a limit.
* @param _limit uint256 to represent the limit.
*/
function LimitBalance(uint _limit) {
function LimitBalance(uint256 _limit) {
limit = _limit;
}
@ -23,9 +23,7 @@ contract LimitBalance {
* @dev Checks if limit was reached. Case true, it throws.
*/
modifier limitedPayable() {
if (this.balance > limit) {
throw;
}
require(this.balance <= limit);
_;
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import "./ownership/Multisig.sol";
@ -16,7 +16,7 @@ contract MultisigWallet is Multisig, Shareable, DayLimit {
struct Transaction {
address to;
uint value;
uint256 value;
bytes data;
}
@ -25,19 +25,19 @@ contract MultisigWallet is Multisig, Shareable, DayLimit {
* @param _owners A list of owners.
* @param _required The amount required for a transaction to be approved.
*/
function MultisigWallet(address[] _owners, uint _required, uint _daylimit)
Shareable(_owners, _required)
function MultisigWallet(address[] _owners, uint256 _required, uint256 _daylimit)
Shareable(_owners, _required)
DayLimit(_daylimit) { }
/**
* @dev destroys the contract sending everything to `_to`.
/**
* @dev destroys the contract sending everything to `_to`.
*/
function destroy(address _to) onlymanyowners(keccak256(msg.data)) external {
selfdestruct(_to);
}
/**
* @dev Fallback function, receives value and emits a deposit event.
/**
* @dev Fallback function, receives value and emits a deposit event.
*/
function() payable {
// just being sent some cash?
@ -46,22 +46,22 @@ contract MultisigWallet is Multisig, Shareable, DayLimit {
}
/**
* @dev Outside-visible transaction entry point. Executes transaction immediately if below daily
* spending 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,
* @dev Outside-visible transaction entry point. Executes transaction immediately if below daily
* spending 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.
* @param _to The receiver address
* @param _value The value to send
* @param _data The data part of the transaction
*/
function execute(address _to, uint _value, bytes _data) external onlyOwner returns (bytes32 _r) {
function execute(address _to, uint256 _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;
revert();
}
return 0;
}
@ -76,30 +76,28 @@ contract MultisigWallet is Multisig, Shareable, DayLimit {
}
/**
* @dev Confirm a transaction by providing just the hash. We use the previous transactions map,
* @dev Confirm a transaction by providing just the hash. We use the previous transactions map,
* txs, in order to determine the body of the transaction from the hash provided.
* @param _h The transaction hash to approve.
*/
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;
}
assert(txs[_h].to.call.value(txs[_h].value)(txs[_h].data));
MultiTransact(msg.sender, _h, txs[_h].value, txs[_h].to, txs[_h].data);
delete txs[_h];
return true;
}
}
/**
* @dev Updates the daily limit value.
* @param _newLimit
/**
* @dev Updates the daily limit value.
* @param _newLimit uint256 to represent the new limit.
*/
function setDailyLimit(uint _newLimit) onlymanyowners(keccak256(msg.data)) external {
function setDailyLimit(uint256 _newLimit) onlymanyowners(keccak256(msg.data)) external {
_setDailyLimit(_newLimit);
}
/**
/**
* @dev Resets the value spent to enable more spending
*/
function resetSpentToday() onlymanyowners(keccak256(msg.data)) external {
@ -108,12 +106,12 @@ contract MultisigWallet is Multisig, Shareable, DayLimit {
// INTERNAL METHODS
/**
/**
* @dev Clears the list of transactions pending approval.
*/
function clearPending() internal {
uint length = pendingsIndex.length;
for (uint i = 0; i < length; ++i) {
uint256 length = pendingsIndex.length;
for (uint256 i = 0; i < length; ++i) {
delete txs[pendingsIndex[i]];
}
super.clearPending();

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
/**
* @title Helps contracts guard agains rentrancy attacks.
@ -9,7 +9,7 @@ pragma solidity ^0.4.8;
contract ReentrancyGuard {
/**
* @dev We use a single lock for the whole contract.
* @dev We use a single lock for the whole contract.
*/
bool private rentrancy_lock = false;
@ -22,13 +22,10 @@ contract ReentrancyGuard {
* wrapper marked as `nonReentrant`.
*/
modifier nonReentrant() {
if(rentrancy_lock == false) {
rentrancy_lock = true;
_;
rentrancy_lock = false;
} else {
throw;
}
require(!rentrancy_lock);
rentrancy_lock = true;
_;
rentrancy_lock = false;
}
}

View File

@ -1,53 +0,0 @@
pragma solidity ^0.4.8;
/**
* Math operations with safety checks
*/
library SafeMath {
function mul(uint a, uint b) internal returns (uint) {
uint c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function div(uint a, uint b) internal returns (uint) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint a, uint b) internal returns (uint) {
assert(b <= a);
return a - b;
}
function add(uint a, uint b) internal returns (uint) {
uint c = a + b;
assert(c >= a);
return c;
}
function max64(uint64 a, uint64 b) internal constant returns (uint64) {
return a >= b ? a : b;
}
function min64(uint64 a, uint64 b) internal constant returns (uint64) {
return a < b ? a : b;
}
function max256(uint256 a, uint256 b) internal constant returns (uint256) {
return a >= b ? a : b;
}
function min256(uint256 a, uint256 b) internal constant returns (uint256) {
return a < b ? a : b;
}
function assert(bool assertion) internal {
if (!assertion) {
throw;
}
}
}

View File

@ -0,0 +1,34 @@
pragma solidity ^0.4.11;
import '../math/SafeMath.sol';
import './Crowdsale.sol';
/**
* @title CappedCrowdsale
* @dev Extension of Crowsdale with a max amount of funds raised
*/
contract CappedCrowdsale is Crowdsale {
using SafeMath for uint256;
uint256 public cap;
function CappedCrowdsale(uint256 _cap) {
require(_cap > 0);
cap = _cap;
}
// overriding Crowdsale#validPurchase to add extra cap logic
// @return true if investors can buy at the moment
function validPurchase() internal constant returns (bool) {
bool withinCap = weiRaised.add(msg.value) <= cap;
return super.validPurchase() && withinCap;
}
// overriding Crowdsale#hasEnded to add cap logic
// @return true if crowdsale event has ended
function hasEnded() public constant returns (bool) {
bool capReached = weiRaised >= cap;
return super.hasEnded() || capReached;
}
}

View File

@ -0,0 +1,107 @@
pragma solidity ^0.4.11;
import '../token/MintableToken.sol';
import '../math/SafeMath.sol';
/**
* @title Crowdsale
* @dev Crowdsale is a base contract for managing a token crowdsale.
* Crowdsales have a start and end block, where investors can make
* token purchases and the crowdsale will assign them tokens based
* on a token per ETH rate. Funds collected are forwarded to a wallet
* as they arrive.
*/
contract Crowdsale {
using SafeMath for uint256;
// The token being sold
MintableToken public token;
// start and end block where investments are allowed (both inclusive)
uint256 public startBlock;
uint256 public endBlock;
// address where funds are collected
address public wallet;
// how many token units a buyer gets per wei
uint256 public rate;
// amount of raised money in wei
uint256 public weiRaised;
/**
* event for token purchase logging
* @param purchaser who paid for the tokens
* @param beneficiary who got the tokens
* @param value weis paid for purchase
* @param amount amount of tokens purchased
*/
event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);
function Crowdsale(uint256 _startBlock, uint256 _endBlock, uint256 _rate, address _wallet) {
require(_startBlock >= block.number);
require(_endBlock >= _startBlock);
require(_rate > 0);
require(_wallet != 0x0);
token = createTokenContract();
startBlock = _startBlock;
endBlock = _endBlock;
rate = _rate;
wallet = _wallet;
}
// creates the token to be sold.
// override this method to have crowdsale of a specific mintable token.
function createTokenContract() internal returns (MintableToken) {
return new MintableToken();
}
// fallback function can be used to buy tokens
function () payable {
buyTokens(msg.sender);
}
// low level token purchase function
function buyTokens(address beneficiary) payable {
require(beneficiary != 0x0);
require(validPurchase());
uint256 weiAmount = msg.value;
// calculate token amount to be created
uint256 tokens = weiAmount.mul(rate);
// update state
weiRaised = weiRaised.add(weiAmount);
token.mint(beneficiary, tokens);
TokenPurchase(msg.sender, beneficiary, weiAmount, tokens);
forwardFunds();
}
// send ether to the fund collection wallet
// override to create custom fund forwarding mechanisms
function forwardFunds() internal {
wallet.transfer(msg.value);
}
// @return true if the transaction can buy tokens
function validPurchase() internal constant returns (bool) {
uint256 current = block.number;
bool withinPeriod = current >= startBlock && current <= endBlock;
bool nonZeroPurchase = msg.value != 0;
return withinPeriod && nonZeroPurchase;
}
// @return true if crowdsale event has ended
function hasEnded() public constant returns (bool) {
return block.number > endBlock;
}
}

View File

@ -0,0 +1,39 @@
pragma solidity ^0.4.11;
import '../math/SafeMath.sol';
import '../ownership/Ownable.sol';
import './Crowdsale.sol';
/**
* @title FinalizableCrowdsale
* @dev Extension of Crowsdale where an owner can do extra work
* after finishing. By default, it will end token minting.
*/
contract FinalizableCrowdsale is Crowdsale, Ownable {
using SafeMath for uint256;
bool public isFinalized = false;
event Finalized();
// should be called after crowdsale ends, to do
// some extra finalization work
function finalize() onlyOwner {
require(!isFinalized);
require(hasEnded());
finalization();
Finalized();
isFinalized = true;
}
// end token minting on finalization
// override this with custom logic if needed
function finalization() internal {
token.finishMinting();
}
}

View File

@ -0,0 +1,56 @@
pragma solidity ^0.4.11;
import '../math/SafeMath.sol';
import '../ownership/Ownable.sol';
/**
* @title RefundVault
* @dev This contract is used for storing funds while a crowdsale
* is in progress. Supports refunding the money if crowdsale fails,
* and forwarding it if crowdsale is successful.
*/
contract RefundVault is Ownable {
using SafeMath for uint256;
enum State { Active, Refunding, Closed }
mapping (address => uint256) public deposited;
address public wallet;
State public state;
event Closed();
event RefundsEnabled();
event Refunded(address indexed beneficiary, uint256 weiAmount);
function RefundVault(address _wallet) {
require(_wallet != 0x0);
wallet = _wallet;
state = State.Active;
}
function deposit(address investor) onlyOwner payable {
require(state == State.Active);
deposited[investor] = deposited[investor].add(msg.value);
}
function close() onlyOwner {
require(state == State.Active);
state = State.Closed;
Closed();
wallet.transfer(this.balance);
}
function enableRefunds() onlyOwner {
require(state == State.Active);
state = State.Refunding;
RefundsEnabled();
}
function refund(address investor) {
require(state == State.Refunding);
uint256 depositedValue = deposited[investor];
deposited[investor] = 0;
investor.transfer(depositedValue);
Refunded(investor, depositedValue);
}
}

View File

@ -0,0 +1,60 @@
pragma solidity ^0.4.11;
import '../math/SafeMath.sol';
import './FinalizableCrowdsale.sol';
import './RefundVault.sol';
/**
* @title RefundableCrowdsale
* @dev Extension of Crowdsale contract that adds a funding goal, and
* the possibility of users getting a refund if goal is not met.
* Uses a RefundVault as the crowdsale's vault.
*/
contract RefundableCrowdsale is FinalizableCrowdsale {
using SafeMath for uint256;
// minimum amount of funds to be raised in weis
uint256 public goal;
// refund vault used to hold funds while crowdsale is running
RefundVault public vault;
function RefundableCrowdsale(uint256 _goal) {
require(_goal > 0);
vault = new RefundVault(wallet);
goal = _goal;
}
// We're overriding the fund forwarding from Crowdsale.
// In addition to sending the funds, we want to call
// the RefundVault deposit function
function forwardFunds() internal {
vault.deposit.value(msg.value)(msg.sender);
}
// if crowdsale is unsuccessful, investors can claim refunds here
function claimRefund() {
require(isFinalized);
require(!goalReached());
vault.refund(msg.sender);
}
// vault finalization task, called when owner calls finalize()
function finalization() internal {
if (goalReached()) {
vault.close();
} else {
vault.enableRefunds();
}
super.finalization();
}
function goalReached() public constant returns (bool) {
return weiRaised >= goal;
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import "../ownership/Ownable.sol";
@ -10,6 +10,8 @@ import "../ownership/Ownable.sol";
*/
contract Destructible is Ownable {
function Destructible() payable { }
/**
* @dev Transfers the current balance to the owner and terminates the contract.
*/

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import '../ownership/Ownable.sol';
@ -8,9 +8,9 @@ import '../ownership/Ownable.sol';
* @dev This is a truffle contract, needed for truffle integration, not meant for use by Zeppelin users.
*/
contract Migrations is Ownable {
uint public lastCompletedMigration;
uint256 public lastCompletedMigration;
function setCompleted(uint completed) onlyOwner {
function setCompleted(uint256 completed) onlyOwner {
lastCompletedMigration = completed;
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import "../ownership/Ownable.sol";
@ -19,7 +19,7 @@ contract Pausable is Ownable {
* @dev modifier to allow actions only when the contract IS paused
*/
modifier whenNotPaused() {
if (paused) throw;
require(!paused);
_;
}
@ -27,7 +27,7 @@ contract Pausable is Ownable {
* @dev modifier to allow actions only when the contract IS NOT paused
*/
modifier whenPaused {
if (!paused) throw;
require(paused);
_;
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import "../ownership/Ownable.sol";
@ -12,6 +12,8 @@ import "../token/ERC20Basic.sol";
*/
contract TokenDestructible is Ownable {
function TokenDestructible() payable { }
/**
* @notice Terminate contract and refund to owner
* @param tokens List of addresses of ERC20 or ERC20Basic token contracts to
@ -22,7 +24,7 @@ contract TokenDestructible is Ownable {
function destroy(address[] tokens) onlyOwner {
// Transfer tokens to owner
for(uint i = 0; i < tokens.length; i++) {
for(uint256 i = 0; i < tokens.length; i++) {
ERC20Basic token = ERC20Basic(tokens[i]);
uint256 balance = token.balanceOf(this);
token.transfer(owner, balance);

24
contracts/math/Math.sol Normal file
View File

@ -0,0 +1,24 @@
pragma solidity ^0.4.11;
/**
* @title Math
* @dev Assorted math operations
*/
library Math {
function max64(uint64 a, uint64 b) internal constant returns (uint64) {
return a >= b ? a : b;
}
function min64(uint64 a, uint64 b) internal constant returns (uint64) {
return a < b ? a : b;
}
function max256(uint256 a, uint256 b) internal constant returns (uint256) {
return a >= b ? a : b;
}
function min256(uint256 a, uint256 b) internal constant returns (uint256) {
return a < b ? a : b;
}
}

View File

@ -0,0 +1,32 @@
pragma solidity ^0.4.11;
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
function mul(uint256 a, uint256 b) internal constant returns (uint256) {
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal constant returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint256 a, uint256 b) internal constant returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal constant returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import './Ownable.sol';
@ -6,25 +6,23 @@ import './Ownable.sol';
/**
* @title Claimable
* @dev Extension for the Ownable contract, where the ownership needs to be claimed.
* @dev 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;
/**
* @dev Modifier throws if called by any account other than the pendingOwner.
* @dev Modifier throws if called by any account other than the pendingOwner.
*/
modifier onlyPendingOwner() {
if (msg.sender != pendingOwner) {
throw;
}
require(msg.sender == pendingOwner);
_;
}
/**
* @dev Allows the current owner to set the pendingOwner address.
* @param newOwner The address to transfer ownership to.
* @dev Allows the current owner to set the pendingOwner address.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) onlyOwner {
pendingOwner = newOwner;

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import './Ownable.sol';

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import './Claimable.sol';
@ -11,30 +11,28 @@ import './Claimable.sol';
*/
contract DelayedClaimable is Claimable {
uint public end;
uint public start;
uint256 public end;
uint256 public start;
/**
* @dev Used to specify the time period during which a pending
* owner can claim ownership.
* @dev Used to specify the time period during which a pending
* owner can claim ownership.
* @param _start The earliest time ownership can be claimed.
* @param _end The latest time ownership can be claimed.
* @param _end The latest time ownership can be claimed.
*/
function setLimits(uint _start, uint _end) onlyOwner {
if (_start > _end)
throw;
function setLimits(uint256 _start, uint256 _end) onlyOwner {
require(_start <= _end);
end = _end;
start = _start;
}
/**
* @dev Allows the pendingOwner address to finalize the transfer, as long as it is called within
* the specified start and end time.
* @dev Allows the pendingOwner address to finalize the transfer, as long as it is called within
* the specified start and end time.
*/
function claimOwnership() onlyPendingOwner {
if ((block.number > end) || (block.number < start))
throw;
require((block.number <= end) && (block.number >= start));
owner = pendingOwner;
pendingOwner = 0x0;
end = 0;

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import "./Ownable.sol";

View File

@ -1,8 +1,8 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import "./Ownable.sol";
/**
/**
* @title Contracts that should not own Ether
* @author Remco Bloemen <remco@2π.com>
* @dev This tries to block incoming ether to prevent accidental loss of Ether. Should Ether end up
@ -16,15 +16,13 @@ contract HasNoEther is Ownable {
/**
* @dev Constructor that rejects incoming Ether
* @dev The `payable` flag is added so we can access `msg.value` without compiler warning. If we
* leave out payable, then Solidity will allow inheriting contracts to implement a payable
* constructor. By doing it this way we prevent a payable constructor from working. Alternatively
* @dev The `payable` flag is added so we can access `msg.value` without compiler warning. If we
* leave out payable, then Solidity will allow inheriting contracts to implement a payable
* constructor. By doing it this way we prevent a payable constructor from working. Alternatively
* we could use assembly to access msg.value.
*/
function HasNoEther() payable {
if(msg.value > 0) {
throw;
}
require(msg.value == 0);
}
/**
@ -37,8 +35,6 @@ contract HasNoEther is Ownable {
* @dev Transfer all Ether held by the contract to the owner.
*/
function reclaimEther() external onlyOwner {
if(!owner.send(this.balance)) {
throw;
}
assert(owner.send(this.balance));
}
}

View File

@ -1,9 +1,9 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import "./Ownable.sol";
import "../token/ERC20Basic.sol";
/**
/**
* @title Contracts that should not own Tokens
* @author Remco Bloemen <remco@2π.com>
* @dev This blocks incoming ERC23 tokens to prevent accidental loss of tokens.
@ -12,14 +12,14 @@ import "../token/ERC20Basic.sol";
*/
contract HasNoTokens is Ownable {
/**
/**
* @dev Reject all ERC23 compatible tokens
* @param from_ address The address that is transferring the tokens
* @param value_ Uint the amount of the specified token
* @param value_ uint256 the amount of the specified token
* @param data_ Bytes The data passed from the caller.
*/
function tokenFallback(address from_, uint value_, bytes data_) external {
throw;
function tokenFallback(address from_, uint256 value_, bytes data_) external {
revert();
}
/**

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
/**
@ -10,19 +10,19 @@ contract Multisig {
// logged events:
// Funds has arrived into the wallet (record how much).
event Deposit(address _from, uint value);
event Deposit(address _from, uint256 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);
event SingleTransact(address owner, uint256 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);
event MultiTransact(address owner, bytes32 operation, uint256 value, address to, bytes data);
// Confirmation still needed for a transaction.
event ConfirmationNeeded(bytes32 operation, address initiator, uint value, address to, bytes data);
event ConfirmationNeeded(bytes32 operation, address initiator, uint256 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 execute(address _to, uint256 _value, bytes _data) external returns (bytes32);
function confirm(bytes32 _h) returns (bool);
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import "./HasNoEther.sol";
import "./HasNoTokens.sol";

View File

@ -1,16 +1,16 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;
/**
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
@ -20,19 +20,17 @@ contract Ownable {
/**
* @dev Throws if called by any account other than the owner.
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
if (msg.sender != owner) {
throw;
}
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) onlyOwner {
if (newOwner != address(0)) {

View File

@ -1,9 +1,9 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
/**
* @title Shareable
* @dev inheritable "property" contract that enables methods to be protected by requiring the
* @dev 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.
* @dev 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.
*/
@ -11,18 +11,18 @@ contract Shareable {
// struct for the status of a pending operation.
struct PendingState {
uint yetNeeded;
uint ownersDone;
uint index;
uint256 yetNeeded;
uint256 ownersDone;
uint256 index;
}
// the number of owners that must confirm the same operation before it is run.
uint public required;
uint256 public required;
// list of owners
address[256] owners;
// index on the list of owners to allow reverse lookup
mapping(address => uint) ownerIndex;
mapping(address => uint256) ownerIndex;
// the ongoing operations.
mapping(bytes32 => PendingState) pendings;
bytes32[] pendingsIndex;
@ -36,14 +36,12 @@ contract Shareable {
// simple single-sig function modifier.
modifier onlyOwner {
if (!isOwner(msg.sender)) {
throw;
}
require(isOwner(msg.sender));
_;
}
/**
* @dev Modifier for multisig functions.
/**
* @dev Modifier for multisig functions.
* @param _operation 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.
*/
@ -53,23 +51,21 @@ contract Shareable {
}
}
/**
* @dev Constructor is given the number of sigs required to do protected "onlymanyowners"
/**
* @dev Constructor is given the number of sigs required to do protected "onlymanyowners"
* transactions as well as the selection of addresses capable of confirming them.
* @param _owners A list of owners.
* @param _required The amount required for a transaction to be approved.
*/
function Shareable(address[] _owners, uint _required) {
function Shareable(address[] _owners, uint256 _required) {
owners[1] = msg.sender;
ownerIndex[msg.sender] = 1;
for (uint i = 0; i < _owners.length; ++i) {
for (uint256 i = 0; i < _owners.length; ++i) {
owners[2 + i] = _owners[i];
ownerIndex[_owners[i]] = 2 + i;
}
required = _required;
if (required > owners.length) {
throw;
}
require(required <= owners.length);
}
/**
@ -77,12 +73,12 @@ contract Shareable {
* @param _operation A string identifying the operation.
*/
function revoke(bytes32 _operation) external {
uint index = ownerIndex[msg.sender];
uint256 index = ownerIndex[msg.sender];
// make sure they're an owner
if (index == 0) {
return;
}
uint ownerIndexBit = 2**index;
uint256 ownerIndexBit = 2**index;
var pending = pendings[_operation];
if (pending.ownersDone & ownerIndexBit > 0) {
pending.yetNeeded++;
@ -93,10 +89,10 @@ contract Shareable {
/**
* @dev Gets an owner by 0-indexed position (using numOwners as the count)
* @param ownerIndex Uint The index of the owner
* @param ownerIndex uint256 The index of the owner
* @return The address of the owner
*/
function getOwner(uint ownerIndex) external constant returns (address) {
function getOwner(uint256 ownerIndex) external constant returns (address) {
return address(owners[ownerIndex + 1]);
}
@ -117,7 +113,7 @@ contract Shareable {
*/
function hasConfirmed(bytes32 _operation, address _owner) constant returns (bool) {
var pending = pendings[_operation];
uint index = ownerIndex[_owner];
uint256 index = ownerIndex[_owner];
// make sure they're an owner
if (index == 0) {
@ -125,7 +121,7 @@ contract Shareable {
}
// determine the bit to set for this owner.
uint ownerIndexBit = 2**index;
uint256 ownerIndexBit = 2**index;
return !(pending.ownersDone & ownerIndexBit == 0);
}
@ -136,11 +132,9 @@ contract Shareable {
*/
function confirmAndCheck(bytes32 _operation) internal returns (bool) {
// determine what index the present sender is:
uint index = ownerIndex[msg.sender];
uint256 index = ownerIndex[msg.sender];
// make sure they're an owner
if (index == 0) {
throw;
}
require(index != 0);
var pending = pendings[_operation];
// if we're not yet working on this operation, switch over and reset the confirmation status.
@ -153,7 +147,7 @@ contract Shareable {
pendingsIndex[pending.index] = _operation;
}
// determine the bit to set for this owner.
uint ownerIndexBit = 2**index;
uint256 ownerIndexBit = 2**index;
// make sure we (the message sender) haven't confirmed this operation previously.
if (pending.ownersDone & ownerIndexBit == 0) {
Confirmation(msg.sender, _operation);
@ -177,8 +171,8 @@ contract Shareable {
* @dev Clear the pending list.
*/
function clearPending() internal {
uint length = pendingsIndex.length;
for (uint i = 0; i < length; ++i) {
uint256 length = pendingsIndex.length;
for (uint256 i = 0; i < length; ++i) {
if (pendingsIndex[i] != 0) {
delete pendings[pendingsIndex[i]];
}

View File

@ -1,7 +1,7 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import '../SafeMath.sol';
import '../math/SafeMath.sol';
/**
@ -10,17 +10,17 @@ import '../SafeMath.sol';
* contract and use asyncSend instead of send.
*/
contract PullPayment {
using SafeMath for uint;
using SafeMath for uint256;
mapping(address => uint) public payments;
uint public totalPayments;
mapping(address => uint256) public payments;
uint256 public totalPayments;
/**
* @dev Called by the payer to store the sent amount as credit to be pulled.
* @param dest The destination address of the funds.
* @param amount The amount to transfer.
*/
function asyncSend(address dest, uint amount) internal {
function asyncSend(address dest, uint256 amount) internal {
payments[dest] = payments[dest].add(amount);
totalPayments = totalPayments.add(amount);
}
@ -30,21 +30,14 @@ contract PullPayment {
*/
function withdrawPayments() {
address payee = msg.sender;
uint payment = payments[payee];
uint256 payment = payments[payee];
if (payment == 0) {
throw;
}
if (this.balance < payment) {
throw;
}
require(payment != 0);
require(this.balance >= payment);
totalPayments = totalPayments.sub(payment);
payments[payee] = 0;
if (!payee.send(payment)) {
throw;
}
assert(payee.send(payment));
}
}

View File

@ -1,8 +1,8 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import './ERC20Basic.sol';
import '../SafeMath.sol';
import '../math/SafeMath.sol';
/**
@ -10,37 +10,28 @@ import '../SafeMath.sol';
* @dev Basic version of StandardToken, with no allowances.
*/
contract BasicToken is ERC20Basic {
using SafeMath for uint;
using SafeMath for uint256;
mapping(address => uint) balances;
/**
* @dev Fix for the ERC20 short address attack.
*/
modifier onlyPayloadSize(uint size) {
if(msg.data.length < size + 4) {
throw;
}
_;
}
mapping(address => uint256) balances;
/**
* @dev transfer token for a specified address
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint _value) onlyPayloadSize(2 * 32) {
function transfer(address _to, uint256 _value) returns (bool) {
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the the balance of.
* @return An uint representing the amount owned by the passed address.
* @return An uint256 representing the amount owned by the passed address.
*/
function balanceOf(address _owner) constant returns (uint balance) {
function balanceOf(address _owner) constant returns (uint256 balance) {
return balances[_owner];
}

View File

@ -1,60 +0,0 @@
pragma solidity ^0.4.8;
import "./StandardToken.sol";
/**
* @title CrowdsaleToken
*
* @dev Simple ERC20 Token example, with crowdsale token creation
* @dev IMPORTANT NOTE: do not use or deploy this contract as-is. It needs some changes to be
* production ready.
*/
contract CrowdsaleToken is StandardToken {
string public constant name = "CrowdsaleToken";
string public constant symbol = "CRW";
uint public constant decimals = 18;
// replace with your fund collection multisig address
address public constant multisig = 0x0;
// 1 ether = 500 example tokens
uint public constant PRICE = 500;
/**
* @dev Fallback function which receives ether and sends the appropriate number of tokens to the
* msg.sender.
*/
function () payable {
createTokens(msg.sender);
}
/**
* @dev Creates tokens and send to the specified address.
* @param recipient The address which will recieve the new tokens.
*/
function createTokens(address recipient) payable {
if (msg.value == 0) {
throw;
}
uint tokens = msg.value.mul(getPrice());
totalSupply = totalSupply.add(tokens);
balances[recipient] = balances[recipient].add(tokens);
if (!multisig.send(msg.value)) {
throw;
}
}
/**
* @dev replace this with any other price function
* @return The price per unit of token.
*/
function getPrice() constant returns (uint result) {
return PRICE;
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import './ERC20Basic.sol';
@ -9,8 +9,8 @@ import './ERC20Basic.sol';
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 is ERC20Basic {
function allowance(address owner, address spender) constant returns (uint);
function transferFrom(address from, address to, uint value);
function approve(address spender, uint value);
event Approval(address indexed owner, address indexed spender, uint value);
function allowance(address owner, address spender) constant returns (uint256);
function transferFrom(address from, address to, uint256 value) returns (bool);
function approve(address spender, uint256 value) returns (bool);
event Approval(address indexed owner, address indexed spender, uint256 value);
}

View File

@ -1,14 +1,14 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
* @dev see https://github.com/ethereum/EIPs/issues/179
*/
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);
uint256 public totalSupply;
function balanceOf(address who) constant returns (uint256);
function transfer(address to, uint256 value) returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}

View File

@ -1,14 +1,14 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import "./ERC20.sol";
/**
* @title LimitedTransferToken
* @dev LimitedTransferToken defines the generic interface and the implementation to limit token
* transferability for different events. It is intended to be used as a base class for other token
* contracts.
* @dev LimitedTransferToken defines the generic interface and the implementation to limit token
* transferability for different events. It is intended to be used as a base class for other token
* contracts.
* LimitedTransferToken has been designed to allow for different limiting factors,
* this can be achieved by recursively calling super.transferableTokens() until the base class is
* this can be achieved by recursively calling super.transferableTokens() until the base class is
* hit. For example:
* function transferableTokens(address holder, uint64 time) constant public returns (uint256) {
* return min256(unlockedTokens, super.transferableTokens(holder, time));
@ -22,8 +22,8 @@ contract LimitedTransferToken is ERC20 {
/**
* @dev Checks whether it can transfer or otherwise throws.
*/
modifier canTransfer(address _sender, uint _value) {
if (_value > transferableTokens(_sender, uint64(now))) throw;
modifier canTransfer(address _sender, uint256 _value) {
require(_value <= transferableTokens(_sender, uint64(now)));
_;
}
@ -32,8 +32,8 @@ contract LimitedTransferToken is ERC20 {
* @param _to The address that will recieve the tokens.
* @param _value The amount of tokens to be transferred.
*/
function transfer(address _to, uint _value) canTransfer(msg.sender, _value) {
return super.transfer(_to, _value);
function transfer(address _to, uint256 _value) canTransfer(msg.sender, _value) returns (bool) {
return super.transfer(_to, _value);
}
/**
@ -42,13 +42,13 @@ contract LimitedTransferToken is ERC20 {
* @param _to The address that will recieve the tokens.
* @param _value The amount of tokens to be transferred.
*/
function transferFrom(address _from, address _to, uint _value) canTransfer(_from, _value) {
return super.transferFrom(_from, _to, _value);
function transferFrom(address _from, address _to, uint256 _value) canTransfer(_from, _value) returns (bool) {
return super.transferFrom(_from, _to, _value);
}
/**
* @dev Default transferable tokens function returns all tokens for a holder (no limit).
* @dev Overwriting transferableTokens(address holder, uint64 time) is the way to provide the
* @dev Overwriting transferableTokens(address holder, uint64 time) is the way to provide the
* specific logic for limiting token transferability for a holder over time.
*/
function transferableTokens(address holder, uint64 time) constant public returns (uint256) {

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import './StandardToken.sol';
@ -14,15 +14,14 @@ import '../ownership/Ownable.sol';
*/
contract MintableToken is StandardToken, Ownable {
event Mint(address indexed to, uint value);
event Mint(address indexed to, uint256 amount);
event MintFinished();
bool public mintingFinished = false;
uint public totalSupply = 0;
modifier canMint() {
if(mintingFinished) throw;
require(!mintingFinished);
_;
}
@ -32,7 +31,7 @@ contract MintableToken is StandardToken, Ownable {
* @param _amount The amount of tokens to mint.
* @return A boolean that indicates if the operation was successful.
*/
function mint(address _to, uint _amount) onlyOwner canMint returns (bool) {
function mint(address _to, uint256 _amount) onlyOwner canMint returns (bool) {
totalSupply = totalSupply.add(_amount);
balances[_to] = balances[_to].add(_amount);
Mint(_to, _amount);

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import './StandardToken.sol';
import '../lifecycle/Pausable.sol';
@ -7,19 +7,15 @@ import '../lifecycle/Pausable.sol';
* Pausable token
*
* Simple ERC20 Token example, with pausable token creation
* Issue:
* https://github.com/OpenZeppelin/zeppelin-solidity/issues/194
* Based on code by BCAPtoken:
* https://github.com/BCAPtoken/BCAPToken/blob/5cb5e76338cc47343ba9268663a915337c8b268e/sol/BCAPToken.sol#L27
**/
contract PausableToken is Pausable, StandardToken {
contract PausableToken is StandardToken, Pausable {
function transfer(address _to, uint _value) whenNotPaused {
function transfer(address _to, uint _value) whenNotPaused returns (bool) {
return super.transfer(_to, _value);
}
function transferFrom(address _from, address _to, uint _value) whenNotPaused {
function transferFrom(address _from, address _to, uint _value) whenNotPaused returns (bool) {
return super.transferFrom(_from, _to, _value);
}
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import "./StandardToken.sol";
@ -14,8 +14,8 @@ contract SimpleToken is StandardToken {
string public name = "SimpleToken";
string public symbol = "SIM";
uint public decimals = 18;
uint public INITIAL_SUPPLY = 10000;
uint256 public decimals = 18;
uint256 public INITIAL_SUPPLY = 10000;
/**
* @dev Contructor that gives msg.sender all of existing tokens.

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import './BasicToken.sol';
@ -8,57 +8,59 @@ import './ERC20.sol';
/**
* @title Standard ERC20 token
*
* @dev Implemantation of the basic standart token.
* @dev Implementation of the basic standard token.
* @dev https://github.com/ethereum/EIPs/issues/20
* @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*/
contract StandardToken is BasicToken, ERC20 {
contract StandardToken is ERC20, BasicToken {
mapping (address => mapping (address => uint)) allowed;
mapping (address => mapping (address => uint256)) allowed;
/**
* @dev Transfer tokens from one address to another
* @param _from address The address which you want to send tokens from
* @param _to address The address which you want to transfer to
* @param _value uint the amout of tokens to be transfered
* @param _value uint256 the amout of tokens to be transfered
*/
function transferFrom(address _from, address _to, uint _value) onlyPayloadSize(3 * 32) {
function transferFrom(address _from, address _to, uint256 _value) returns (bool) {
var _allowance = allowed[_from][msg.sender];
// Check is not needed because sub(_allowance, _value) will already throw if this condition is not met
// if (_value > _allowance) throw;
// require (_value <= _allowance);
balances[_to] = balances[_to].add(_value);
balances[_from] = balances[_from].sub(_value);
allowed[_from][msg.sender] = _allowance.sub(_value);
Transfer(_from, _to, _value);
return true;
}
/**
* @dev Aprove the passed address to spend the specified amount of tokens on beahlf of msg.sender.
* @dev Aprove the passed address to spend the specified amount of tokens on behalf of msg.sender.
* @param _spender The address which will spend the funds.
* @param _value The amount of tokens to be spent.
*/
function approve(address _spender, uint _value) {
function approve(address _spender, uint256 _value) returns (bool) {
// To change the approve amount you first have to reduce the addresses`
// allowance to zero by calling `approve(_spender, 0)` if it is not
// already 0 to mitigate the race condition described here:
// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
if ((_value != 0) && (allowed[msg.sender][_spender] != 0)) throw;
require((_value == 0) || (allowed[msg.sender][_spender] == 0));
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
/**
* @dev Function to check the amount of tokens than an owner allowed to a spender.
* @dev Function to check the amount of tokens that an owner allowed to a spender.
* @param _owner address The address which owns the funds.
* @param _spender address The address which will spend the funds.
* @return A uint specifing the amount of tokens still avaible for the spender.
* @return A uint256 specifing the amount of tokens still avaible for the spender.
*/
function allowance(address _owner, address _spender) constant returns (uint remaining) {
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
return allowed[_owner][_spender];
}

View File

@ -0,0 +1,49 @@
pragma solidity ^0.4.11;
import './ERC20Basic.sol';
/**
* @title TokenTimelock
* @dev TokenTimelock is a token holder contract that will allow a
* beneficiary to extract the tokens after a given release time
*/
contract TokenTimelock {
// ERC20 basic token contract being held
ERC20Basic token;
// beneficiary of tokens after they are released
address beneficiary;
// timestamp when token release is enabled
uint releaseTime;
function TokenTimelock(ERC20Basic _token, address _beneficiary, uint _releaseTime) {
require(_releaseTime > now);
token = _token;
beneficiary = _beneficiary;
releaseTime = _releaseTime;
}
/**
* @notice Transfers tokens held by timelock to beneficiary.
* Deprecated: please use TokenTimelock#release instead.
*/
function claim() {
require(msg.sender == beneficiary);
release();
}
/**
* @notice Transfers tokens held by timelock to beneficiary.
*/
function release() {
require(now >= releaseTime);
uint amount = token.balanceOf(this);
require(amount > 0);
token.transfer(beneficiary, amount);
}
}

View File

@ -1,5 +1,6 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import "../math/Math.sol";
import "./StandardToken.sol";
import "./LimitedTransferToken.sol";
@ -44,13 +45,11 @@ contract VestedToken is StandardToken, LimitedTransferToken {
) public {
// Check for date inconsistencies that may cause unexpected behavior
if (_cliff < _start || _vesting < _cliff) {
throw;
}
require(_cliff >= _start && _vesting >= _cliff);
if (tokenGrantsCount(_to) > MAX_GRANTS_PER_ADDRESS) throw; // To prevent a user being spammed and have his balance locked (out of gas attack when calculating vesting).
require(tokenGrantsCount(_to) < MAX_GRANTS_PER_ADDRESS); // To prevent a user being spammed and have his balance locked (out of gas attack when calculating vesting).
uint count = grants[_to].push(
uint256 count = grants[_to].push(
TokenGrant(
_revokable ? msg.sender : 0, // avoid storing an extra 20 bytes when it is non-revokable
_value,
@ -72,16 +71,11 @@ contract VestedToken is StandardToken, LimitedTransferToken {
* @param _holder The address which will have its tokens revoked.
* @param _grantId The id of the token grant.
*/
function revokeTokenGrant(address _holder, uint _grantId) public {
function revokeTokenGrant(address _holder, uint256 _grantId) public {
TokenGrant grant = grants[_holder][_grantId];
if (!grant.revokable) { // Check if grant was revokable
throw;
}
if (grant.granter != msg.sender) { // Only granter can revoke it
throw;
}
require(grant.revokable);
require(grant.granter == msg.sender); // Only granter can revoke it
address receiver = grant.burnsOnRevoke ? 0xdead : msg.sender;
@ -103,12 +97,12 @@ contract VestedToken is StandardToken, LimitedTransferToken {
* @dev Calculate the total amount of transferable tokens of a holder at a given time
* @param holder address The address of the holder
* @param time uint64 The specific time.
* @return An uint representing a holder's total amount of transferable tokens.
* @return An uint256 representing a holder's total amount of transferable tokens.
*/
function transferableTokens(address holder, uint64 time) constant public returns (uint256) {
uint256 grantIndex = tokenGrantsCount(holder);
if (grantIndex == 0) return balanceOf(holder); // shortcut for holder without grants
if (grantIndex == 0) return super.transferableTokens(holder, time); // shortcut for holder without grants
// Iterate through all the grants the holder has, and add all non-vested tokens
uint256 nonVested = 0;
@ -121,15 +115,15 @@ contract VestedToken is StandardToken, LimitedTransferToken {
// Return the minimum of how many vested can transfer and other value
// in case there are other limiting transferability factors (default is balanceOf)
return SafeMath.min256(vestedTransferable, super.transferableTokens(holder, time));
return Math.min256(vestedTransferable, super.transferableTokens(holder, time));
}
/**
* @dev Check the amount of grants that an address has.
* @param _holder The holder of the grants.
* @return A uint representing the total amount of grants.
* @return A uint256 representing the total amount of grants.
*/
function tokenGrantsCount(address _holder) constant returns (uint index) {
function tokenGrantsCount(address _holder) constant returns (uint256 index) {
return grants[_holder].length;
}
@ -140,7 +134,7 @@ contract VestedToken is StandardToken, LimitedTransferToken {
* @param start uint64 A time representing the begining of the grant
* @param cliff uint64 The cliff period.
* @param vesting uint64 The vesting period.
* @return An uint representing the amount of vested tokensof a specif grant.
* @return An uint256 representing the amount of vested tokensof a specif grant.
* transferableTokens
* | _/-------- vestedTokens rect
* | _/
@ -191,7 +185,7 @@ contract VestedToken is StandardToken, LimitedTransferToken {
* @return Returns all the values that represent a TokenGrant(address, value, start, cliff,
* revokability, burnsOnRevoke, and vesting) plus the vested value at the current time.
*/
function tokenGrant(address _holder, uint _grantId) constant returns (address granter, uint256 value, uint256 vested, uint64 start, uint64 cliff, uint64 vesting, bool revokable, bool burnsOnRevoke) {
function tokenGrant(address _holder, uint256 _grantId) constant returns (address granter, uint256 value, uint256 vested, uint64 start, uint64 cliff, uint64 vesting, bool revokable, bool burnsOnRevoke) {
TokenGrant grant = grants[_holder][_grantId];
granter = grant.granter;
@ -209,7 +203,7 @@ contract VestedToken is StandardToken, LimitedTransferToken {
* @dev Get the amount of vested tokens at a specific time.
* @param grant TokenGrant The grant to be checked.
* @param time The time to be checked
* @return An uint representing the amount of vested tokens of a specific grant at a specific time.
* @return An uint256 representing the amount of vested tokens of a specific grant at a specific time.
*/
function vestedTokens(TokenGrant grant, uint64 time) private constant returns (uint256) {
return calculateVestedTokens(
@ -225,7 +219,7 @@ contract VestedToken is StandardToken, LimitedTransferToken {
* @dev Calculate the amount of non vested tokens at a specific time.
* @param grant TokenGrant The grant to be checked.
* @param time uint64 The time to be checked
* @return An uint representing the amount of non vested tokens of a specifc grant on the
* @return An uint256 representing the amount of non vested tokens of a specifc grant on the
* passed time frame.
*/
function nonVestedTokens(TokenGrant grant, uint64 time) private constant returns (uint256) {
@ -235,13 +229,13 @@ contract VestedToken is StandardToken, LimitedTransferToken {
/**
* @dev Calculate the date when the holder can trasfer all its tokens
* @param holder address The address of the holder
* @return An uint representing the date of the last transferable tokens.
* @return An uint256 representing the date of the last transferable tokens.
*/
function lastTokenIsTransferableDate(address holder) constant public returns (uint64 date) {
date = uint64(now);
uint256 grantIndex = grants[holder].length;
for (uint256 i = 0; i < grantIndex; i++) {
date = SafeMath.max64(grants[holder][i].vesting, date);
date = Math.max64(grants[holder][i].vesting, date);
}
}
}

View File

@ -1,14 +0,0 @@
CrowdsaleToken
=============================================
Simple ERC20 Token example, with crowdsale token creation.
Inherits from contract StandardToken.
createTokens(address recipient) payable
"""""""""""""""""""""""""""""""""""""""""
Creates tokens based on message value and credits to the recipient.
getPrice() constant returns (uint result)
"""""""""""""""""""""""""""""""""""""""""
Returns the amount of tokens per 1 ether.

View File

@ -0,0 +1,9 @@
ECReovery
=============================================
Returns the signer of the the hash using the signature divided in v, r, and s values.
recover(bytes32 hash, bytes sig) internal returns (address)
"""""""""""""""""""""""""""""""""""""""""""""""""
Returns the signer of the the hash using the signature that provides the web3.eth.sign() method.

View File

@ -13,7 +13,7 @@ To install the Zeppelin library, run::
After that, you'll get all the library's contracts in the contracts/zeppelin folder. You can use the contracts in the library like so::
import "./zeppelin/Ownable.sol";
import "zeppelin-solidity/contracts/Ownable.sol";
contract MyContract is Ownable {
...

24
docs/source/math.rst Normal file
View File

@ -0,0 +1,24 @@
Math
=============================================
Provides assorted low-level math operations.
max64(uint64 a, uint64 b) internal constant returns (uint64)
"""""""""""""""""""""""""""""""""""""""""""""""""
Returns the largest of two uint64 numbers.
min64(uint64 a, uint64 b) internal constant returns (uint64)
"""""""""""""""""""""""""""""""""""""""""""""""""
Returns the smallest of two uint64 numbers.
max64(uint256 a, uint256 b) internal constant returns (uint256)
"""""""""""""""""""""""""""""""""""""""""""""""""
Returns the largest of two uint256 numbers.
min64(uint256 a, uint256 b) internal constant returns (uint256)
"""""""""""""""""""""""""""""""""""""""""""""""""
Returns the smallest of two uint256 numbers.

View File

@ -11,6 +11,6 @@ modifier onlyOwner( )
""""""""""""""""""""""""""""""""""""""
Prevents function from running if it is called by anyone other than the owner.
transfer(address newOwner) onlyOwner
transferOwnership(address newOwner) onlyOwner
""""""""""""""""""""""""""""""""""""""
Transfers ownership of the contract to the passed address.
Transfers ownership of the contract to the passed address.

View File

@ -8,17 +8,17 @@ assert(bool assertion) internal
Throws an error if the passed result is false. Used in this contract by checking mathematical expressions.
safeMul(uint a, uint b) internal returns (uint)
mul(uint256 a, uint256 b) internal returns (uint256)
"""""""""""""""""""""""""""""""""""""""""""""""""
Multiplies two unisgned integers. Asserts that dividing the product by the non-zero multiplicand results in the multiplier.
safeSub(uint a, uint b) internal returns (uint)
sub(uint256 a, uint256 b) internal returns (uint256)
"""""""""""""""""""""""""""""""""""""""""""""""""
Checks that b is not greater than a before subtracting.
safeAdd(uint a, uint b) internal returns (uint)
add(uint256 a, uint256 b) internal returns (uint256)
"""""""""""""""""""""""""""""""""""""""""""""""""
Checks that the result is greater than both a and b.
Checks that the result is greater than both a and b.

View File

@ -1,6 +1,6 @@
{
"package_name": "zeppelin",
"version": "1.0.6",
"version": "1.2.0",
"description": "Secure Smart Contract library for Solidity",
"authors": [
"Manuel Araoz <manuelaraoz@gmail.com>"

View File

@ -1,13 +1,13 @@
{
"name": "zeppelin-solidity",
"version": "1.0.6",
"version": "1.2.0",
"description": "Secure Smart Contract library for Solidity",
"main": "truffle.js",
"scripts": {
"test": "scripts/test.sh",
"console": "truffle console",
"install": "scripts/install.sh",
"coverage": "scripts/coverage.sh"
"coverage": "scripts/coverage.sh",
"coveralls": "scripts/coveralls.sh"
},
"repository": {
"type": "git",
@ -35,8 +35,14 @@
"babel-preset-stage-2": "^6.18.0",
"babel-preset-stage-3": "^6.17.0",
"babel-register": "^6.23.0",
"chai": "^4.0.2",
"chai-as-promised": "^7.0.0",
"chai-bignumber": "^2.0.0",
"coveralls": "^2.13.1",
"ethereumjs-testrpc": "^3.0.2",
"solidity-coverage": "^0.1.0",
"truffle": "https://github.com/ConsenSys/truffle.git#3.1.9"
"mocha-lcov-reporter": "^1.3.0",
"moment": "^2.18.1",
"solidity-coverage": "^0.1.7",
"truffle": "3.2.2"
}
}

View File

@ -1,3 +1,25 @@
#! /bin/bash
SOLIDITY_COVERAGE=true ./node_modules/.bin/solidity-coverage
output=$(nc -z localhost 8555; echo $?)
[ $output -eq "0" ] && trpc_running=true
if [ ! $trpc_running ]; then
echo "Starting testrpc-sc to generate coverage"
# we give each account 1M ether, needed for high-value tests
./node_modules/ethereumjs-testrpc-sc/bin/testrpc --gasLimit 0xfffffffffff --port 8555 \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501200,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501201,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501202,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501203,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501204,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501205,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501206,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501207,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501208,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501209,1000000000000000000000000" \
> /dev/null &
trpc_pid=$!
fi
SOLIDITY_COVERAGE=true && ./node_modules/.bin/solidity-coverage

4
scripts/coveralls.sh Executable file
View File

@ -0,0 +1,4 @@
#! /bin/bash
yarn run coverage && cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js

View File

@ -1,3 +0,0 @@
#! /bin/bash
mkdir -p ../../contracts/zeppelin && cp -r contracts/* "$_"

View File

@ -4,10 +4,22 @@ output=$(nc -z localhost 8545; echo $?)
[ $output -eq "0" ] && trpc_running=true
if [ ! $trpc_running ]; then
echo "Starting our own testrpc node instance"
testrpc > /dev/null &
# we give each account 1M ether, needed for high-value tests
testrpc \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501200,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501201,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501202,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501203,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501204,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501205,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501206,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501207,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501208,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501209,1000000000000000000000000" \
> /dev/null &
trpc_pid=$!
fi
./node_modules/truffle/cli.js test
./node_modules/truffle/cli.js test "$@"
if [ ! $trpc_running ]; then
kill -9 $trpc_pid
fi

90
test/CappedCrowdsale.js Normal file
View File

@ -0,0 +1,90 @@
import ether from './helpers/ether'
import advanceToBlock from './helpers/advanceToBlock'
import EVMThrow from './helpers/EVMThrow'
const BigNumber = web3.BigNumber
require('chai')
.use(require('chai-as-promised'))
.use(require('chai-bignumber')(BigNumber))
.should()
const CappedCrowdsale = artifacts.require('./helpers/CappedCrowdsaleImpl.sol')
const MintableToken = artifacts.require('MintableToken')
contract('CappedCrowdsale', function ([_, wallet]) {
const rate = new BigNumber(1000)
const cap = ether(300)
const lessThanCap = ether(60)
describe('creating a valid crowdsale', function () {
it('should fail with zero cap', async function () {
await CappedCrowdsale.new(this.startBlock, this.endBlock, rate, wallet, 0).should.be.rejectedWith(EVMThrow);
})
});
beforeEach(async function () {
this.startBlock = web3.eth.blockNumber + 10
this.endBlock = web3.eth.blockNumber + 20
this.crowdsale = await CappedCrowdsale.new(this.startBlock, this.endBlock, rate, wallet, cap)
this.token = MintableToken.at(await this.crowdsale.token())
})
describe('accepting payments', function () {
beforeEach(async function () {
await advanceToBlock(this.startBlock - 1)
})
it('should accept payments within cap', async function () {
await this.crowdsale.send(cap.minus(lessThanCap)).should.be.fulfilled
await this.crowdsale.send(lessThanCap).should.be.fulfilled
})
it('should reject payments outside cap', async function () {
await this.crowdsale.send(cap)
await this.crowdsale.send(1).should.be.rejectedWith(EVMThrow)
})
it('should reject payments that exceed cap', async function () {
await this.crowdsale.send(cap.plus(1)).should.be.rejectedWith(EVMThrow)
})
})
describe('ending', function () {
beforeEach(async function () {
await advanceToBlock(this.startBlock - 1)
})
it('should not be ended if under cap', async function () {
let hasEnded = await this.crowdsale.hasEnded()
hasEnded.should.equal(false)
await this.crowdsale.send(lessThanCap)
hasEnded = await this.crowdsale.hasEnded()
hasEnded.should.equal(false)
})
it('should not be ended if just under cap', async function () {
await this.crowdsale.send(cap.minus(1))
let hasEnded = await this.crowdsale.hasEnded()
hasEnded.should.equal(false)
})
it('should be ended if cap reached', async function () {
await this.crowdsale.send(cap)
let hasEnded = await this.crowdsale.hasEnded()
hasEnded.should.equal(true)
})
})
})

143
test/Crowdsale.js Normal file
View File

@ -0,0 +1,143 @@
import ether from './helpers/ether'
import advanceToBlock from './helpers/advanceToBlock'
import EVMThrow from './helpers/EVMThrow'
const BigNumber = web3.BigNumber
const should = require('chai')
.use(require('chai-as-promised'))
.use(require('chai-bignumber')(BigNumber))
.should()
const Crowdsale = artifacts.require('Crowdsale')
const MintableToken = artifacts.require('MintableToken')
contract('Crowdsale', function ([_, investor, wallet, purchaser]) {
const rate = new BigNumber(1000)
const value = ether(42)
const expectedTokenAmount = rate.mul(value)
beforeEach(async function () {
this.startBlock = web3.eth.blockNumber + 10
this.endBlock = web3.eth.blockNumber + 20
this.crowdsale = await Crowdsale.new(this.startBlock, this.endBlock, rate, wallet)
this.token = MintableToken.at(await this.crowdsale.token())
})
it('should be token owner', async function () {
const owner = await this.token.owner()
owner.should.equal(this.crowdsale.address)
})
it('should be ended only after end', async function () {
let ended = await this.crowdsale.hasEnded()
ended.should.equal(false)
await advanceToBlock(this.endBlock + 1)
ended = await this.crowdsale.hasEnded()
ended.should.equal(true)
})
describe('accepting payments', function () {
it('should reject payments before start', async function () {
await this.crowdsale.send(value).should.be.rejectedWith(EVMThrow)
await this.crowdsale.buyTokens(investor, value, {from: purchaser}).should.be.rejectedWith(EVMThrow)
})
it('should accept payments after start', async function () {
await advanceToBlock(this.startBlock - 1)
await this.crowdsale.send(value).should.be.fulfilled
await this.crowdsale.buyTokens(investor, {value: value, from: purchaser}).should.be.fulfilled
})
it('should reject payments after end', async function () {
await advanceToBlock(this.endBlock)
await this.crowdsale.send(value).should.be.rejectedWith(EVMThrow)
await this.crowdsale.buyTokens(investor, {value: value, from: purchaser}).should.be.rejectedWith(EVMThrow)
})
})
describe('high-level purchase', function () {
beforeEach(async function() {
await advanceToBlock(this.startBlock)
})
it('should log purchase', async function () {
const {logs} = await this.crowdsale.sendTransaction({value: value, from: investor})
const event = logs.find(e => e.event === 'TokenPurchase')
should.exist(event)
event.args.purchaser.should.equal(investor)
event.args.beneficiary.should.equal(investor)
event.args.value.should.be.bignumber.equal(value)
event.args.amount.should.be.bignumber.equal(expectedTokenAmount)
})
it('should increase totalSupply', async function () {
await this.crowdsale.send(value)
const totalSupply = await this.token.totalSupply()
totalSupply.should.be.bignumber.equal(expectedTokenAmount)
})
it('should assign tokens to sender', async function () {
await this.crowdsale.sendTransaction({value: value, from: investor})
let balance = await this.token.balanceOf(investor);
balance.should.be.bignumber.equal(expectedTokenAmount)
})
it('should forward funds to wallet', async function () {
const pre = web3.eth.getBalance(wallet)
await this.crowdsale.sendTransaction({value, from: investor})
const post = web3.eth.getBalance(wallet)
post.minus(pre).should.be.bignumber.equal(value)
})
})
describe('low-level purchase', function () {
beforeEach(async function() {
await advanceToBlock(this.startBlock)
})
it('should log purchase', async function () {
const {logs} = await this.crowdsale.buyTokens(investor, {value: value, from: purchaser})
const event = logs.find(e => e.event === 'TokenPurchase')
should.exist(event)
event.args.purchaser.should.equal(purchaser)
event.args.beneficiary.should.equal(investor)
event.args.value.should.be.bignumber.equal(value)
event.args.amount.should.be.bignumber.equal(expectedTokenAmount)
})
it('should increase totalSupply', async function () {
await this.crowdsale.buyTokens(investor, {value, from: purchaser})
const totalSupply = await this.token.totalSupply()
totalSupply.should.be.bignumber.equal(expectedTokenAmount)
})
it('should assign tokens to beneficiary', async function () {
await this.crowdsale.buyTokens(investor, {value, from: purchaser})
const balance = await this.token.balanceOf(investor)
balance.should.be.bignumber.equal(expectedTokenAmount)
})
it('should forward funds to wallet', async function () {
const pre = web3.eth.getBalance(wallet)
await this.crowdsale.buyTokens(investor, {value, from: purchaser})
const post = web3.eth.getBalance(wallet)
post.minus(pre).should.be.bignumber.equal(value)
})
})
})

View File

@ -1,9 +1,11 @@
'use strict';
const assertJump = require('./helpers/assertJump');
const timer = require('./helpers/timer');
var DayLimitMock = artifacts.require('helpers/DayLimitMock.sol');
var DayLimitMock = artifacts.require('./helpers/DayLimitMock.sol');
contract('DayLimit', function(accounts) {
const day = 60 * 60 * 24;
it('should construct with the passed daily limit', async function() {
let initLimit = 10;
@ -84,4 +86,27 @@ contract('DayLimit', function(accounts) {
assert.equal(spentToday, 3);
});
it('should allow spending if daily limit is reached and then the next has come', async function() {
let limit = 10;
let dayLimit = await DayLimitMock.new(limit);
await dayLimit.attemptSpend(8);
let spentToday = await dayLimit.spentToday();
assert.equal(spentToday, 8);
try {
await dayLimit.attemptSpend(3);
} catch(error) {
assertJump(error);
}
spentToday = await dayLimit.spentToday();
assert.equal(spentToday, 8);
await timer(day);
await dayLimit.attemptSpend(3);
spentToday = await dayLimit.spentToday();
assert.equal(spentToday, 3);
});
});

View File

@ -49,7 +49,7 @@ contract('DelayedClaimable', function(accounts) {
} catch (error) {
err = error;
}
assert.isFalse(err.message.search('invalid JUMP') === -1);
assert.isFalse(err.message.search('invalid opcode') === -1);
let owner = await delayedClaimable.owner();
assert.isTrue(owner !== accounts[1]);
});
@ -62,7 +62,7 @@ contract('DelayedClaimable', function(accounts) {
} catch (error) {
err = error;
}
assert.isFalse(err.message.search('invalid JUMP') === -1);
assert.isFalse(err.message.search('invalid opcode') === -1);
});
});

55
test/ECRecovery.js Normal file
View File

@ -0,0 +1,55 @@
var ECRecovery = artifacts.require("../contracts/ECRecovery.sol");
var utils = require('ethereumjs-util');
var hashMessage = require('./helpers/hashMessage.js');
contract('ECRecovery', function(accounts) {
let ecrecovery;
before(async function() {
ecrecovery = await ECRecovery.new();
});
it("recover v0", async function() {
// Signature generated outside testrpc with method web3.eth.sign(signer, message)
let signer = '0x2cc1166f6212628a0deef2b33befb2187d35b86c';
let message = '0x7dbaf558b0a1a5dc7a67202117ab143c1d8605a983e4a743bc06fcc03162dc0d'; // web3.sha3('OpenZeppelin')
let signature = '0x5d99b6f7f6d1f73d1a26497f2b1c89b24c0993913f86e9a2d02cd69887d9c94f3c880358579d811b21dd1b7fd9bb01c1d81d10e69f0384e675c32b39643be89200';
assert.equal(signer, await ecrecovery.recover(message, signature));
});
it("recover v1", async function() {
// Signature generated outside testrpc with method web3.eth.sign(signer, message)
let signer = '0x1e318623ab09fe6de3c9b8672098464aeda9100e';
let message = '0x7dbaf558b0a1a5dc7a67202117ab143c1d8605a983e4a743bc06fcc03162dc0d'; // web3.sha3('OpenZeppelin')
let signature = '0x331fe75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e001';
assert.equal(signer, await ecrecovery.recover(message, signature));
});
it("recover using web3.eth.sign()", async function() {
// Create the signature using account[0]
const signature = web3.eth.sign(web3.eth.accounts[0], web3.sha3('OpenZeppelin'));
// Recover the signer address form the generated message and signature.
assert.equal(web3.eth.accounts[0], await ecrecovery.recover(hashMessage('OpenZeppelin'), signature));
});
it("recover using web3.eth.sign() should return wrong signer", async function() {
// Create the signature using account[0]
const signature = web3.eth.sign(web3.eth.accounts[0], web3.sha3('OpenZeppelin'));
// Recover the signer address form the generated message and wrong signature.
assert.notEqual(web3.eth.accounts[0], await ecrecovery.recover(hashMessage('Test'), signature));
});
it("recover should fail when a wrong hash is sent", async function() {
// Create the signature using account[0]
let signature = web3.eth.sign(web3.eth.accounts[0], web3.sha3('OpenZeppelin'));
// Recover the signer address form the generated message and wrong signature.
assert.equal('0x0000000000000000000000000000000000000000',
await ecrecovery.recover(hashMessage('OpenZeppelin').substring(2), signature)
);
});
});

View File

@ -0,0 +1,61 @@
import advanceToBlock from './helpers/advanceToBlock'
import EVMThrow from './helpers/EVMThrow'
const BigNumber = web3.BigNumber
const should = require('chai')
.use(require('chai-as-promised'))
.use(require('chai-bignumber')(BigNumber))
.should()
const FinalizableCrowdsale = artifacts.require('./helpers/FinalizableCrowdsaleImpl.sol')
const MintableToken = artifacts.require('MintableToken')
contract('FinalizableCrowdsale', function ([_, owner, wallet, thirdparty]) {
const rate = new BigNumber(1000)
beforeEach(async function () {
this.startBlock = web3.eth.blockNumber + 10
this.endBlock = web3.eth.blockNumber + 20
this.crowdsale = await FinalizableCrowdsale.new(this.startBlock, this.endBlock, rate, wallet, {from: owner})
this.token = MintableToken.at(await this.crowdsale.token())
})
it('cannot be finalized before ending', async function () {
await this.crowdsale.finalize({from: owner}).should.be.rejectedWith(EVMThrow)
})
it('cannot be finalized by third party after ending', async function () {
await advanceToBlock(this.endBlock)
await this.crowdsale.finalize({from: thirdparty}).should.be.rejectedWith(EVMThrow)
})
it('can be finalized by owner after ending', async function () {
await advanceToBlock(this.endBlock)
await this.crowdsale.finalize({from: owner}).should.be.fulfilled
})
it('cannot be finalized twice', async function () {
await advanceToBlock(this.endBlock + 1)
await this.crowdsale.finalize({from: owner})
await this.crowdsale.finalize({from: owner}).should.be.rejectedWith(EVMThrow)
})
it('logs finalized', async function () {
await advanceToBlock(this.endBlock)
const {logs} = await this.crowdsale.finalize({from: owner})
const event = logs.find(e => e.event === 'Finalized')
should.exist(event)
})
it('finishes minting of token', async function () {
await advanceToBlock(this.endBlock)
await this.crowdsale.finalize({from: owner})
const finished = await this.token.mintingFinished()
finished.should.equal(true)
})
})

View File

@ -35,7 +35,8 @@ contract('HasNoEther', function(accounts) {
assert.equal(startBalance, 0);
// Force ether into it
await ForceEther.new(hasNoEther.address, {value: amount});
let forceEther = await ForceEther.new({value: amount});
await forceEther.destroyAndSend(hasNoEther.address);
const forcedBalance = await web3.eth.getBalance(hasNoEther.address);
assert.equal(forcedBalance, amount);
@ -53,7 +54,8 @@ contract('HasNoEther', function(accounts) {
let hasNoEther = await HasNoEtherTest.new({from: accounts[0]});
// Force ether into it
await ForceEther.new(hasNoEther.address, {value: amount});
let forceEther = await ForceEther.new({value: amount});
await forceEther.destroyAndSend(hasNoEther.address);
const forcedBalance = await web3.eth.getBalance(hasNoEther.address);
assert.equal(forcedBalance, amount);

View File

@ -52,7 +52,7 @@ contract('MultisigWallet', function(accounts) {
//Balance of account2 should have increased
let newAccountBalance = web3.eth.getBalance(accounts[2]);
assert.isTrue(newAccountBalance > accountBalance);
assert.isTrue(newAccountBalance.greaterThan(accountBalance));
});
it('should prevent execution of transaction if above daily limit', async function() {

61
test/RefundVault.js Normal file
View File

@ -0,0 +1,61 @@
const BigNumber = web3.BigNumber
require('chai')
.use(require('chai-as-promised'))
.use(require('chai-bignumber')(BigNumber))
.should()
import ether from './helpers/ether'
import EVMThrow from './helpers/EVMThrow'
const RefundVault = artifacts.require('RefundVault')
contract('RefundVault', function ([_, owner, wallet, investor]) {
const value = ether(42)
beforeEach(async function () {
this.vault = await RefundVault.new(wallet, {from: owner})
})
it('should accept contributions', async function () {
await this.vault.deposit(investor, {value, from: owner}).should.be.fulfilled
})
it('should not refund contribution during active state', async function () {
await this.vault.deposit(investor, {value, from: owner})
await this.vault.refund(investor).should.be.rejectedWith(EVMThrow)
})
it('only owner can enter refund mode', async function () {
await this.vault.enableRefunds({from: _}).should.be.rejectedWith(EVMThrow)
await this.vault.enableRefunds({from: owner}).should.be.fulfilled
})
it('should refund contribution after entering refund mode', async function () {
await this.vault.deposit(investor, {value, from: owner})
await this.vault.enableRefunds({from: owner})
const pre = web3.eth.getBalance(investor)
await this.vault.refund(investor)
const post = web3.eth.getBalance(investor)
post.minus(pre).should.be.bignumber.equal(value)
})
it('only owner can close', async function () {
await this.vault.close({from: _}).should.be.rejectedWith(EVMThrow)
await this.vault.close({from: owner}).should.be.fulfilled
})
it('should forward funds to wallet after closing', async function () {
await this.vault.deposit(investor, {value, from: owner})
const pre = web3.eth.getBalance(wallet)
await this.vault.close({from: owner})
const post = web3.eth.getBalance(wallet)
post.minus(pre).should.be.bignumber.equal(value)
})
})

View File

@ -0,0 +1,76 @@
import ether from './helpers/ether'
import advanceToBlock from './helpers/advanceToBlock'
import EVMThrow from './helpers/EVMThrow'
const BigNumber = web3.BigNumber
require('chai')
.use(require('chai-as-promised'))
.use(require('chai-bignumber')(BigNumber))
.should()
const RefundableCrowdsale = artifacts.require('./helpers/RefundableCrowdsaleImpl.sol')
contract('RefundableCrowdsale', function ([_, owner, wallet, investor]) {
const rate = new BigNumber(1000)
const goal = ether(800)
const lessThanGoal = ether(750)
describe('creating a valid crowdsale', function () {
it('should fail with zero goal', async function () {
await RefundableCrowdsale.new(this.startBlock, this.endBlock, rate, wallet, 0, {from: owner}).should.be.rejectedWith(EVMThrow);
})
});
beforeEach(async function () {
this.startBlock = web3.eth.blockNumber + 10
this.endBlock = web3.eth.blockNumber + 20
this.crowdsale = await RefundableCrowdsale.new(this.startBlock, this.endBlock, rate, wallet, goal, {from: owner})
})
it('should deny refunds before end', async function () {
await this.crowdsale.claimRefund({from: investor}).should.be.rejectedWith(EVMThrow)
await advanceToBlock(this.endBlock - 1)
await this.crowdsale.claimRefund({from: investor}).should.be.rejectedWith(EVMThrow)
})
it('should deny refunds after end if goal was reached', async function () {
await advanceToBlock(this.startBlock - 1)
await this.crowdsale.sendTransaction({value: goal, from: investor})
await advanceToBlock(this.endBlock)
await this.crowdsale.claimRefund({from: investor}).should.be.rejectedWith(EVMThrow)
})
it('should allow refunds after end if goal was not reached', async function () {
await advanceToBlock(this.startBlock - 1)
await this.crowdsale.sendTransaction({value: lessThanGoal, from: investor})
await advanceToBlock(this.endBlock)
await this.crowdsale.finalize({from: owner})
const pre = web3.eth.getBalance(investor)
await this.crowdsale.claimRefund({from: investor, gasPrice: 0})
.should.be.fulfilled
const post = web3.eth.getBalance(investor)
post.minus(pre).should.be.bignumber.equal(lessThanGoal)
})
it('should forward funds to wallet after end if goal was reached', async function () {
await advanceToBlock(this.startBlock - 1)
await this.crowdsale.sendTransaction({value: goal, from: investor})
await advanceToBlock(this.endBlock)
const pre = web3.eth.getBalance(wallet)
await this.crowdsale.finalize({from: owner})
const post = web3.eth.getBalance(wallet)
post.minus(pre).should.be.bignumber.equal(goal)
})
})

58
test/TokenTimelock.js Normal file
View File

@ -0,0 +1,58 @@
const BigNumber = web3.BigNumber
require('chai')
.use(require('chai-as-promised'))
.use(require('chai-bignumber')(BigNumber))
.should()
import moment from 'moment'
import latestTime from './helpers/latestTime'
import increaseTime from './helpers/increaseTime'
const MintableToken = artifacts.require('MintableToken')
const TokenTimelock = artifacts.require('TokenTimelock')
contract('TokenTimelock', function ([_, owner, beneficiary]) {
const amount = new BigNumber(100)
beforeEach(async function () {
this.token = await MintableToken.new({from: owner})
this.releaseTime = latestTime().add(1, 'year').unix()
this.timelock = await TokenTimelock.new(this.token.address, beneficiary, this.releaseTime)
await this.token.mint(this.timelock.address, amount, {from: owner})
})
it('cannot be released before time limit', async function () {
await this.timelock.release().should.be.rejected
})
it('cannot be released just before time limit', async function () {
await increaseTime(moment.duration(0.99, 'year'))
await this.timelock.release().should.be.rejected
})
it('can be released just after limit', async function () {
await increaseTime(moment.duration(1.01, 'year'))
await this.timelock.release().should.be.fulfilled
const balance = await this.token.balanceOf(beneficiary)
balance.should.be.bignumber.equal(amount)
})
it('can be released after time limit', async function () {
await increaseTime(moment.duration(2, 'year'))
await this.timelock.release().should.be.fulfilled
const balance = await this.token.balanceOf(beneficiary)
balance.should.be.bignumber.equal(amount)
})
it('cannot be released twice', async function () {
await increaseTime(moment.duration(2, 'year'))
await this.timelock.release().should.be.fulfilled
await this.timelock.release().should.be.rejected
const balance = await this.token.balanceOf(beneficiary)
balance.should.be.bignumber.equal(amount)
})
})

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import '../../contracts/token/BasicToken.sol';

View File

@ -0,0 +1,21 @@
pragma solidity ^0.4.11;
import '../../contracts/crowdsale/CappedCrowdsale.sol';
contract CappedCrowdsaleImpl is CappedCrowdsale {
function CappedCrowdsaleImpl (
uint256 _startBlock,
uint256 _endBlock,
uint256 _rate,
address _wallet,
uint256 _cap
)
Crowdsale(_startBlock, _endBlock, _rate, _wallet)
CappedCrowdsale(_cap)
{
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import "../../contracts/DayLimit.sol";
contract DayLimitMock is DayLimit {

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import '../../contracts/token/BasicToken.sol';

1
test/helpers/EVMThrow.js Normal file
View File

@ -0,0 +1 @@
export default 'invalid opcode'

View File

@ -0,0 +1,20 @@
pragma solidity ^0.4.11;
import '../../contracts/crowdsale/FinalizableCrowdsale.sol';
contract FinalizableCrowdsaleImpl is FinalizableCrowdsale {
function FinalizableCrowdsaleImpl (
uint256 _startBlock,
uint256 _endBlock,
uint256 _rate,
address _wallet
)
Crowdsale(_startBlock, _endBlock, _rate, _wallet)
FinalizableCrowdsale()
{
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
// @title Force Ether into a contract.
// @notice even
@ -6,8 +6,10 @@ pragma solidity ^0.4.8;
// @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);
function ForceEther() payable { }
function destroyAndSend(address _recipient) {
selfdestruct(_recipient);
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import "../../contracts/ownership/HasNoEther.sol";

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import {Bounty, Target} from "../../contracts/Bounty.sol";

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import '../../contracts/LimitBalance.sol';

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import "../../contracts/MultisigWallet.sol";
contract MultisigWalletMock is MultisigWallet {

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import '../../contracts/lifecycle/Pausable.sol';

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import '../../contracts/token/PausableToken.sol';

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import '../../contracts/payment/PullPayment.sol';

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
contract ReentrancyAttack {

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import '../../contracts/ReentrancyGuard.sol';
import './ReentrancyAttack.sol';

View File

@ -0,0 +1,21 @@
pragma solidity ^0.4.11;
import '../../contracts/crowdsale/RefundableCrowdsale.sol';
contract RefundableCrowdsaleImpl is RefundableCrowdsale {
function RefundableCrowdsaleImpl (
uint256 _startBlock,
uint256 _endBlock,
uint256 _rate,
address _wallet,
uint256 _goal
)
Crowdsale(_startBlock, _endBlock, _rate, _wallet)
RefundableCrowdsale(_goal)
{
}
}

View File

@ -1,7 +1,7 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import '../../contracts/SafeMath.sol';
import '../../contracts/math/SafeMath.sol';
contract SafeMathMock {

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import {Bounty, Target} from "../../contracts/Bounty.sol";

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import "../../contracts/ownership/Shareable.sol";
contract ShareableMock is Shareable {

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import '../../contracts/token/StandardToken.sol';

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import '../../contracts/token/VestedToken.sol';

View File

@ -0,0 +1,22 @@
export function advanceBlock() {
return new Promise((resolve, reject) => {
web3.currentProvider.sendAsync({
jsonrpc: '2.0',
method: 'evm_mine',
id: Date.now(),
}, (err, res) => {
return err ? reject(err) : resolve(res)
})
})
}
// Advances the block number so that the last mined block is `number`.
export default async function advanceToBlock(number) {
if (web3.eth.blockNumber > number) {
throw Error(`block number ${number} is in the past (current is ${web3.eth.blockNumber})`)
}
while (web3.eth.blockNumber < number) {
await advanceBlock()
}
}

View File

@ -1,3 +1,3 @@
module.exports = function(error) {
assert.isAbove(error.message.search('invalid JUMP'), -1, 'Invalid JUMP error must be returned');
assert.isAbove(error.message.search('invalid opcode'), -1, 'Invalid opcode error must be returned');
}

3
test/helpers/ether.js Normal file
View File

@ -0,0 +1,3 @@
export default function ether(n) {
return new web3.BigNumber(web3.toWei(n, 'ether'))
}

View File

@ -4,14 +4,14 @@ export default async 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;
const invalidOpcode = error.message.search('invalid opcode') >= 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,
invalidOpcode || outOfGas,
"Expected throw, got '" + error + "' instead",
);
return;

View File

@ -0,0 +1,8 @@
import utils from 'ethereumjs-util';
// Hash and add same prefix to the hash that testrpc use.
module.exports = function(message) {
const messageHex = new Buffer(utils.sha3(message).toString('hex'), 'hex');
const prefix = utils.toBuffer('\u0019Ethereum Signed Message:\n' + messageHex.length.toString());
return utils.bufferToHex( utils.sha3(Buffer.concat([prefix, messageHex])) );
};

View File

@ -0,0 +1,23 @@
// Increases testrpc time by the passed duration (a moment.js instance)
export default function increaseTime(duration) {
const id = Date.now()
return new Promise((resolve, reject) => {
web3.currentProvider.sendAsync({
jsonrpc: '2.0',
method: 'evm_increaseTime',
params: [duration.asSeconds()],
id: id,
}, err1 => {
if (err1) return reject(err1)
web3.currentProvider.sendAsync({
jsonrpc: '2.0',
method: 'evm_mine',
id: id+1,
}, (err2, res) => {
return err2 ? reject(err2) : resolve(res)
})
})
})
}

View File

@ -0,0 +1,6 @@
import moment from 'moment'
// Returns a moment.js instance representing the time of the last mined block
export default function latestTime() {
return moment.unix(web3.eth.getBlock('latest').timestamp)
}

6843
yarn.lock Normal file

File diff suppressed because it is too large Load Diff