Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7434b3d6d2 | |||
| 63b5fc5971 | |||
| f507a0ea29 | |||
| d5a75362ec | |||
| e748c3ea36 | |||
| 421ed4f8ab | |||
| 0b1f08043b | |||
| 759f8de81f | |||
| 96b550b722 | |||
| b961eea89d | |||
| d2dd6e40b6 | |||
| 070bcbcdbd | |||
| 46fe7ee76d | |||
| ba383a6d20 | |||
| a66f5f8f03 | |||
| 262b7dd7dd | |||
| 5d847ed4d9 | |||
| b3ca0c73b3 | |||
| d6a45ef14e | |||
| 54d74b1c26 | |||
| 657c56c650 | |||
| 50a903a62d | |||
| 0791e6639a | |||
| 59e9609926 | |||
| fadb2cf47e | |||
| 4d55d8fa8e | |||
| e31abffcb6 | |||
| cd47fbe953 | |||
| 42c6392533 | |||
| 3430c7a289 | |||
| daf1784be4 | |||
| de92a02127 | |||
| 82ca385725 | |||
| e33d9bb41b | |||
| 79b3a1b1a2 | |||
| c6a3c29eb4 | |||
| dd34d8df0f | |||
| 80d052d43f | |||
| 710f77dfe1 | |||
| b1e504d6c6 | |||
| 7deaee04c8 | |||
| 2020d56ba4 | |||
| a49fe53fa1 | |||
| 403e7336a9 | |||
| fea2a8383c | |||
| ffe464a43e | |||
| 3fbcb1b282 | |||
| 28b2a0c881 | |||
| 7b9c1429d9 | |||
| d53ddd4a95 | |||
| 6ede3d9001 | |||
| c3cb0dcf80 | |||
| f214dccab9 | |||
| c0cce27703 | |||
| 2eded7a337 | |||
| 41a6f1cd84 |
1
.coveralls.yml
Normal file
1
.coveralls.yml
Normal file
@ -0,0 +1 @@
|
||||
repo_token: AelGMv47LJ85e3KF1PhYBsjyduSjDmP0h
|
||||
10
.travis.yml
10
.travis.yml
@ -4,9 +4,9 @@ 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
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
# Zeppelin Solidity
|
||||
[](https://www.npmjs.org/package/zeppelin-solidity)
|
||||
[](https://travis-ci.org/OpenZeppelin/zeppelin-solidity)
|
||||
[](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:
|
||||
|
||||
@ -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:
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
|
||||
import './payment/PullPayment.sol';
|
||||
|
||||
@ -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,16 +57,16 @@ 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) {
|
||||
modifier limitedDaily(uint256 _value) {
|
||||
if (!underLimit(_value)) {
|
||||
throw;
|
||||
}
|
||||
|
||||
@ -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.
|
||||
* @param _limit uint256 to represent the limit.
|
||||
*/
|
||||
function LimitBalance(uint _limit) {
|
||||
function LimitBalance(uint256 _limit) {
|
||||
limit = _limit;
|
||||
}
|
||||
|
||||
|
||||
@ -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,7 +25,7 @@ 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)
|
||||
function MultisigWallet(address[] _owners, uint256 _required, uint256 _daylimit)
|
||||
Shareable(_owners, _required)
|
||||
DayLimit(_daylimit) { }
|
||||
|
||||
@ -55,7 +55,7 @@ contract MultisigWallet is Multisig, Shareable, DayLimit {
|
||||
* @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);
|
||||
@ -93,9 +93,9 @@ contract MultisigWallet is Multisig, Shareable, DayLimit {
|
||||
|
||||
/**
|
||||
* @dev Updates the daily limit value.
|
||||
* @param _newLimit
|
||||
* @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);
|
||||
}
|
||||
|
||||
@ -112,8 +112,8 @@ contract MultisigWallet is Multisig, Shareable, DayLimit {
|
||||
* @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();
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
/**
|
||||
* @title Helps contracts guard agains rentrancy attacks.
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
33
contracts/crowdsale/CappedCrowdsale.sol
Normal file
33
contracts/crowdsale/CappedCrowdsale.sol
Normal file
@ -0,0 +1,33 @@
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
108
contracts/crowdsale/Crowdsale.sol
Normal file
108
contracts/crowdsale/Crowdsale.sol
Normal file
@ -0,0 +1,108 @@
|
||||
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;
|
||||
uint256 updatedWeiRaised = weiRaised.add(weiAmount);
|
||||
|
||||
// calculate token amount to be created
|
||||
uint256 tokens = weiAmount.mul(rate);
|
||||
|
||||
// update state
|
||||
weiRaised = updatedWeiRaised;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
39
contracts/crowdsale/FinalizableCrowdsale.sol
Normal file
39
contracts/crowdsale/FinalizableCrowdsale.sol
Normal 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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
56
contracts/crowdsale/RefundVault.sol
Normal file
56
contracts/crowdsale/RefundVault.sol
Normal 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);
|
||||
}
|
||||
}
|
||||
59
contracts/crowdsale/RefundableCrowdsale.sol
Normal file
59
contracts/crowdsale/RefundableCrowdsale.sol
Normal file
@ -0,0 +1,59 @@
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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.
|
||||
*/
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
|
||||
import "../ownership/Ownable.sol";
|
||||
|
||||
@ -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
24
contracts/math/Math.sol
Normal 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;
|
||||
}
|
||||
}
|
||||
32
contracts/math/SafeMath.sol
Normal file
32
contracts/math/SafeMath.sol
Normal 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 returns (uint256) {
|
||||
uint256 c = a * b;
|
||||
assert(a == 0 || c / a == b);
|
||||
return c;
|
||||
}
|
||||
|
||||
function div(uint256 a, uint256 b) internal 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 returns (uint256) {
|
||||
assert(b <= a);
|
||||
return a - b;
|
||||
}
|
||||
|
||||
function add(uint256 a, uint256 b) internal returns (uint256) {
|
||||
uint256 c = a + b;
|
||||
assert(c >= a);
|
||||
return c;
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
|
||||
import './Ownable.sol';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
import './Ownable.sol';
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
|
||||
import './Claimable.sol';
|
||||
@ -11,8 +11,8 @@ 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
|
||||
@ -20,7 +20,7 @@ contract DelayedClaimable is Claimable {
|
||||
* @param _start The earliest time ownership can be claimed.
|
||||
* @param _end The latest time ownership can be claimed.
|
||||
*/
|
||||
function setLimits(uint _start, uint _end) onlyOwner {
|
||||
function setLimits(uint256 _start, uint256 _end) onlyOwner {
|
||||
if (_start > _end)
|
||||
throw;
|
||||
end = _end;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
import "./Ownable.sol";
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
import "./Ownable.sol";
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
import "./Ownable.sol";
|
||||
import "../token/ERC20Basic.sol";
|
||||
@ -15,10 +15,10 @@ 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 {
|
||||
function tokenFallback(address from_, uint256 value_, bytes data_) external {
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
import "./HasNoEther.sol";
|
||||
import "./HasNoTokens.sol";
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
|
||||
/**
|
||||
@ -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;
|
||||
@ -59,10 +59,10 @@ contract Shareable {
|
||||
* @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;
|
||||
}
|
||||
@ -77,12 +77,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 +93,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 +117,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 +125,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,7 +136,7 @@ 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;
|
||||
@ -153,7 +153,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 +177,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]];
|
||||
}
|
||||
|
||||
@ -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,7 +30,7 @@ contract PullPayment {
|
||||
*/
|
||||
function withdrawPayments() {
|
||||
address payee = msg.sender;
|
||||
uint payment = payments[payee];
|
||||
uint256 payment = payments[payee];
|
||||
|
||||
if (payment == 0) {
|
||||
throw;
|
||||
|
||||
@ -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,26 +10,16 @@ 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) {
|
||||
balances[msg.sender] = balances[msg.sender].sub(_value);
|
||||
balances[_to] = balances[_to].add(_value);
|
||||
Transfer(msg.sender, _to, _value);
|
||||
@ -38,9 +28,9 @@ contract BasicToken is ERC20Basic {
|
||||
/**
|
||||
* @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];
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
function approve(address spender, uint256 value);
|
||||
event Approval(address indexed owner, address indexed spender, uint256 value);
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
|
||||
/**
|
||||
@ -7,8 +7,8 @@ pragma solidity ^0.4.8;
|
||||
* @dev see https://github.com/ethereum/EIPs/issues/20
|
||||
*/
|
||||
contract ERC20Basic {
|
||||
uint public totalSupply;
|
||||
function balanceOf(address who) constant returns (uint);
|
||||
function transfer(address to, uint value);
|
||||
event Transfer(address indexed from, address indexed to, uint value);
|
||||
uint256 public totalSupply;
|
||||
function balanceOf(address who) constant returns (uint256);
|
||||
function transfer(address to, uint256 value);
|
||||
event Transfer(address indexed from, address indexed to, uint256 value);
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
import "./ERC20.sol";
|
||||
|
||||
@ -22,7 +22,7 @@ contract LimitedTransferToken is ERC20 {
|
||||
/**
|
||||
* @dev Checks whether it can transfer or otherwise throws.
|
||||
*/
|
||||
modifier canTransfer(address _sender, uint _value) {
|
||||
modifier canTransfer(address _sender, uint256 _value) {
|
||||
if (_value > transferableTokens(_sender, uint64(now))) throw;
|
||||
_;
|
||||
}
|
||||
@ -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) {
|
||||
super.transfer(_to, _value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -42,8 +42,8 @@ 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) {
|
||||
super.transferFrom(_from, _to, _value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
|
||||
import './StandardToken.sol';
|
||||
@ -14,11 +14,10 @@ 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() {
|
||||
@ -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);
|
||||
|
||||
@ -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 {
|
||||
return super.transfer(_to, _value);
|
||||
super.transfer(_to, _value);
|
||||
}
|
||||
|
||||
function transferFrom(address _from, address _to, uint _value) whenNotPaused {
|
||||
return super.transferFrom(_from, _to, _value);
|
||||
super.transferFrom(_from, _to, _value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
|
||||
import './BasicToken.sol';
|
||||
@ -8,22 +8,22 @@ 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) {
|
||||
var _allowance = allowed[_from][msg.sender];
|
||||
|
||||
// Check is not needed because sub(_allowance, _value) will already throw if this condition is not met
|
||||
@ -36,11 +36,11 @@ contract StandardToken is BasicToken, ERC20 {
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
|
||||
// To change the approve amount you first have to reduce the addresses`
|
||||
// allowance to zero by calling `approve(_spender, 0)` if it is not
|
||||
@ -53,12 +53,12 @@ contract StandardToken is BasicToken, ERC20 {
|
||||
}
|
||||
|
||||
/**
|
||||
* @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];
|
||||
}
|
||||
|
||||
|
||||
41
contracts/token/TokenTimelock.sol
Normal file
41
contracts/token/TokenTimelock.sol
Normal file
@ -0,0 +1,41 @@
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev beneficiary claims tokens held by time lock
|
||||
*/
|
||||
function claim() {
|
||||
require(msg.sender == beneficiary);
|
||||
require(now >= releaseTime);
|
||||
|
||||
uint amount = token.balanceOf(this);
|
||||
require(amount > 0);
|
||||
|
||||
token.transfer(beneficiary, amount);
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
import "../math/Math.sol";
|
||||
import "./StandardToken.sol";
|
||||
import "./LimitedTransferToken.sol";
|
||||
|
||||
@ -50,7 +51,7 @@ contract VestedToken is StandardToken, LimitedTransferToken {
|
||||
|
||||
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).
|
||||
|
||||
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,7 +73,7 @@ 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
|
||||
@ -103,7 +104,7 @@ 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);
|
||||
@ -121,15 +122,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 +141,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 +192,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 +210,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 +226,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 +236,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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.
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"package_name": "zeppelin",
|
||||
"version": "1.0.6",
|
||||
"version": "1.1.0",
|
||||
"description": "Secure Smart Contract library for Solidity",
|
||||
"authors": [
|
||||
"Manuel Araoz <manuelaraoz@gmail.com>"
|
||||
|
||||
14
package.json
14
package.json
@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "zeppelin-solidity",
|
||||
"version": "1.0.6",
|
||||
"version": "1.1.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",
|
||||
"mocha-lcov-reporter": "^1.3.0",
|
||||
"moment": "^2.18.1",
|
||||
"solidity-coverage": "^0.1.0",
|
||||
"truffle": "https://github.com/ConsenSys/truffle.git#3.1.9"
|
||||
"truffle": "3.2.2"
|
||||
}
|
||||
}
|
||||
|
||||
4
scripts/coveralls.sh
Executable file
4
scripts/coveralls.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#! /bin/bash
|
||||
|
||||
yarn run coverage && cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
#! /bin/bash
|
||||
|
||||
mkdir -p ../../contracts/zeppelin && cp -r contracts/* "$_"
|
||||
@ -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
|
||||
|
||||
81
test/CappedCrowdsale.js
Normal file
81
test/CappedCrowdsale.js
Normal file
@ -0,0 +1,81 @@
|
||||
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)
|
||||
|
||||
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
143
test/Crowdsale.js
Normal 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)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
@ -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);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@ -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);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
61
test/FinalizableCrowdsale.js
Normal file
61
test/FinalizableCrowdsale.js
Normal 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)
|
||||
})
|
||||
|
||||
})
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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
61
test/RefundVault.js
Normal 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)
|
||||
})
|
||||
|
||||
})
|
||||
67
test/RefundableCrowdsale.js
Normal file
67
test/RefundableCrowdsale.js
Normal file
@ -0,0 +1,67 @@
|
||||
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)
|
||||
|
||||
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
58
test/TokenTimelock.js
Normal 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 claimed before time limit', async function () {
|
||||
await this.timelock.claim({from: beneficiary}).should.be.rejected
|
||||
})
|
||||
|
||||
it('cannot be claimed just before time limit', async function () {
|
||||
await increaseTime(moment.duration(0.99, 'year'))
|
||||
await this.timelock.claim({from: beneficiary}).should.be.rejected
|
||||
})
|
||||
|
||||
it('can be claimed just after limit', async function () {
|
||||
await increaseTime(moment.duration(1.01, 'year'))
|
||||
await this.timelock.claim({from: beneficiary}).should.be.fulfilled
|
||||
const balance = await this.token.balanceOf(beneficiary)
|
||||
balance.should.be.bignumber.equal(amount)
|
||||
})
|
||||
|
||||
it('can be claimed after time limit', async function () {
|
||||
await increaseTime(moment.duration(2, 'year'))
|
||||
await this.timelock.claim({from: beneficiary}).should.be.fulfilled
|
||||
const balance = await this.token.balanceOf(beneficiary)
|
||||
balance.should.be.bignumber.equal(amount)
|
||||
})
|
||||
|
||||
it('cannot be claimed twice', async function () {
|
||||
await increaseTime(moment.duration(2, 'year'))
|
||||
await this.timelock.claim({from: beneficiary}).should.be.fulfilled
|
||||
await this.timelock.claim({from: beneficiary}).should.be.rejected
|
||||
const balance = await this.token.balanceOf(beneficiary)
|
||||
balance.should.be.bignumber.equal(amount)
|
||||
})
|
||||
|
||||
})
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
|
||||
import '../../contracts/token/BasicToken.sol';
|
||||
|
||||
21
test/helpers/CappedCrowdsaleImpl.sol
Normal file
21
test/helpers/CappedCrowdsaleImpl.sol
Normal 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)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
import "../../contracts/DayLimit.sol";
|
||||
|
||||
contract DayLimitMock is DayLimit {
|
||||
|
||||
@ -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
1
test/helpers/EVMThrow.js
Normal file
@ -0,0 +1 @@
|
||||
export default 'invalid opcode'
|
||||
20
test/helpers/FinalizableCrowdsaleImpl.sol
Normal file
20
test/helpers/FinalizableCrowdsaleImpl.sol
Normal 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()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
import "../../contracts/ownership/HasNoEther.sol";
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
|
||||
import {Bounty, Target} from "../../contracts/Bounty.sol";
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
|
||||
import '../../contracts/LimitBalance.sol';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
import "../../contracts/MultisigWallet.sol";
|
||||
|
||||
contract MultisigWalletMock is MultisigWallet {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
|
||||
import '../../contracts/lifecycle/Pausable.sol';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
import '../../contracts/token/PausableToken.sol';
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
|
||||
import '../../contracts/payment/PullPayment.sol';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
contract ReentrancyAttack {
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
import '../../contracts/ReentrancyGuard.sol';
|
||||
import './ReentrancyAttack.sol';
|
||||
|
||||
21
test/helpers/RefundableCrowdsaleImpl.sol
Normal file
21
test/helpers/RefundableCrowdsaleImpl.sol
Normal 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)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
|
||||
import {Bounty, Target} from "../../contracts/Bounty.sol";
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
import "../../contracts/ownership/Shareable.sol";
|
||||
|
||||
contract ShareableMock is Shareable {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
|
||||
import '../../contracts/token/StandardToken.sol';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
import '../../contracts/token/VestedToken.sol';
|
||||
|
||||
|
||||
22
test/helpers/advanceToBlock.js
Normal file
22
test/helpers/advanceToBlock.js
Normal 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()
|
||||
}
|
||||
}
|
||||
@ -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
3
test/helpers/ether.js
Normal file
@ -0,0 +1,3 @@
|
||||
export default function ether(n) {
|
||||
return new web3.BigNumber(web3.toWei(n, 'ether'))
|
||||
}
|
||||
@ -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;
|
||||
|
||||
23
test/helpers/increaseTime.js
Normal file
23
test/helpers/increaseTime.js
Normal 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)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
6
test/helpers/latestTime.js
Normal file
6
test/helpers/latestTime.js
Normal 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)
|
||||
}
|
||||
Reference in New Issue
Block a user