Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6e070c91e8 | |||
| 59afaca753 | |||
| f35eeed0eb | |||
| 8b19e3c215 | |||
| dca62efba9 | |||
| 923bbb44a8 | |||
| d4c455c180 | |||
| 5ac618681a | |||
| d191247505 | |||
| 9b55e96fa0 | |||
| 8868c0b6d3 | |||
| 534ff92ba5 | |||
| 31ec824aef | |||
| b732b6417e | |||
| 998b5f43fb | |||
| ff31995104 | |||
| 48a7cd4e60 | |||
| acd34a9372 | |||
| 2ce67a25ef | |||
| 700b811813 | |||
| 16f04b13d7 | |||
| e3ad4a5e14 | |||
| 579446d5d9 | |||
| fc07f7a0ff | |||
| dd6054efeb | |||
| 27a6a15d66 | |||
| 32e93579fa | |||
| c8719ce418 | |||
| 39fe05dfad | |||
| be101154fa | |||
| c329fc0a5f | |||
| e55dbc9681 | |||
| 6f1c67af0d | |||
| 5284a6df88 | |||
| 8bce0a4f2e | |||
| 11d2bbc092 | |||
| ff69c54497 | |||
| 6669f3fcee | |||
| 18e16a5db0 | |||
| 95fdc7bd8a | |||
| 27d696aa7d | |||
| ff6a565452 | |||
| 5f079c8605 | |||
| ea335ebc64 | |||
| b1a801566c | |||
| 2eac2a79b7 | |||
| f9fc8d2e96 | |||
| 89c32f5dd7 | |||
| eff3d7ca8e | |||
| 85225ef6ae | |||
| 2010c6b464 | |||
| 03891b00a7 | |||
| d0ec491b1f | |||
| 38536f42f4 |
@ -1,72 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
import "./payment/PullPayment.sol";
|
||||
import "./lifecycle/Destructible.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Bounty
|
||||
* @dev This bounty will pay out to a researcher if they break invariant logic of the contract.
|
||||
*/
|
||||
contract Bounty is PullPayment, Destructible {
|
||||
bool public claimed;
|
||||
mapping(address => address) public researchers;
|
||||
|
||||
event TargetCreated(address createdAddress);
|
||||
|
||||
/**
|
||||
* @dev Fallback function allowing the contract to receive funds, if they haven't already been claimed.
|
||||
*/
|
||||
function() external payable {
|
||||
require(!claimed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Create and deploy the target contract (extension of Target contract), and sets the
|
||||
* msg.sender as a researcher
|
||||
* @return A target contract
|
||||
*/
|
||||
function createTarget() public returns(Target) {
|
||||
Target target = Target(deployContract());
|
||||
researchers[target] = msg.sender;
|
||||
emit TargetCreated(target);
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sends the contract funds to the researcher that proved the contract is broken.
|
||||
* @param target contract
|
||||
*/
|
||||
function claim(Target target) public {
|
||||
address researcher = researchers[target];
|
||||
require(researcher != 0);
|
||||
// Check Target contract invariants
|
||||
require(!target.checkInvariant());
|
||||
asyncSend(researcher, address(this).balance);
|
||||
claimed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function to deploy the target contract.
|
||||
* @return A target contract address
|
||||
*/
|
||||
function deployContract() internal returns(address);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @title Target
|
||||
* @dev Your main contract should inherit from this class and implement the checkInvariant method.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
function checkInvariant() public returns(bool);
|
||||
}
|
||||
@ -1,75 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
/**
|
||||
* @title DayLimit
|
||||
* @dev Base contract that enables methods to be protected by placing a linear limit (specifiable)
|
||||
* on a particular resource per calendar day. Is multiowned to allow the limit to be altered.
|
||||
*/
|
||||
contract DayLimit {
|
||||
|
||||
uint256 public dailyLimit;
|
||||
uint256 public spentToday;
|
||||
uint256 public lastDay;
|
||||
|
||||
/**
|
||||
* @dev Constructor that sets the passed value as a dailyLimit.
|
||||
* @param _limit uint256 to represent the daily limit.
|
||||
*/
|
||||
function DayLimit(uint256 _limit) public {
|
||||
dailyLimit = _limit;
|
||||
lastDay = today();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev sets the daily limit. Does not alter the amount already spent today.
|
||||
* @param _newLimit uint256 to represent the new limit.
|
||||
*/
|
||||
function _setDailyLimit(uint256 _newLimit) internal {
|
||||
dailyLimit = _newLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Resets the amount already spent today.
|
||||
*/
|
||||
function _resetSpentToday() internal {
|
||||
spentToday = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Checks to see if there is enough resource to spend today. If true, the resource may be expended.
|
||||
* @param _value uint256 representing the amount of resource to spend.
|
||||
* @return A boolean that is True if the resource was spent and false otherwise.
|
||||
*/
|
||||
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;
|
||||
lastDay = today();
|
||||
}
|
||||
// check to see if there's enough left - if so, subtract and return true.
|
||||
// overflow protection // dailyLimit check
|
||||
if (spentToday + _value >= spentToday && spentToday + _value <= dailyLimit) {
|
||||
spentToday += _value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Private function to determine today's index
|
||||
* @return uint256 of today's index.
|
||||
*/
|
||||
function today() private view returns (uint256) {
|
||||
// solium-disable-next-line security/no-block-members
|
||||
return block.timestamp / 1 days;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Simple modifier for daily limit.
|
||||
*/
|
||||
modifier limitedDaily(uint256 _value) {
|
||||
require(underLimit(_value));
|
||||
_;
|
||||
}
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
/**
|
||||
* @title LimitBalance
|
||||
* @dev Simple contract to limit the balance of child contract.
|
||||
* @dev Note this doesn't prevent other contracts to send funds by using selfdestruct(address);
|
||||
* @dev See: https://github.com/ConsenSys/smart-contract-best-practices#remember-that-ether-can-be-forcibly-sent-to-an-account
|
||||
*/
|
||||
contract LimitBalance {
|
||||
|
||||
uint256 public limit;
|
||||
|
||||
/**
|
||||
* @dev Constructor that sets the passed value as a limit.
|
||||
* @param _limit uint256 to represent the limit.
|
||||
*/
|
||||
function LimitBalance(uint256 _limit) public {
|
||||
limit = _limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Checks if limit was reached. Case true, it throws.
|
||||
*/
|
||||
modifier limitedPayable() {
|
||||
require(address(this).balance <= limit);
|
||||
_;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
/**
|
||||
* @title Helps contracts guard agains reentrancy attacks.
|
||||
* @author Remco Bloemen <remco@2π.com>
|
||||
* @notice If you mark a function `nonReentrant`, you should also
|
||||
* mark it `external`.
|
||||
*/
|
||||
contract ReentrancyGuard {
|
||||
|
||||
/**
|
||||
* @dev We use a single lock for the whole contract.
|
||||
*/
|
||||
bool private reentrancyLock = false;
|
||||
|
||||
/**
|
||||
* @dev Prevents a contract from calling itself, directly or indirectly.
|
||||
* @notice If you mark a function `nonReentrant`, you should also
|
||||
* mark it `external`. Calling one nonReentrant function from
|
||||
* another is not supported. Instead, you can implement a
|
||||
* `private` function doing the actual work, and a `external`
|
||||
* wrapper marked as `nonReentrant`.
|
||||
*/
|
||||
modifier nonReentrant() {
|
||||
require(!reentrancyLock);
|
||||
reentrancyLock = true;
|
||||
_;
|
||||
reentrancyLock = false;
|
||||
}
|
||||
|
||||
}
|
||||
@ -4,6 +4,7 @@ import "../ownership/Ownable.sol";
|
||||
import "../ownership/rbac/RBAC.sol";
|
||||
import "../ECRecovery.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title SignatureBouncer
|
||||
* @author PhABC and Shrugs
|
||||
@ -21,11 +22,18 @@ import "../ECRecovery.sol";
|
||||
* @dev
|
||||
* @dev See the tests Bouncer.test.js for specific usage examples.
|
||||
*/
|
||||
contract SignatureBouncer is Ownable, RBAC {
|
||||
contract SignatureBouncer is Migratable, Ownable, RBAC {
|
||||
using ECRecovery for bytes32;
|
||||
|
||||
string public constant ROLE_BOUNCER = "bouncer";
|
||||
|
||||
function initialize(address _sender)
|
||||
isInitializer("SignatureBouncer", "1.9.0")
|
||||
public
|
||||
{
|
||||
Ownable.initialize(_sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev requires that a valid signature of a bouncer was provided
|
||||
*/
|
||||
|
||||
@ -1,163 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/ERC20/ERC20.sol";
|
||||
import "../math/SafeMath.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Crowdsale
|
||||
* @dev Crowdsale is a base contract for managing a token crowdsale,
|
||||
* allowing investors to purchase tokens with ether. This contract implements
|
||||
* such functionality in its most fundamental form and can be extended to provide additional
|
||||
* functionality and/or custom behavior.
|
||||
* The external interface represents the basic interface for purchasing tokens, and conform
|
||||
* the base architecture for crowdsales. They are *not* intended to be modified / overriden.
|
||||
* The internal interface conforms the extensible and modifiable surface of crowdsales. Override
|
||||
* the methods to add functionality. Consider using 'super' where appropiate to concatenate
|
||||
* behavior.
|
||||
*/
|
||||
contract Crowdsale {
|
||||
using SafeMath for uint256;
|
||||
|
||||
// The token being sold
|
||||
ERC20 public token;
|
||||
|
||||
// Address where funds are collected
|
||||
address public wallet;
|
||||
|
||||
// How many token units a buyer gets per wei
|
||||
uint256 public rate;
|
||||
|
||||
// Amount of wei raised
|
||||
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);
|
||||
|
||||
/**
|
||||
* @param _rate Number of token units a buyer gets per wei
|
||||
* @param _wallet Address where collected funds will be forwarded to
|
||||
* @param _token Address of the token being sold
|
||||
*/
|
||||
function Crowdsale(uint256 _rate, address _wallet, ERC20 _token) public {
|
||||
require(_rate > 0);
|
||||
require(_wallet != address(0));
|
||||
require(_token != address(0));
|
||||
|
||||
rate = _rate;
|
||||
wallet = _wallet;
|
||||
token = _token;
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
// Crowdsale external interface
|
||||
// -----------------------------------------
|
||||
|
||||
/**
|
||||
* @dev fallback function ***DO NOT OVERRIDE***
|
||||
*/
|
||||
function () external payable {
|
||||
buyTokens(msg.sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev low level token purchase ***DO NOT OVERRIDE***
|
||||
* @param _beneficiary Address performing the token purchase
|
||||
*/
|
||||
function buyTokens(address _beneficiary) public payable {
|
||||
|
||||
uint256 weiAmount = msg.value;
|
||||
_preValidatePurchase(_beneficiary, weiAmount);
|
||||
|
||||
// calculate token amount to be created
|
||||
uint256 tokens = _getTokenAmount(weiAmount);
|
||||
|
||||
// update state
|
||||
weiRaised = weiRaised.add(weiAmount);
|
||||
|
||||
_processPurchase(_beneficiary, tokens);
|
||||
emit TokenPurchase(
|
||||
msg.sender,
|
||||
_beneficiary,
|
||||
weiAmount,
|
||||
tokens
|
||||
);
|
||||
|
||||
_updatePurchasingState(_beneficiary, weiAmount);
|
||||
|
||||
_forwardFunds();
|
||||
_postValidatePurchase(_beneficiary, weiAmount);
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
// Internal interface (extensible)
|
||||
// -----------------------------------------
|
||||
|
||||
/**
|
||||
* @dev Validation of an incoming purchase. Use require statements to revert state when conditions are not met. Use super to concatenate validations.
|
||||
* @param _beneficiary Address performing the token purchase
|
||||
* @param _weiAmount Value in wei involved in the purchase
|
||||
*/
|
||||
function _preValidatePurchase(address _beneficiary, uint256 _weiAmount) internal {
|
||||
require(_beneficiary != address(0));
|
||||
require(_weiAmount != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Validation of an executed purchase. Observe state and use revert statements to undo rollback when valid conditions are not met.
|
||||
* @param _beneficiary Address performing the token purchase
|
||||
* @param _weiAmount Value in wei involved in the purchase
|
||||
*/
|
||||
function _postValidatePurchase(address _beneficiary, uint256 _weiAmount) internal {
|
||||
// optional override
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Source of tokens. Override this method to modify the way in which the crowdsale ultimately gets and sends its tokens.
|
||||
* @param _beneficiary Address performing the token purchase
|
||||
* @param _tokenAmount Number of tokens to be emitted
|
||||
*/
|
||||
function _deliverTokens(address _beneficiary, uint256 _tokenAmount) internal {
|
||||
token.transfer(_beneficiary, _tokenAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Executed when a purchase has been validated and is ready to be executed. Not necessarily emits/sends tokens.
|
||||
* @param _beneficiary Address receiving the tokens
|
||||
* @param _tokenAmount Number of tokens to be purchased
|
||||
*/
|
||||
function _processPurchase(address _beneficiary, uint256 _tokenAmount) internal {
|
||||
_deliverTokens(_beneficiary, _tokenAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Override for extensions that require an internal state to check for validity (current user contributions, etc.)
|
||||
* @param _beneficiary Address receiving the tokens
|
||||
* @param _weiAmount Value in wei involved in the purchase
|
||||
*/
|
||||
function _updatePurchasingState(address _beneficiary, uint256 _weiAmount) internal {
|
||||
// optional override
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Override to extend the way in which ether is converted to tokens.
|
||||
* @param _weiAmount Value in wei to be converted into tokens
|
||||
* @return Number of tokens that can be purchased with the specified _weiAmount
|
||||
*/
|
||||
function _getTokenAmount(uint256 _weiAmount) internal view returns (uint256) {
|
||||
return _weiAmount.mul(rate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Determines how ETH is stored/forwarded on purchases.
|
||||
*/
|
||||
function _forwardFunds() internal {
|
||||
wallet.transfer(msg.value);
|
||||
}
|
||||
}
|
||||
@ -1,42 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../../math/SafeMath.sol";
|
||||
import "../../ownership/Ownable.sol";
|
||||
import "../validation/TimedCrowdsale.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title FinalizableCrowdsale
|
||||
* @dev Extension of Crowdsale where an owner can do extra work
|
||||
* after finishing.
|
||||
*/
|
||||
contract FinalizableCrowdsale is TimedCrowdsale, Ownable {
|
||||
using SafeMath for uint256;
|
||||
|
||||
bool public isFinalized = false;
|
||||
|
||||
event Finalized();
|
||||
|
||||
/**
|
||||
* @dev Must be called after crowdsale ends, to do some extra finalization
|
||||
* work. Calls the contract's finalization function.
|
||||
*/
|
||||
function finalize() onlyOwner public {
|
||||
require(!isFinalized);
|
||||
require(hasClosed());
|
||||
|
||||
finalization();
|
||||
emit Finalized();
|
||||
|
||||
isFinalized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Can be overridden to add finalization logic. The overriding function
|
||||
* should call super.finalization() to ensure the chain of finalization is
|
||||
* executed entirely.
|
||||
*/
|
||||
function finalization() internal {
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../validation/TimedCrowdsale.sol";
|
||||
import "../../token/ERC20/ERC20.sol";
|
||||
import "../../math/SafeMath.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title PostDeliveryCrowdsale
|
||||
* @dev Crowdsale that locks tokens from withdrawal until it ends.
|
||||
*/
|
||||
contract PostDeliveryCrowdsale is TimedCrowdsale {
|
||||
using SafeMath for uint256;
|
||||
|
||||
mapping(address => uint256) public balances;
|
||||
|
||||
/**
|
||||
* @dev Withdraw tokens only after crowdsale ends.
|
||||
*/
|
||||
function withdrawTokens() public {
|
||||
require(hasClosed());
|
||||
uint256 amount = balances[msg.sender];
|
||||
require(amount > 0);
|
||||
balances[msg.sender] = 0;
|
||||
_deliverTokens(msg.sender, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Overrides parent by storing balances instead of issuing tokens right away.
|
||||
* @param _beneficiary Token purchaser
|
||||
* @param _tokenAmount Amount of tokens purchased
|
||||
*/
|
||||
function _processPurchase(address _beneficiary, uint256 _tokenAmount) internal {
|
||||
balances[_beneficiary] = balances[_beneficiary].add(_tokenAmount);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,72 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
import "../../math/SafeMath.sol";
|
||||
import "./FinalizableCrowdsale.sol";
|
||||
import "./utils/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;
|
||||
|
||||
/**
|
||||
* @dev Constructor, creates RefundVault.
|
||||
* @param _goal Funding goal
|
||||
*/
|
||||
function RefundableCrowdsale(uint256 _goal) public {
|
||||
require(_goal > 0);
|
||||
vault = new RefundVault(wallet);
|
||||
goal = _goal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Investors can claim refunds here if crowdsale is unsuccessful
|
||||
*/
|
||||
function claimRefund() public {
|
||||
require(isFinalized);
|
||||
require(!goalReached());
|
||||
|
||||
vault.refund(msg.sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Checks whether funding goal was reached.
|
||||
* @return Whether funding goal was reached
|
||||
*/
|
||||
function goalReached() public view returns (bool) {
|
||||
return weiRaised >= goal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev vault finalization task, called when owner calls finalize()
|
||||
*/
|
||||
function finalization() internal {
|
||||
if (goalReached()) {
|
||||
vault.close();
|
||||
} else {
|
||||
vault.enableRefunds();
|
||||
}
|
||||
|
||||
super.finalization();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Overrides Crowdsale fund forwarding, sending funds to vault.
|
||||
*/
|
||||
function _forwardFunds() internal {
|
||||
vault.deposit.value(msg.value)(msg.sender);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,66 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* @param _wallet Vault address
|
||||
*/
|
||||
function RefundVault(address _wallet) public {
|
||||
require(_wallet != address(0));
|
||||
wallet = _wallet;
|
||||
state = State.Active;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param investor Investor address
|
||||
*/
|
||||
function deposit(address investor) onlyOwner public payable {
|
||||
require(state == State.Active);
|
||||
deposited[investor] = deposited[investor].add(msg.value);
|
||||
}
|
||||
|
||||
function close() onlyOwner public {
|
||||
require(state == State.Active);
|
||||
state = State.Closed;
|
||||
emit Closed();
|
||||
wallet.transfer(address(this).balance);
|
||||
}
|
||||
|
||||
function enableRefunds() onlyOwner public {
|
||||
require(state == State.Active);
|
||||
state = State.Refunding;
|
||||
emit RefundsEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param investor Investor address
|
||||
*/
|
||||
function refund(address investor) public {
|
||||
require(state == State.Refunding);
|
||||
uint256 depositedValue = deposited[investor];
|
||||
deposited[investor] = 0;
|
||||
investor.transfer(depositedValue);
|
||||
emit Refunded(investor, depositedValue);
|
||||
}
|
||||
}
|
||||
@ -1,42 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../Crowdsale.sol";
|
||||
import "../../token/ERC20/ERC20.sol";
|
||||
import "../../math/SafeMath.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title AllowanceCrowdsale
|
||||
* @dev Extension of Crowdsale where tokens are held by a wallet, which approves an allowance to the crowdsale.
|
||||
*/
|
||||
contract AllowanceCrowdsale is Crowdsale {
|
||||
using SafeMath for uint256;
|
||||
|
||||
address public tokenWallet;
|
||||
|
||||
/**
|
||||
* @dev Constructor, takes token wallet address.
|
||||
* @param _tokenWallet Address holding the tokens, which has approved allowance to the crowdsale
|
||||
*/
|
||||
function AllowanceCrowdsale(address _tokenWallet) public {
|
||||
require(_tokenWallet != address(0));
|
||||
tokenWallet = _tokenWallet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Checks the amount of tokens left in the allowance.
|
||||
* @return Amount of tokens left in the allowance
|
||||
*/
|
||||
function remainingTokens() public view returns (uint256) {
|
||||
return token.allowance(tokenWallet, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Overrides parent behavior by transferring tokens from wallet.
|
||||
* @param _beneficiary Token purchaser
|
||||
* @param _tokenAmount Amount of tokens purchased
|
||||
*/
|
||||
function _deliverTokens(address _beneficiary, uint256 _tokenAmount) internal {
|
||||
token.transferFrom(tokenWallet, _beneficiary, _tokenAmount);
|
||||
}
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../Crowdsale.sol";
|
||||
import "../../token/ERC20/MintableToken.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title MintedCrowdsale
|
||||
* @dev Extension of Crowdsale contract whose tokens are minted in each purchase.
|
||||
* Token ownership should be transferred to MintedCrowdsale for minting.
|
||||
*/
|
||||
contract MintedCrowdsale is Crowdsale {
|
||||
|
||||
/**
|
||||
* @dev Overrides delivery by minting tokens upon purchase.
|
||||
* @param _beneficiary Token purchaser
|
||||
* @param _tokenAmount Number of tokens to be minted
|
||||
*/
|
||||
function _deliverTokens(address _beneficiary, uint256 _tokenAmount) internal {
|
||||
require(MintableToken(token).mint(_beneficiary, _tokenAmount));
|
||||
}
|
||||
}
|
||||
@ -1,54 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../validation/TimedCrowdsale.sol";
|
||||
import "../../math/SafeMath.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title IncreasingPriceCrowdsale
|
||||
* @dev Extension of Crowdsale contract that increases the price of tokens linearly in time.
|
||||
* Note that what should be provided to the constructor is the initial and final _rates_, that is,
|
||||
* the amount of tokens per wei contributed. Thus, the initial rate must be greater than the final rate.
|
||||
*/
|
||||
contract IncreasingPriceCrowdsale is TimedCrowdsale {
|
||||
using SafeMath for uint256;
|
||||
|
||||
uint256 public initialRate;
|
||||
uint256 public finalRate;
|
||||
|
||||
/**
|
||||
* @dev Constructor, takes intial and final rates of tokens received per wei contributed.
|
||||
* @param _initialRate Number of tokens a buyer gets per wei at the start of the crowdsale
|
||||
* @param _finalRate Number of tokens a buyer gets per wei at the end of the crowdsale
|
||||
*/
|
||||
function IncreasingPriceCrowdsale(uint256 _initialRate, uint256 _finalRate) public {
|
||||
require(_initialRate >= _finalRate);
|
||||
require(_finalRate > 0);
|
||||
initialRate = _initialRate;
|
||||
finalRate = _finalRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the rate of tokens per wei at the present time.
|
||||
* Note that, as price _increases_ with time, the rate _decreases_.
|
||||
* @return The number of tokens a buyer gets per wei at a given time
|
||||
*/
|
||||
function getCurrentRate() public view returns (uint256) {
|
||||
// solium-disable-next-line security/no-block-members
|
||||
uint256 elapsedTime = block.timestamp.sub(openingTime);
|
||||
uint256 timeRange = closingTime.sub(openingTime);
|
||||
uint256 rateRange = initialRate.sub(finalRate);
|
||||
return initialRate.sub(elapsedTime.mul(rateRange).div(timeRange));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Overrides parent method taking into account variable rate.
|
||||
* @param _weiAmount The value in wei to be converted into tokens
|
||||
* @return The number of tokens _weiAmount wei will buy at present time
|
||||
*/
|
||||
function _getTokenAmount(uint256 _weiAmount) internal view returns (uint256) {
|
||||
uint256 currentRate = getCurrentRate();
|
||||
return currentRate.mul(_weiAmount);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../../math/SafeMath.sol";
|
||||
import "../Crowdsale.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title CappedCrowdsale
|
||||
* @dev Crowdsale with a limit for total contributions.
|
||||
*/
|
||||
contract CappedCrowdsale is Crowdsale {
|
||||
using SafeMath for uint256;
|
||||
|
||||
uint256 public cap;
|
||||
|
||||
/**
|
||||
* @dev Constructor, takes maximum amount of wei accepted in the crowdsale.
|
||||
* @param _cap Max amount of wei to be contributed
|
||||
*/
|
||||
function CappedCrowdsale(uint256 _cap) public {
|
||||
require(_cap > 0);
|
||||
cap = _cap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Checks whether the cap has been reached.
|
||||
* @return Whether the cap was reached
|
||||
*/
|
||||
function capReached() public view returns (bool) {
|
||||
return weiRaised >= cap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Extend parent behavior requiring purchase to respect the funding cap.
|
||||
* @param _beneficiary Token purchaser
|
||||
* @param _weiAmount Amount of wei contributed
|
||||
*/
|
||||
function _preValidatePurchase(address _beneficiary, uint256 _weiAmount) internal {
|
||||
super._preValidatePurchase(_beneficiary, _weiAmount);
|
||||
require(weiRaised.add(_weiAmount) <= cap);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,76 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../../math/SafeMath.sol";
|
||||
import "../Crowdsale.sol";
|
||||
import "../../ownership/Ownable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title IndividuallyCappedCrowdsale
|
||||
* @dev Crowdsale with per-user caps.
|
||||
*/
|
||||
contract IndividuallyCappedCrowdsale is Crowdsale, Ownable {
|
||||
using SafeMath for uint256;
|
||||
|
||||
mapping(address => uint256) public contributions;
|
||||
mapping(address => uint256) public caps;
|
||||
|
||||
/**
|
||||
* @dev Sets a specific user's maximum contribution.
|
||||
* @param _beneficiary Address to be capped
|
||||
* @param _cap Wei limit for individual contribution
|
||||
*/
|
||||
function setUserCap(address _beneficiary, uint256 _cap) external onlyOwner {
|
||||
caps[_beneficiary] = _cap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets a group of users' maximum contribution.
|
||||
* @param _beneficiaries List of addresses to be capped
|
||||
* @param _cap Wei limit for individual contribution
|
||||
*/
|
||||
function setGroupCap(address[] _beneficiaries, uint256 _cap) external onlyOwner {
|
||||
for (uint256 i = 0; i < _beneficiaries.length; i++) {
|
||||
caps[_beneficiaries[i]] = _cap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the cap of a specific user.
|
||||
* @param _beneficiary Address whose cap is to be checked
|
||||
* @return Current cap for individual user
|
||||
*/
|
||||
function getUserCap(address _beneficiary) public view returns (uint256) {
|
||||
return caps[_beneficiary];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the amount contributed so far by a sepecific user.
|
||||
* @param _beneficiary Address of contributor
|
||||
* @return User contribution so far
|
||||
*/
|
||||
function getUserContribution(address _beneficiary) public view returns (uint256) {
|
||||
return contributions[_beneficiary];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Extend parent behavior requiring purchase to respect the user's funding cap.
|
||||
* @param _beneficiary Token purchaser
|
||||
* @param _weiAmount Amount of wei contributed
|
||||
*/
|
||||
function _preValidatePurchase(address _beneficiary, uint256 _weiAmount) internal {
|
||||
super._preValidatePurchase(_beneficiary, _weiAmount);
|
||||
require(contributions[_beneficiary].add(_weiAmount) <= caps[_beneficiary]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Extend parent behavior to update user contributions
|
||||
* @param _beneficiary Token purchaser
|
||||
* @param _weiAmount Amount of wei contributed
|
||||
*/
|
||||
function _updatePurchasingState(address _beneficiary, uint256 _weiAmount) internal {
|
||||
super._updatePurchasingState(_beneficiary, _weiAmount);
|
||||
contributions[_beneficiary] = contributions[_beneficiary].add(_weiAmount);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,58 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../../math/SafeMath.sol";
|
||||
import "../Crowdsale.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title TimedCrowdsale
|
||||
* @dev Crowdsale accepting contributions only within a time frame.
|
||||
*/
|
||||
contract TimedCrowdsale is Crowdsale {
|
||||
using SafeMath for uint256;
|
||||
|
||||
uint256 public openingTime;
|
||||
uint256 public closingTime;
|
||||
|
||||
/**
|
||||
* @dev Reverts if not in crowdsale time range.
|
||||
*/
|
||||
modifier onlyWhileOpen {
|
||||
// solium-disable-next-line security/no-block-members
|
||||
require(block.timestamp >= openingTime && block.timestamp <= closingTime);
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Constructor, takes crowdsale opening and closing times.
|
||||
* @param _openingTime Crowdsale opening time
|
||||
* @param _closingTime Crowdsale closing time
|
||||
*/
|
||||
function TimedCrowdsale(uint256 _openingTime, uint256 _closingTime) public {
|
||||
// solium-disable-next-line security/no-block-members
|
||||
require(_openingTime >= block.timestamp);
|
||||
require(_closingTime >= _openingTime);
|
||||
|
||||
openingTime = _openingTime;
|
||||
closingTime = _closingTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Checks whether the period in which the crowdsale is open has already elapsed.
|
||||
* @return Whether crowdsale period has elapsed
|
||||
*/
|
||||
function hasClosed() public view returns (bool) {
|
||||
// solium-disable-next-line security/no-block-members
|
||||
return block.timestamp > closingTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Extend parent behavior requiring to be within contributing period
|
||||
* @param _beneficiary Token purchaser
|
||||
* @param _weiAmount Amount of wei contributed
|
||||
*/
|
||||
function _preValidatePurchase(address _beneficiary, uint256 _weiAmount) internal onlyWhileOpen {
|
||||
super._preValidatePurchase(_beneficiary, _weiAmount);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,58 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../Crowdsale.sol";
|
||||
import "../../ownership/Ownable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title WhitelistedCrowdsale
|
||||
* @dev Crowdsale in which only whitelisted users can contribute.
|
||||
*/
|
||||
contract WhitelistedCrowdsale is Crowdsale, Ownable {
|
||||
|
||||
mapping(address => bool) public whitelist;
|
||||
|
||||
/**
|
||||
* @dev Reverts if beneficiary is not whitelisted. Can be used when extending this contract.
|
||||
*/
|
||||
modifier isWhitelisted(address _beneficiary) {
|
||||
require(whitelist[_beneficiary]);
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Adds single address to whitelist.
|
||||
* @param _beneficiary Address to be added to the whitelist
|
||||
*/
|
||||
function addToWhitelist(address _beneficiary) external onlyOwner {
|
||||
whitelist[_beneficiary] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Adds list of addresses to whitelist. Not overloaded due to limitations with truffle testing.
|
||||
* @param _beneficiaries Addresses to be added to the whitelist
|
||||
*/
|
||||
function addManyToWhitelist(address[] _beneficiaries) external onlyOwner {
|
||||
for (uint256 i = 0; i < _beneficiaries.length; i++) {
|
||||
whitelist[_beneficiaries[i]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Removes single address from whitelist.
|
||||
* @param _beneficiary Address to be removed to the whitelist
|
||||
*/
|
||||
function removeFromWhitelist(address _beneficiary) external onlyOwner {
|
||||
whitelist[_beneficiary] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Extend parent behavior requiring beneficiary to be in whitelist.
|
||||
* @param _beneficiary Token beneficiary
|
||||
* @param _weiAmount Amount of wei contributed
|
||||
*/
|
||||
function _preValidatePurchase(address _beneficiary, uint256 _weiAmount) internal isWhitelisted(_beneficiary) {
|
||||
super._preValidatePurchase(_beneficiary, _weiAmount);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,55 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../crowdsale/validation/CappedCrowdsale.sol";
|
||||
import "../crowdsale/distribution/RefundableCrowdsale.sol";
|
||||
import "../crowdsale/emission/MintedCrowdsale.sol";
|
||||
import "../token/ERC20/MintableToken.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title SampleCrowdsaleToken
|
||||
* @dev Very simple ERC20 Token that can be minted.
|
||||
* It is meant to be used in a crowdsale contract.
|
||||
*/
|
||||
contract SampleCrowdsaleToken is MintableToken {
|
||||
|
||||
string public constant name = "Sample Crowdsale Token"; // solium-disable-line uppercase
|
||||
string public constant symbol = "SCT"; // solium-disable-line uppercase
|
||||
uint8 public constant decimals = 18; // solium-disable-line uppercase
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @title SampleCrowdsale
|
||||
* @dev This is an example of a fully fledged crowdsale.
|
||||
* The way to add new features to a base crowdsale is by multiple inheritance.
|
||||
* In this example we are providing following extensions:
|
||||
* CappedCrowdsale - sets a max boundary for raised funds
|
||||
* RefundableCrowdsale - set a min goal to be reached and returns funds if it's not met
|
||||
*
|
||||
* After adding multiple features it's good practice to run integration tests
|
||||
* to ensure that subcontracts works together as intended.
|
||||
*/
|
||||
contract SampleCrowdsale is CappedCrowdsale, RefundableCrowdsale, MintedCrowdsale {
|
||||
|
||||
function SampleCrowdsale(
|
||||
uint256 _openingTime,
|
||||
uint256 _closingTime,
|
||||
uint256 _rate,
|
||||
address _wallet,
|
||||
uint256 _cap,
|
||||
MintableToken _token,
|
||||
uint256 _goal
|
||||
)
|
||||
public
|
||||
Crowdsale(_rate, _wallet, _token)
|
||||
CappedCrowdsale(_cap)
|
||||
TimedCrowdsale(_openingTime, _closingTime)
|
||||
RefundableCrowdsale(_goal)
|
||||
{
|
||||
//As goal needs to be met for a successful crowdsale
|
||||
//the value needs to less or equal than a cap which is limit for accepted funds
|
||||
require(_goal <= _cap);
|
||||
}
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../ownership/Heritable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title SimpleSavingsWallet
|
||||
* @dev Simplest form of savings wallet whose ownership can be claimed by a heir
|
||||
* if owner dies.
|
||||
* In this example, we take a very simple savings wallet providing two operations
|
||||
* (to send and receive funds) and extend its capabilities by making it Heritable.
|
||||
* The account that creates the contract is set as owner, who has the authority to
|
||||
* choose an heir account. Heir account can reclaim the contract ownership in the
|
||||
* case that the owner dies.
|
||||
*/
|
||||
contract SimpleSavingsWallet is Heritable {
|
||||
|
||||
event Sent(address indexed payee, uint256 amount, uint256 balance);
|
||||
event Received(address indexed payer, uint256 amount, uint256 balance);
|
||||
|
||||
|
||||
function SimpleSavingsWallet(uint256 _heartbeatTimeout) Heritable(_heartbeatTimeout) public {}
|
||||
|
||||
/**
|
||||
* @dev wallet can receive funds.
|
||||
*/
|
||||
function () public payable {
|
||||
emit Received(msg.sender, msg.value, address(this).balance);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev wallet can send funds
|
||||
*/
|
||||
function sendTo(address payee, uint256 amount) public onlyOwner {
|
||||
require(payee != 0 && payee != address(this));
|
||||
require(amount > 0);
|
||||
payee.transfer(amount);
|
||||
emit Sent(payee, amount, address(this).balance);
|
||||
}
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
import "../token/ERC20/StandardToken.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title SimpleToken
|
||||
* @dev Very simple ERC20 Token example, where all tokens are pre-assigned to the creator.
|
||||
* Note they can later distribute these tokens as they wish using `transfer` and other
|
||||
* `StandardToken` functions.
|
||||
*/
|
||||
contract SimpleToken is StandardToken {
|
||||
|
||||
string public constant name = "SimpleToken"; // solium-disable-line uppercase
|
||||
string public constant symbol = "SIM"; // solium-disable-line uppercase
|
||||
uint8 public constant decimals = 18; // solium-disable-line uppercase
|
||||
|
||||
uint256 public constant INITIAL_SUPPLY = 10000 * (10 ** uint256(decimals));
|
||||
|
||||
/**
|
||||
* @dev Constructor that gives msg.sender all of existing tokens.
|
||||
*/
|
||||
function SimpleToken() public {
|
||||
totalSupply_ = INITIAL_SUPPLY;
|
||||
balances[msg.sender] = INITIAL_SUPPLY;
|
||||
emit Transfer(0x0, msg.sender, INITIAL_SUPPLY);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
import "../ownership/Ownable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Destructible
|
||||
* @dev Base contract that can be destroyed by owner. All funds in contract will be sent to the owner.
|
||||
*/
|
||||
contract Destructible is Ownable {
|
||||
|
||||
function Destructible() public payable { }
|
||||
|
||||
/**
|
||||
* @dev Transfers the current balance to the owner and terminates the contract.
|
||||
*/
|
||||
function destroy() onlyOwner public {
|
||||
selfdestruct(owner);
|
||||
}
|
||||
|
||||
function destroyAndSend(address _recipient) onlyOwner public {
|
||||
selfdestruct(_recipient);
|
||||
}
|
||||
}
|
||||
@ -8,13 +8,17 @@ import "../ownership/Ownable.sol";
|
||||
* @title Pausable
|
||||
* @dev Base contract which allows children to implement an emergency stop mechanism.
|
||||
*/
|
||||
contract Pausable is Ownable {
|
||||
contract Pausable is Migratable, Ownable {
|
||||
event Pause();
|
||||
event Unpause();
|
||||
|
||||
bool public paused = false;
|
||||
|
||||
|
||||
function initialize(address _sender) isInitializer("Pausable", "1.9.0") public {
|
||||
Ownable.initialize(_sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Modifier to make a function callable only when the contract is not paused.
|
||||
*/
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../ownership/Ownable.sol";
|
||||
import "../token/ERC20/ERC20Basic.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title TokenDestructible:
|
||||
* @author Remco Bloemen <remco@2π.com>
|
||||
* @dev Base contract that can be destroyed by owner. All funds in contract including
|
||||
* listed tokens will be sent to the owner.
|
||||
*/
|
||||
contract TokenDestructible is Ownable {
|
||||
|
||||
function TokenDestructible() public payable { }
|
||||
|
||||
/**
|
||||
* @notice Terminate contract and refund to owner
|
||||
* @param tokens List of addresses of ERC20 or ERC20Basic token contracts to
|
||||
refund.
|
||||
* @notice The called token contracts could try to re-enter this contract. Only
|
||||
supply token contracts you trust.
|
||||
*/
|
||||
function destroy(address[] tokens) onlyOwner public {
|
||||
|
||||
// Transfer tokens to owner
|
||||
for (uint256 i = 0; i < tokens.length; i++) {
|
||||
ERC20Basic token = ERC20Basic(tokens[i]);
|
||||
uint256 balance = token.balanceOf(this);
|
||||
token.transfer(owner, balance);
|
||||
}
|
||||
|
||||
// Transfer Eth to owner and terminate contract
|
||||
selfdestruct(owner);
|
||||
}
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/ERC20/ERC20.sol";
|
||||
import "../crowdsale/emission/AllowanceCrowdsale.sol";
|
||||
|
||||
|
||||
contract AllowanceCrowdsaleImpl is AllowanceCrowdsale {
|
||||
|
||||
function AllowanceCrowdsaleImpl (
|
||||
uint256 _rate,
|
||||
address _wallet,
|
||||
ERC20 _token,
|
||||
address _tokenWallet
|
||||
)
|
||||
public
|
||||
Crowdsale(_rate, _wallet, _token)
|
||||
AllowanceCrowdsale(_tokenWallet)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@ -4,6 +4,13 @@ import "../access/SignatureBouncer.sol";
|
||||
|
||||
|
||||
contract SignatureBouncerMock is SignatureBouncer {
|
||||
function initialize(address _sender)
|
||||
isInitializer("SignatureBouncerMock", "1.9.0")
|
||||
public
|
||||
{
|
||||
SignatureBouncer.initialize(_sender);
|
||||
}
|
||||
|
||||
function checkValidSignature(address _address, bytes _sig)
|
||||
public
|
||||
view
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/ERC20/ERC20.sol";
|
||||
import "../crowdsale/validation/CappedCrowdsale.sol";
|
||||
|
||||
|
||||
contract CappedCrowdsaleImpl is CappedCrowdsale {
|
||||
|
||||
function CappedCrowdsaleImpl (
|
||||
uint256 _rate,
|
||||
address _wallet,
|
||||
ERC20 _token,
|
||||
uint256 _cap
|
||||
)
|
||||
public
|
||||
Crowdsale(_rate, _wallet, _token)
|
||||
CappedCrowdsale(_cap)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../../contracts/DayLimit.sol";
|
||||
|
||||
|
||||
contract DayLimitMock is DayLimit {
|
||||
uint256 public totalSpending;
|
||||
|
||||
function DayLimitMock(uint256 _value) public DayLimit(_value) {
|
||||
totalSpending = 0;
|
||||
}
|
||||
|
||||
function attemptSpend(uint256 _value) external limitedDaily(_value) {
|
||||
totalSpending += _value;
|
||||
}
|
||||
|
||||
function setDailyLimit(uint256 _newLimit) external {
|
||||
_setDailyLimit(_newLimit);
|
||||
}
|
||||
|
||||
function resetSpentToday() external {
|
||||
_resetSpentToday();
|
||||
}
|
||||
|
||||
}
|
||||
@ -5,5 +5,7 @@ import "../token/ERC20/DetailedERC20.sol";
|
||||
|
||||
|
||||
contract DetailedERC20Mock is StandardToken, DetailedERC20 {
|
||||
function DetailedERC20Mock(string _name, string _symbol, uint8 _decimals) DetailedERC20(_name, _symbol, _decimals) public {}
|
||||
function DetailedERC20Mock(string _name, string _symbol, uint8 _decimals) public {
|
||||
DetailedERC20.initialize(_name, _symbol, _decimals);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/ERC20/BasicToken.sol";
|
||||
|
||||
|
||||
contract ERC223ContractInterface {
|
||||
function tokenFallback(address _from, uint256 _value, bytes _data) external;
|
||||
}
|
||||
|
||||
|
||||
contract ERC223TokenMock is BasicToken {
|
||||
|
||||
function ERC223TokenMock(address initialAccount, uint256 initialBalance) public {
|
||||
balances[initialAccount] = initialBalance;
|
||||
totalSupply_ = initialBalance;
|
||||
}
|
||||
|
||||
// ERC223 compatible transfer function (except the name)
|
||||
function transferERC223(address _to, uint256 _value, bytes _data) public
|
||||
returns (bool success)
|
||||
{
|
||||
transfer(_to, _value);
|
||||
bool isContract = false;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
isContract := not(iszero(extcodesize(_to)))
|
||||
}
|
||||
if (isContract) {
|
||||
ERC223ContractInterface receiver = ERC223ContractInterface(_to);
|
||||
receiver.tokenFallback(msg.sender, _value, _data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -9,9 +9,9 @@ import "../token/ERC721/ERC721Token.sol";
|
||||
* and a public setter for metadata URI
|
||||
*/
|
||||
contract ERC721TokenMock is ERC721Token {
|
||||
function ERC721TokenMock(string name, string symbol) public
|
||||
ERC721Token(name, symbol)
|
||||
{ }
|
||||
function ERC721TokenMock(string name, string symbol) public {
|
||||
ERC721Token.initialize(name, symbol);
|
||||
}
|
||||
|
||||
function mint(address _to, uint256 _tokenId) public {
|
||||
super._mint(_to, _tokenId);
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
import "../token/ERC827/ERC827Token.sol";
|
||||
|
||||
|
||||
// mock class using ERC827 Token
|
||||
contract ERC827TokenMock is ERC827Token {
|
||||
|
||||
function ERC827TokenMock(address initialAccount, uint256 initialBalance) public {
|
||||
balances[initialAccount] = initialBalance;
|
||||
totalSupply_ = initialBalance;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/ERC20/MintableToken.sol";
|
||||
import "../crowdsale/distribution/FinalizableCrowdsale.sol";
|
||||
|
||||
|
||||
contract FinalizableCrowdsaleImpl is FinalizableCrowdsale {
|
||||
|
||||
function FinalizableCrowdsaleImpl (
|
||||
uint256 _openingTime,
|
||||
uint256 _closingTime,
|
||||
uint256 _rate,
|
||||
address _wallet,
|
||||
MintableToken _token
|
||||
)
|
||||
public
|
||||
Crowdsale(_rate, _wallet, _token)
|
||||
TimedCrowdsale(_openingTime, _closingTime)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
// @title Force Ether into a contract.
|
||||
// @notice even
|
||||
// if the contract is not payable.
|
||||
// @notice To use, construct the contract with the target as argument.
|
||||
// @author Remco Bloemen <remco@neufund.org>
|
||||
contract ForceEther {
|
||||
|
||||
function ForceEther() public payable { }
|
||||
|
||||
function destroyAndSend(address _recipient) public {
|
||||
selfdestruct(_recipient);
|
||||
}
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../../contracts/ownership/HasNoEther.sol";
|
||||
|
||||
|
||||
contract HasNoEtherTest is HasNoEther {
|
||||
|
||||
// Constructor with explicit payable — should still fail
|
||||
function HasNoEtherTest() public payable {
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../crowdsale/price/IncreasingPriceCrowdsale.sol";
|
||||
import "../math/SafeMath.sol";
|
||||
|
||||
|
||||
contract IncreasingPriceCrowdsaleImpl is IncreasingPriceCrowdsale {
|
||||
|
||||
function IncreasingPriceCrowdsaleImpl (
|
||||
uint256 _openingTime,
|
||||
uint256 _closingTime,
|
||||
address _wallet,
|
||||
ERC20 _token,
|
||||
uint256 _initialRate,
|
||||
uint256 _finalRate
|
||||
)
|
||||
public
|
||||
Crowdsale(_initialRate, _wallet, _token)
|
||||
TimedCrowdsale(_openingTime, _closingTime)
|
||||
IncreasingPriceCrowdsale(_initialRate, _finalRate)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/ERC20/ERC20.sol";
|
||||
import "../crowdsale/validation/IndividuallyCappedCrowdsale.sol";
|
||||
|
||||
|
||||
contract IndividuallyCappedCrowdsaleImpl is IndividuallyCappedCrowdsale {
|
||||
|
||||
function IndividuallyCappedCrowdsaleImpl (
|
||||
uint256 _rate,
|
||||
address _wallet,
|
||||
ERC20 _token
|
||||
)
|
||||
public
|
||||
Crowdsale(_rate, _wallet, _token)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import {Bounty, Target} from "../../contracts/Bounty.sol";
|
||||
|
||||
|
||||
contract InsecureTargetMock is Target {
|
||||
function checkInvariant() public returns(bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract InsecureTargetBounty is Bounty {
|
||||
function deployContract() internal returns (address) {
|
||||
return new InsecureTargetMock();
|
||||
}
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
import "../LimitBalance.sol";
|
||||
|
||||
|
||||
// mock class using LimitBalance
|
||||
contract LimitBalanceMock is LimitBalance(1000) {
|
||||
|
||||
function limitedDeposit() public payable limitedPayable {
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
contract MessageHelper {
|
||||
|
||||
event Show(bytes32 b32, uint256 number, string text);
|
||||
event Buy(bytes32 b32, uint256 number, string text, uint256 value);
|
||||
|
||||
function showMessage( bytes32 message, uint256 number, string text ) public returns (bool) {
|
||||
emit Show(message, number, text);
|
||||
return true;
|
||||
}
|
||||
|
||||
function buyMessage( bytes32 message, uint256 number, string text ) public payable returns (bool) {
|
||||
emit Buy(
|
||||
message,
|
||||
number,
|
||||
text,
|
||||
msg.value);
|
||||
return true;
|
||||
}
|
||||
|
||||
function fail() public {
|
||||
require(false);
|
||||
}
|
||||
|
||||
function call(address to, bytes data) public returns (bool) {
|
||||
// solium-disable-next-line security/no-low-level-calls
|
||||
if (to.call(data))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/ERC20/MintableToken.sol";
|
||||
import "../crowdsale/emission/MintedCrowdsale.sol";
|
||||
|
||||
|
||||
contract MintedCrowdsaleImpl is MintedCrowdsale {
|
||||
|
||||
function MintedCrowdsaleImpl (
|
||||
uint256 _rate,
|
||||
address _wallet,
|
||||
MintableToken _token
|
||||
)
|
||||
public
|
||||
Crowdsale(_rate, _wallet, _token)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@ -10,6 +10,8 @@ contract PausableMock is Pausable {
|
||||
uint256 public count;
|
||||
|
||||
function PausableMock() public {
|
||||
Ownable.initialize(msg.sender);
|
||||
|
||||
drasticMeasureTaken = false;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
@ -7,6 +7,8 @@ import "../token/ERC20/PausableToken.sol";
|
||||
contract PausableTokenMock is PausableToken {
|
||||
|
||||
function PausableTokenMock(address initialAccount, uint initialBalance) public {
|
||||
Ownable.initialize(msg.sender);
|
||||
|
||||
balances[initialAccount] = initialBalance;
|
||||
}
|
||||
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/ERC20/ERC20.sol";
|
||||
import "../crowdsale/distribution/PostDeliveryCrowdsale.sol";
|
||||
|
||||
|
||||
contract PostDeliveryCrowdsaleImpl is PostDeliveryCrowdsale {
|
||||
|
||||
function PostDeliveryCrowdsaleImpl (
|
||||
uint256 _openingTime,
|
||||
uint256 _closingTime,
|
||||
uint256 _rate,
|
||||
address _wallet,
|
||||
ERC20 _token
|
||||
)
|
||||
public
|
||||
TimedCrowdsale(_openingTime, _closingTime)
|
||||
Crowdsale(_rate, _wallet, _token)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@ -19,6 +19,8 @@ contract RBACMock is RBACWithAdmin {
|
||||
function RBACMock(address[] _advisors)
|
||||
public
|
||||
{
|
||||
RBACWithAdmin.initialize(msg.sender);
|
||||
|
||||
addRole(msg.sender, ROLE_ADVISOR);
|
||||
|
||||
for (uint256 i = 0; i < _advisors.length; i++) {
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
contract ReentrancyAttack {
|
||||
|
||||
function callSender(bytes4 data) public {
|
||||
// solium-disable-next-line security/no-low-level-calls
|
||||
require(msg.sender.call(data));
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,46 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../ReentrancyGuard.sol";
|
||||
import "./ReentrancyAttack.sol";
|
||||
|
||||
|
||||
contract ReentrancyMock is ReentrancyGuard {
|
||||
|
||||
uint256 public counter;
|
||||
|
||||
function ReentrancyMock() public {
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
function callback() external nonReentrant {
|
||||
count();
|
||||
}
|
||||
|
||||
function countLocalRecursive(uint256 n) public nonReentrant {
|
||||
if (n > 0) {
|
||||
count();
|
||||
countLocalRecursive(n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
function countThisRecursive(uint256 n) public nonReentrant {
|
||||
bytes4 func = bytes4(keccak256("countThisRecursive(uint256)"));
|
||||
if (n > 0) {
|
||||
count();
|
||||
// solium-disable-next-line security/no-low-level-calls
|
||||
bool result = address(this).call(func, n - 1);
|
||||
require(result == true);
|
||||
}
|
||||
}
|
||||
|
||||
function countAndCall(ReentrancyAttack attacker) public nonReentrant {
|
||||
count();
|
||||
bytes4 func = bytes4(keccak256("callback()"));
|
||||
attacker.callSender(func);
|
||||
}
|
||||
|
||||
function count() private {
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/ERC20/MintableToken.sol";
|
||||
import "../crowdsale/distribution/RefundableCrowdsale.sol";
|
||||
|
||||
|
||||
contract RefundableCrowdsaleImpl is RefundableCrowdsale {
|
||||
|
||||
function RefundableCrowdsaleImpl (
|
||||
uint256 _openingTime,
|
||||
uint256 _closingTime,
|
||||
uint256 _rate,
|
||||
address _wallet,
|
||||
MintableToken _token,
|
||||
uint256 _goal
|
||||
)
|
||||
public
|
||||
Crowdsale(_rate, _wallet, _token)
|
||||
TimedCrowdsale(_openingTime, _closingTime)
|
||||
RefundableCrowdsale(_goal)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@ -21,11 +21,11 @@ contract ERC20FailingMock is ERC20 {
|
||||
return false;
|
||||
}
|
||||
|
||||
function balanceOf(address) public constant returns (uint256) {
|
||||
function balanceOf(address) public view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function allowance(address, address) public constant returns (uint256) {
|
||||
function allowance(address, address) public view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -48,11 +48,11 @@ contract ERC20SucceedingMock is ERC20 {
|
||||
return true;
|
||||
}
|
||||
|
||||
function balanceOf(address) public constant returns (uint256) {
|
||||
function balanceOf(address) public view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function allowance(address, address) public constant returns (uint256) {
|
||||
function allowance(address, address) public view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import {Bounty, Target} from "../../contracts/Bounty.sol";
|
||||
|
||||
|
||||
contract SecureTargetMock is Target {
|
||||
function checkInvariant() public returns(bool) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract SecureTargetBounty is Bounty {
|
||||
function deployContract() internal returns (address) {
|
||||
return new SecureTargetMock();
|
||||
}
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/ERC20/ERC20.sol";
|
||||
import "../crowdsale/validation/TimedCrowdsale.sol";
|
||||
|
||||
|
||||
contract TimedCrowdsaleImpl is TimedCrowdsale {
|
||||
|
||||
function TimedCrowdsaleImpl (
|
||||
uint256 _openingTime,
|
||||
uint256 _closingTime,
|
||||
uint256 _rate,
|
||||
address _wallet,
|
||||
ERC20 _token
|
||||
)
|
||||
public
|
||||
Crowdsale(_rate, _wallet, _token)
|
||||
TimedCrowdsale(_openingTime, _closingTime)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../ownership/Whitelist.sol";
|
||||
|
||||
|
||||
contract WhitelistMock is Whitelist {
|
||||
|
||||
function onlyWhitelistedCanDoThis()
|
||||
onlyWhitelisted
|
||||
view
|
||||
external
|
||||
{
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/ERC20/ERC20.sol";
|
||||
import "../crowdsale/validation/WhitelistedCrowdsale.sol";
|
||||
|
||||
|
||||
contract WhitelistedCrowdsaleImpl is WhitelistedCrowdsale {
|
||||
|
||||
function WhitelistedCrowdsaleImpl (
|
||||
uint256 _rate,
|
||||
address _wallet,
|
||||
ERC20 _token
|
||||
)
|
||||
public
|
||||
Crowdsale(_rate, _wallet, _token)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./Ownable.sol";
|
||||
import "../token/ERC20/ERC20Basic.sol";
|
||||
import "../token/ERC20/SafeERC20.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Contracts that should be able to recover tokens
|
||||
* @author SylTi
|
||||
* @dev This allow a contract to recover any ERC20 token received in a contract by transferring the balance to the contract owner.
|
||||
* This will prevent any accidental loss of tokens.
|
||||
*/
|
||||
contract CanReclaimToken is Ownable {
|
||||
using SafeERC20 for ERC20Basic;
|
||||
|
||||
/**
|
||||
* @dev Reclaim all ERC20Basic compatible tokens
|
||||
* @param token ERC20Basic The address of the token contract
|
||||
*/
|
||||
function reclaimToken(ERC20Basic token) external onlyOwner {
|
||||
uint256 balance = token.balanceOf(this);
|
||||
token.safeTransfer(owner, balance);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,39 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
import "./Ownable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Claimable
|
||||
* @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.
|
||||
*/
|
||||
modifier onlyPendingOwner() {
|
||||
require(msg.sender == pendingOwner);
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Allows the current owner to set the pendingOwner address.
|
||||
* @param newOwner The address to transfer ownership to.
|
||||
*/
|
||||
function transferOwnership(address newOwner) onlyOwner public {
|
||||
pendingOwner = newOwner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Allows the pendingOwner address to finalize the transfer.
|
||||
*/
|
||||
function claimOwnership() onlyPendingOwner public {
|
||||
emit OwnershipTransferred(owner, pendingOwner);
|
||||
owner = pendingOwner;
|
||||
pendingOwner = address(0);
|
||||
}
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./Ownable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Contactable token
|
||||
* @dev Basic version of a contactable contract, allowing the owner to provide a string with their
|
||||
* contact information.
|
||||
*/
|
||||
contract Contactable is Ownable {
|
||||
|
||||
string public contactInformation;
|
||||
|
||||
/**
|
||||
* @dev Allows the owner to set a string with their contact information.
|
||||
* @param info The contact information to attach to the contract.
|
||||
*/
|
||||
function setContactInformation(string info) onlyOwner public {
|
||||
contactInformation = info;
|
||||
}
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./Claimable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title DelayedClaimable
|
||||
* @dev Extension for the Claimable contract, where the ownership needs to be claimed before/after
|
||||
* a certain block number.
|
||||
*/
|
||||
contract DelayedClaimable is Claimable {
|
||||
|
||||
uint256 public end;
|
||||
uint256 public start;
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
function setLimits(uint256 _start, uint256 _end) onlyOwner public {
|
||||
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.
|
||||
*/
|
||||
function claimOwnership() onlyPendingOwner public {
|
||||
require((block.number <= end) && (block.number >= start));
|
||||
emit OwnershipTransferred(owner, pendingOwner);
|
||||
owner = pendingOwner;
|
||||
pendingOwner = address(0);
|
||||
end = 0;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./Ownable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Contracts that should not own Contracts
|
||||
* @author Remco Bloemen <remco@2π.com>
|
||||
* @dev Should contracts (anything Ownable) end up being owned by this contract, it allows the owner
|
||||
* of this contract to reclaim ownership of the contracts.
|
||||
*/
|
||||
contract HasNoContracts is Ownable {
|
||||
|
||||
/**
|
||||
* @dev Reclaim ownership of Ownable contracts
|
||||
* @param contractAddr The address of the Ownable to be reclaimed.
|
||||
*/
|
||||
function reclaimContract(address contractAddr) external onlyOwner {
|
||||
Ownable contractInst = Ownable(contractAddr);
|
||||
contractInst.transferOwnership(owner);
|
||||
}
|
||||
}
|
||||
@ -1,42 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
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
|
||||
* in the contract, it will allow the owner to reclaim this ether.
|
||||
* @notice Ether can still be sent to this contract by:
|
||||
* calling functions labeled `payable`
|
||||
* `selfdestruct(contract_address)`
|
||||
* mining directly to the contract address
|
||||
*/
|
||||
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
|
||||
* we could use assembly to access msg.value.
|
||||
*/
|
||||
function HasNoEther() public payable {
|
||||
require(msg.value == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Disallows direct send by settings a default function without the `payable` flag.
|
||||
*/
|
||||
function() external {
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Transfer all Ether held by the contract to the owner.
|
||||
*/
|
||||
function reclaimEther() external onlyOwner {
|
||||
// solium-disable-next-line security/no-send
|
||||
assert(owner.send(address(this).balance));
|
||||
}
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./CanReclaimToken.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Contracts that should not own Tokens
|
||||
* @author Remco Bloemen <remco@2π.com>
|
||||
* @dev This blocks incoming ERC223 tokens to prevent accidental loss of tokens.
|
||||
* Should tokens (any ERC20Basic compatible) end up in the contract, it allows the
|
||||
* owner to reclaim the tokens.
|
||||
*/
|
||||
contract HasNoTokens is CanReclaimToken {
|
||||
|
||||
/**
|
||||
* @dev Reject all ERC223 compatible tokens
|
||||
* @param from_ address The address that is transferring the tokens
|
||||
* @param value_ uint256 the amount of the specified token
|
||||
* @param data_ Bytes The data passed from the caller.
|
||||
*/
|
||||
function tokenFallback(address from_, uint256 value_, bytes data_) external {
|
||||
from_;
|
||||
value_;
|
||||
data_;
|
||||
revert();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,117 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
import "./Ownable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Heritable
|
||||
* @dev The Heritable contract provides ownership transfer capabilities, in the
|
||||
* case that the current owner stops "heartbeating". Only the heir can pronounce the
|
||||
* owner's death.
|
||||
*/
|
||||
contract Heritable is Ownable {
|
||||
address private heir_;
|
||||
|
||||
// Time window the owner has to notify they are alive.
|
||||
uint256 private heartbeatTimeout_;
|
||||
|
||||
// Timestamp of the owner's death, as pronounced by the heir.
|
||||
uint256 private timeOfDeath_;
|
||||
|
||||
event HeirChanged(address indexed owner, address indexed newHeir);
|
||||
event OwnerHeartbeated(address indexed owner);
|
||||
event OwnerProclaimedDead(address indexed owner, address indexed heir, uint256 timeOfDeath);
|
||||
event HeirOwnershipClaimed(address indexed previousOwner, address indexed newOwner);
|
||||
|
||||
|
||||
/**
|
||||
* @dev Throw an exception if called by any account other than the heir's.
|
||||
*/
|
||||
modifier onlyHeir() {
|
||||
require(msg.sender == heir_);
|
||||
_;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @notice Create a new Heritable Contract with heir address 0x0.
|
||||
* @param _heartbeatTimeout time available for the owner to notify they are alive,
|
||||
* before the heir can take ownership.
|
||||
*/
|
||||
function Heritable(uint256 _heartbeatTimeout) public {
|
||||
setHeartbeatTimeout(_heartbeatTimeout);
|
||||
}
|
||||
|
||||
function setHeir(address newHeir) public onlyOwner {
|
||||
require(newHeir != owner);
|
||||
heartbeat();
|
||||
emit HeirChanged(owner, newHeir);
|
||||
heir_ = newHeir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Use these getter functions to access the internal variables in
|
||||
* an inherited contract.
|
||||
*/
|
||||
function heir() public view returns(address) {
|
||||
return heir_;
|
||||
}
|
||||
|
||||
function heartbeatTimeout() public view returns(uint256) {
|
||||
return heartbeatTimeout_;
|
||||
}
|
||||
|
||||
function timeOfDeath() public view returns(uint256) {
|
||||
return timeOfDeath_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev set heir = 0x0
|
||||
*/
|
||||
function removeHeir() public onlyOwner {
|
||||
heartbeat();
|
||||
heir_ = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Heir can pronounce the owners death. To claim the ownership, they will
|
||||
* have to wait for `heartbeatTimeout` seconds.
|
||||
*/
|
||||
function proclaimDeath() public onlyHeir {
|
||||
require(ownerLives());
|
||||
emit OwnerProclaimedDead(owner, heir_, timeOfDeath_);
|
||||
// solium-disable-next-line security/no-block-members
|
||||
timeOfDeath_ = block.timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Owner can send a heartbeat if they were mistakenly pronounced dead.
|
||||
*/
|
||||
function heartbeat() public onlyOwner {
|
||||
emit OwnerHeartbeated(owner);
|
||||
timeOfDeath_ = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Allows heir to transfer ownership only if heartbeat has timed out.
|
||||
*/
|
||||
function claimHeirOwnership() public onlyHeir {
|
||||
require(!ownerLives());
|
||||
// solium-disable-next-line security/no-block-members
|
||||
require(block.timestamp >= timeOfDeath_ + heartbeatTimeout_);
|
||||
emit OwnershipTransferred(owner, heir_);
|
||||
emit HeirOwnershipClaimed(owner, heir_);
|
||||
owner = heir_;
|
||||
timeOfDeath_ = 0;
|
||||
}
|
||||
|
||||
function setHeartbeatTimeout(uint256 newHeartbeatTimeout) internal onlyOwner {
|
||||
require(ownerLives());
|
||||
heartbeatTimeout_ = newHeartbeatTimeout;
|
||||
}
|
||||
|
||||
function ownerLives() internal view returns (bool) {
|
||||
return timeOfDeath_ == 0;
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./HasNoEther.sol";
|
||||
import "./HasNoTokens.sol";
|
||||
import "./HasNoContracts.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Base contract for contracts that should not own things.
|
||||
* @author Remco Bloemen <remco@2π.com>
|
||||
* @dev Solves a class of errors where a contract accidentally becomes owner of Ether, Tokens or
|
||||
* Owned contracts. See respective base contracts for details.
|
||||
*/
|
||||
contract NoOwner is HasNoEther, HasNoTokens, HasNoContracts {
|
||||
}
|
||||
@ -1,24 +1,25 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "zos-lib/contracts/migrations/Migratable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Ownable
|
||||
* @dev The Ownable contract has an owner address, and provides basic authorization control
|
||||
* functions, this simplifies the implementation of "user permissions".
|
||||
*/
|
||||
contract Ownable {
|
||||
contract Ownable is Migratable {
|
||||
address public owner;
|
||||
|
||||
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
|
||||
|
||||
|
||||
/**
|
||||
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
|
||||
* account.
|
||||
*/
|
||||
function Ownable() public {
|
||||
owner = msg.sender;
|
||||
function initialize(address _sender) public isInitializer("Ownable", "1.9.0") {
|
||||
owner = _sender;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,81 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
import "./Ownable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Whitelist
|
||||
* @dev The Whitelist contract has a whitelist of addresses, and provides basic authorization control functions.
|
||||
* @dev This simplifies the implementation of "user permissions".
|
||||
*/
|
||||
contract Whitelist is Ownable {
|
||||
mapping(address => bool) public whitelist;
|
||||
|
||||
event WhitelistedAddressAdded(address addr);
|
||||
event WhitelistedAddressRemoved(address addr);
|
||||
|
||||
/**
|
||||
* @dev Throws if called by any account that's not whitelisted.
|
||||
*/
|
||||
modifier onlyWhitelisted() {
|
||||
require(whitelist[msg.sender]);
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev add an address to the whitelist
|
||||
* @param addr address
|
||||
* @return true if the address was added to the whitelist, false if the address was already in the whitelist
|
||||
*/
|
||||
function addAddressToWhitelist(address addr) onlyOwner public returns(bool success) {
|
||||
if (!whitelist[addr]) {
|
||||
whitelist[addr] = true;
|
||||
emit WhitelistedAddressAdded(addr);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev add addresses to the whitelist
|
||||
* @param addrs addresses
|
||||
* @return true if at least one address was added to the whitelist,
|
||||
* false if all addresses were already in the whitelist
|
||||
*/
|
||||
function addAddressesToWhitelist(address[] addrs) onlyOwner public returns(bool success) {
|
||||
for (uint256 i = 0; i < addrs.length; i++) {
|
||||
if (addAddressToWhitelist(addrs[i])) {
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev remove an address from the whitelist
|
||||
* @param addr address
|
||||
* @return true if the address was removed from the whitelist,
|
||||
* false if the address wasn't in the whitelist in the first place
|
||||
*/
|
||||
function removeAddressFromWhitelist(address addr) onlyOwner public returns(bool success) {
|
||||
if (whitelist[addr]) {
|
||||
whitelist[addr] = false;
|
||||
emit WhitelistedAddressRemoved(addr);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev remove addresses from the whitelist
|
||||
* @param addrs addresses
|
||||
* @return true if at least one address was removed from the whitelist,
|
||||
* false if all addresses weren't in the whitelist in the first place
|
||||
*/
|
||||
function removeAddressesFromWhitelist(address[] addrs) onlyOwner public returns(bool success) {
|
||||
for (uint256 i = 0; i < addrs.length; i++) {
|
||||
if (removeAddressFromWhitelist(addrs[i])) {
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./RBAC.sol";
|
||||
import "zos-lib/contracts/migrations/Migratable.sol";
|
||||
|
||||
|
||||
/**
|
||||
@ -9,7 +10,7 @@ import "./RBAC.sol";
|
||||
* @dev It's recommended that you define constants in the contract,
|
||||
* @dev like ROLE_ADMIN below, to avoid typos.
|
||||
*/
|
||||
contract RBACWithAdmin is RBAC {
|
||||
contract RBACWithAdmin is RBAC, Migratable {
|
||||
/**
|
||||
* A constant role name for indicating admins.
|
||||
*/
|
||||
@ -26,12 +27,13 @@ contract RBACWithAdmin is RBAC {
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev constructor. Sets msg.sender as admin by default
|
||||
* @dev constructor. Sets initialAdmin as admin.
|
||||
*/
|
||||
function RBACWithAdmin()
|
||||
function initialize(address initialAdmin)
|
||||
isInitializer("RBACWithAdmin", "1.9.0")
|
||||
public
|
||||
{
|
||||
addRole(msg.sender, ROLE_ADMIN);
|
||||
addRole(initialAdmin, ROLE_ADMIN);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../math/SafeMath.sol";
|
||||
import "zos-lib/contracts/migrations/Migratable.sol";
|
||||
|
||||
|
||||
/**
|
||||
@ -8,7 +9,7 @@ import "../math/SafeMath.sol";
|
||||
* @dev Base contract that supports multiple payees claiming funds sent to this contract
|
||||
* according to the proportion they own.
|
||||
*/
|
||||
contract SplitPayment {
|
||||
contract SplitPayment is Migratable {
|
||||
using SafeMath for uint256;
|
||||
|
||||
uint256 public totalShares = 0;
|
||||
@ -21,7 +22,11 @@ contract SplitPayment {
|
||||
/**
|
||||
* @dev Constructor
|
||||
*/
|
||||
function SplitPayment(address[] _payees, uint256[] _shares) public payable {
|
||||
function initialize(address[] _payees, uint256[] _shares)
|
||||
isInitializer("SplitPayment", "1.9.0")
|
||||
public
|
||||
payable
|
||||
{
|
||||
require(_payees.length == _shares.length);
|
||||
|
||||
for (uint256 i = 0; i < _payees.length; i++) {
|
||||
|
||||
@ -1,31 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./MintableToken.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Capped token
|
||||
* @dev Mintable token with a token cap.
|
||||
*/
|
||||
contract CappedToken is MintableToken {
|
||||
|
||||
uint256 public cap;
|
||||
|
||||
function CappedToken(uint256 _cap) public {
|
||||
require(_cap > 0);
|
||||
cap = _cap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Function to mint tokens
|
||||
* @param _to The address that will receive the minted tokens.
|
||||
* @param _amount The amount of tokens to mint.
|
||||
* @return A boolean that indicates if the operation was successful.
|
||||
*/
|
||||
function mint(address _to, uint256 _amount) onlyOwner canMint public returns (bool) {
|
||||
require(totalSupply_.add(_amount) <= cap);
|
||||
|
||||
return super.mint(_to, _amount);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,14 +1,15 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./ERC20.sol";
|
||||
import "zos-lib/contracts/migrations/Migratable.sol";
|
||||
|
||||
|
||||
contract DetailedERC20 is ERC20 {
|
||||
contract DetailedERC20 is Migratable, ERC20 {
|
||||
string public name;
|
||||
string public symbol;
|
||||
uint8 public decimals;
|
||||
|
||||
function DetailedERC20(string _name, string _symbol, uint8 _decimals) public {
|
||||
function initialize(string _name, string _symbol, uint8 _decimals) public isInitializer("DetailedERC20", "1.9.0") {
|
||||
name = _name;
|
||||
symbol = _symbol;
|
||||
decimals = _decimals;
|
||||
|
||||
21
contracts/token/ERC20/DetailedMintableToken.sol
Normal file
21
contracts/token/ERC20/DetailedMintableToken.sol
Normal file
@ -0,0 +1,21 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "zos-lib/contracts/migrations/Migratable.sol";
|
||||
import "./DetailedERC20.sol";
|
||||
import "./MintableToken.sol";
|
||||
|
||||
|
||||
contract DetailedMintableToken is Migratable, DetailedERC20, MintableToken {
|
||||
function initialize(
|
||||
address _sender,
|
||||
string _name,
|
||||
string _symbol,
|
||||
uint8 _decimals
|
||||
)
|
||||
isInitializer("DetailedMintableToken", "1.9.0")
|
||||
public
|
||||
{
|
||||
DetailedERC20.initialize(_name, _symbol, _decimals);
|
||||
MintableToken.initialize(_sender);
|
||||
}
|
||||
}
|
||||
29
contracts/token/ERC20/DetailedPremintedToken.sol
Normal file
29
contracts/token/ERC20/DetailedPremintedToken.sol
Normal file
@ -0,0 +1,29 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "zos-lib/contracts/migrations/Migratable.sol";
|
||||
import "./DetailedERC20.sol";
|
||||
import "./MintableToken.sol";
|
||||
|
||||
|
||||
contract DetailedPremintedToken is Migratable, DetailedERC20, StandardToken {
|
||||
function initialize(
|
||||
address _sender,
|
||||
string _name,
|
||||
string _symbol,
|
||||
uint8 _decimals,
|
||||
uint256 _initialBalance
|
||||
)
|
||||
isInitializer("DetailedPremintedToken", "1.9.0")
|
||||
public
|
||||
{
|
||||
DetailedERC20.initialize(_name, _symbol, _decimals);
|
||||
|
||||
_premint(_sender, _initialBalance);
|
||||
}
|
||||
|
||||
function _premint(address _to, uint256 _value) internal {
|
||||
totalSupply_ += _value;
|
||||
balances[_to] += _value;
|
||||
emit Transfer(0, _to, _value);
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,7 @@ pragma solidity ^0.4.21;
|
||||
|
||||
import "./StandardToken.sol";
|
||||
import "../../ownership/Ownable.sol";
|
||||
import "zos-lib/contracts/migrations/Migratable.sol";
|
||||
|
||||
|
||||
/**
|
||||
@ -10,7 +11,7 @@ import "../../ownership/Ownable.sol";
|
||||
* @dev Issue: * https://github.com/OpenZeppelin/openzeppelin-solidity/issues/120
|
||||
* Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol
|
||||
*/
|
||||
contract MintableToken is StandardToken, Ownable {
|
||||
contract MintableToken is Migratable, Ownable, StandardToken {
|
||||
event Mint(address indexed to, uint256 amount);
|
||||
event MintFinished();
|
||||
|
||||
@ -22,6 +23,10 @@ contract MintableToken is StandardToken, Ownable {
|
||||
_;
|
||||
}
|
||||
|
||||
function initialize(address _sender) isInitializer("MintableToken", "1.9.0") public {
|
||||
Ownable.initialize(_sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Function to mint tokens
|
||||
* @param _to The address that will receive the minted tokens.
|
||||
|
||||
@ -8,7 +8,11 @@ import "../../lifecycle/Pausable.sol";
|
||||
* @title Pausable token
|
||||
* @dev StandardToken modified with pausable transfers.
|
||||
**/
|
||||
contract PausableToken is StandardToken, Pausable {
|
||||
contract PausableToken is Migratable, StandardToken, Pausable {
|
||||
|
||||
function initialize(address _sender) isInitializer("PausableToken", "1.9.0") public {
|
||||
Pausable.initialize(_sender);
|
||||
}
|
||||
|
||||
function transfer(address _to, uint256 _value) public whenNotPaused returns (bool) {
|
||||
return super.transfer(_to, _value);
|
||||
|
||||
@ -3,6 +3,7 @@ pragma solidity ^0.4.18;
|
||||
import "./BurnableToken.sol";
|
||||
import "./StandardToken.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Standard Burnable Token
|
||||
* @dev Adds burnFrom method to ERC20 implementations
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./SafeERC20.sol";
|
||||
import "zos-lib/contracts/migrations/Migratable.sol";
|
||||
|
||||
|
||||
/**
|
||||
@ -8,7 +9,7 @@ import "./SafeERC20.sol";
|
||||
* @dev TokenTimelock is a token holder contract that will allow a
|
||||
* beneficiary to extract the tokens after a given release time
|
||||
*/
|
||||
contract TokenTimelock {
|
||||
contract TokenTimelock is Migratable {
|
||||
using SafeERC20 for ERC20Basic;
|
||||
|
||||
// ERC20 basic token contract being held
|
||||
@ -20,7 +21,15 @@ contract TokenTimelock {
|
||||
// timestamp when token release is enabled
|
||||
uint256 public releaseTime;
|
||||
|
||||
function TokenTimelock(ERC20Basic _token, address _beneficiary, uint256 _releaseTime) public {
|
||||
function initialize(
|
||||
address _sender,
|
||||
ERC20Basic _token,
|
||||
address _beneficiary,
|
||||
uint256 _releaseTime
|
||||
)
|
||||
isInitializer("TokenTimelock", "1.9.0")
|
||||
public
|
||||
{
|
||||
// solium-disable-next-line security/no-block-members
|
||||
require(_releaseTime > block.timestamp);
|
||||
token = _token;
|
||||
|
||||
@ -6,6 +6,7 @@ import "./ERC20Basic.sol";
|
||||
import "./SafeERC20.sol";
|
||||
import "../../ownership/Ownable.sol";
|
||||
import "../../math/SafeMath.sol";
|
||||
import "zos-lib/contracts/migrations/Migratable.sol";
|
||||
|
||||
|
||||
/**
|
||||
@ -14,7 +15,7 @@ import "../../math/SafeMath.sol";
|
||||
* typical vesting scheme, with a cliff and vesting period. Optionally revocable by the
|
||||
* owner.
|
||||
*/
|
||||
contract TokenVesting is Ownable {
|
||||
contract TokenVesting is Migratable, Ownable {
|
||||
using SafeMath for uint256;
|
||||
using SafeERC20 for ERC20Basic;
|
||||
|
||||
@ -42,7 +43,8 @@ contract TokenVesting is Ownable {
|
||||
* @param _duration duration in seconds of the period in which the tokens will vest
|
||||
* @param _revocable whether the vesting is revocable or not
|
||||
*/
|
||||
function TokenVesting(
|
||||
function initialize(
|
||||
address _sender,
|
||||
address _beneficiary,
|
||||
uint256 _start,
|
||||
uint256 _cliff,
|
||||
@ -50,7 +52,10 @@ contract TokenVesting is Ownable {
|
||||
bool _revocable
|
||||
)
|
||||
public
|
||||
isInitializer("TokenVesting", "1.9.0")
|
||||
{
|
||||
Ownable.initialize(_sender);
|
||||
|
||||
require(_beneficiary != address(0));
|
||||
require(_cliff <= _duration);
|
||||
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./ERC721.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title ERC-721 methods shipped in OpenZeppelin v1.7.0, removed in the latest version of the standard
|
||||
* @dev Only use this interface for compatibility with previously deployed contracts
|
||||
* @dev Use ERC721 for interacting with new contracts which are standard-compliant
|
||||
*/
|
||||
contract DeprecatedERC721 is ERC721 {
|
||||
function takeOwnership(uint256 _tokenId) public;
|
||||
function transfer(address _to, uint256 _tokenId) public;
|
||||
function tokensOf(address _owner) public view returns (uint256[]);
|
||||
}
|
||||
@ -2,6 +2,7 @@ pragma solidity ^0.4.21;
|
||||
|
||||
import "./ERC721.sol";
|
||||
import "./ERC721BasicToken.sol";
|
||||
import "zos-lib/contracts/migrations/Migratable.sol";
|
||||
|
||||
|
||||
/**
|
||||
@ -10,7 +11,7 @@ import "./ERC721BasicToken.sol";
|
||||
* Moreover, it includes approve all functionality using operator terminology
|
||||
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
|
||||
*/
|
||||
contract ERC721Token is ERC721, ERC721BasicToken {
|
||||
contract ERC721Token is Migratable, ERC721, ERC721BasicToken {
|
||||
// Token name
|
||||
string internal name_;
|
||||
|
||||
@ -35,7 +36,7 @@ contract ERC721Token is ERC721, ERC721BasicToken {
|
||||
/**
|
||||
* @dev Constructor function
|
||||
*/
|
||||
function ERC721Token(string _name, string _symbol) public {
|
||||
function initialize(string _name, string _symbol) public isInitializer("ERC721Token", "1.9.0") {
|
||||
name_ = _name;
|
||||
symbol_ = _symbol;
|
||||
}
|
||||
|
||||
19
contracts/token/ERC721/MintableERC721Token.sol
Normal file
19
contracts/token/ERC721/MintableERC721Token.sol
Normal file
@ -0,0 +1,19 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./ERC721Token.sol";
|
||||
import "../../ownership/Ownable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Mintable ERC721 Token
|
||||
*/
|
||||
contract MintableERC721Token is Migratable, Ownable, ERC721Token {
|
||||
function initialize(address _sender, string _name, string _symbol) isInitializer("MintableERC721Token", "1.9.0") public {
|
||||
Ownable.initialize(_sender);
|
||||
ERC721Token.initialize(_name, _symbol);
|
||||
}
|
||||
|
||||
function mint(address _to, uint256 _tokenId) onlyOwner public {
|
||||
_mint(_to, _tokenId);
|
||||
}
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
import "../ERC20/ERC20.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title ERC827 interface, an extension of ERC20 token standard
|
||||
*
|
||||
* @dev Interface of a ERC827 token, following the ERC20 standard with extra
|
||||
* @dev methods to transfer value and data and execute calls in transfers and
|
||||
* @dev approvals.
|
||||
*/
|
||||
contract ERC827 is ERC20 {
|
||||
function approveAndCall( address _spender, uint256 _value, bytes _data) public payable returns (bool);
|
||||
function transferAndCall( address _to, uint256 _value, bytes _data) public payable returns (bool);
|
||||
function transferFromAndCall(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _value,
|
||||
bytes _data
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (bool);
|
||||
}
|
||||
@ -1,144 +0,0 @@
|
||||
/* solium-disable security/no-low-level-calls */
|
||||
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./ERC827.sol";
|
||||
import "../ERC20/StandardToken.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title ERC827, an extension of ERC20 token standard
|
||||
*
|
||||
* @dev Implementation the ERC827, following the ERC20 standard with extra
|
||||
* @dev methods to transfer value and data and execute calls in transfers and
|
||||
* @dev approvals.
|
||||
*
|
||||
* @dev Uses OpenZeppelin StandardToken.
|
||||
*/
|
||||
contract ERC827Token is ERC827, StandardToken {
|
||||
|
||||
/**
|
||||
* @dev Addition to ERC20 token methods. It allows to
|
||||
* @dev approve the transfer of value and execute a call with the sent data.
|
||||
*
|
||||
* @dev Beware that changing an allowance with this method brings the risk that
|
||||
* @dev someone may use both the old and the new allowance by unfortunate
|
||||
* @dev transaction ordering. One possible solution to mitigate this race condition
|
||||
* @dev is to first reduce the spender's allowance to 0 and set the desired value
|
||||
* @dev afterwards:
|
||||
* @dev https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
|
||||
*
|
||||
* @param _spender The address that will spend the funds.
|
||||
* @param _value The amount of tokens to be spent.
|
||||
* @param _data ABI-encoded contract call to call `_to` address.
|
||||
*
|
||||
* @return true if the call function was executed successfully
|
||||
*/
|
||||
function approveAndCall(address _spender, uint256 _value, bytes _data) public payable returns (bool) {
|
||||
require(_spender != address(this));
|
||||
|
||||
super.approve(_spender, _value);
|
||||
|
||||
// solium-disable-next-line security/no-call-value
|
||||
require(_spender.call.value(msg.value)(_data));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Addition to ERC20 token methods. Transfer tokens to a specified
|
||||
* @dev address and execute a call with the sent data on the same transaction
|
||||
*
|
||||
* @param _to address The address which you want to transfer to
|
||||
* @param _value uint256 the amout of tokens to be transfered
|
||||
* @param _data ABI-encoded contract call to call `_to` address.
|
||||
*
|
||||
* @return true if the call function was executed successfully
|
||||
*/
|
||||
function transferAndCall(address _to, uint256 _value, bytes _data) public payable returns (bool) {
|
||||
require(_to != address(this));
|
||||
|
||||
super.transfer(_to, _value);
|
||||
|
||||
// solium-disable-next-line security/no-call-value
|
||||
require(_to.call.value(msg.value)(_data));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Addition to ERC20 token methods. Transfer tokens from one address to
|
||||
* @dev another and make a contract call on the same transaction
|
||||
*
|
||||
* @param _from The address which you want to send tokens from
|
||||
* @param _to The address which you want to transfer to
|
||||
* @param _value The amout of tokens to be transferred
|
||||
* @param _data ABI-encoded contract call to call `_to` address.
|
||||
*
|
||||
* @return true if the call function was executed successfully
|
||||
*/
|
||||
function transferFromAndCall(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _value,
|
||||
bytes _data
|
||||
)
|
||||
public payable returns (bool)
|
||||
{
|
||||
require(_to != address(this));
|
||||
|
||||
super.transferFrom(_from, _to, _value);
|
||||
|
||||
// solium-disable-next-line security/no-call-value
|
||||
require(_to.call.value(msg.value)(_data));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Addition to StandardToken methods. Increase the amount of tokens that
|
||||
* @dev an owner allowed to a spender and execute a call with the sent data.
|
||||
*
|
||||
* @dev approve should be called when allowed[_spender] == 0. To increment
|
||||
* @dev allowed value is better to use this function to avoid 2 calls (and wait until
|
||||
* @dev the first transaction is mined)
|
||||
* @dev From MonolithDAO Token.sol
|
||||
*
|
||||
* @param _spender The address which will spend the funds.
|
||||
* @param _addedValue The amount of tokens to increase the allowance by.
|
||||
* @param _data ABI-encoded contract call to call `_spender` address.
|
||||
*/
|
||||
function increaseApprovalAndCall(address _spender, uint _addedValue, bytes _data) public payable returns (bool) {
|
||||
require(_spender != address(this));
|
||||
|
||||
super.increaseApproval(_spender, _addedValue);
|
||||
|
||||
// solium-disable-next-line security/no-call-value
|
||||
require(_spender.call.value(msg.value)(_data));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Addition to StandardToken methods. Decrease the amount of tokens that
|
||||
* @dev an owner allowed to a spender and execute a call with the sent data.
|
||||
*
|
||||
* @dev approve should be called when allowed[_spender] == 0. To decrement
|
||||
* @dev allowed value is better to use this function to avoid 2 calls (and wait until
|
||||
* @dev the first transaction is mined)
|
||||
* @dev From MonolithDAO Token.sol
|
||||
*
|
||||
* @param _spender The address which will spend the funds.
|
||||
* @param _subtractedValue The amount of tokens to decrease the allowance by.
|
||||
* @param _data ABI-encoded contract call to call `_spender` address.
|
||||
*/
|
||||
function decreaseApprovalAndCall(address _spender, uint _subtractedValue, bytes _data) public payable returns (bool) {
|
||||
require(_spender != address(this));
|
||||
|
||||
super.decreaseApproval(_spender, _subtractedValue);
|
||||
|
||||
// solium-disable-next-line security/no-call-value
|
||||
require(_spender.call.value(msg.value)(_data));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"package_name": "zeppelin",
|
||||
"version": "1.9.0",
|
||||
"version": "1.9.1",
|
||||
"description": "Secure Smart Contract library for Solidity",
|
||||
"authors": [
|
||||
"Manuel Araoz <manuelaraoz@gmail.com>"
|
||||
|
||||
7673
package-lock.json
generated
7673
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
19
package.json
19
package.json
@ -1,12 +1,16 @@
|
||||
{
|
||||
"name": "openzeppelin-solidity",
|
||||
"version": "1.9.0",
|
||||
"name": "openzeppelin-zos",
|
||||
"version": "1.9.1",
|
||||
"description": "Secure Smart Contract library for Solidity",
|
||||
"files": [
|
||||
"contracts",
|
||||
"test"
|
||||
"build",
|
||||
"test",
|
||||
"zos.json",
|
||||
"zos.*.json"
|
||||
],
|
||||
"scripts": {
|
||||
"prepack": "truffle compile",
|
||||
"test": "scripts/test.sh",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix",
|
||||
@ -59,6 +63,13 @@
|
||||
"solidity-coverage": "^0.4.15",
|
||||
"solium": "^1.1.6",
|
||||
"truffle": "^4.1.5",
|
||||
"truffle-hdwallet-provider": "0.0.3"
|
||||
"truffle-hdwallet-provider": "0.0.3",
|
||||
"zos": "^0.8.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"zos-lib": "^0.1.26"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"zos-lib": "^0.1.26"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,111 +0,0 @@
|
||||
|
||||
let sendReward = function (sender, receiver, value) {
|
||||
web3.eth.sendTransaction({
|
||||
from: sender,
|
||||
to: receiver,
|
||||
value: value,
|
||||
});
|
||||
};
|
||||
var SecureTargetBounty = artifacts.require('SecureTargetBounty');
|
||||
var InsecureTargetBounty = artifacts.require('InsecureTargetBounty');
|
||||
|
||||
function awaitEvent (event, handler) {
|
||||
return new Promise((resolve, reject) => {
|
||||
function wrappedHandler (...args) {
|
||||
Promise.resolve(handler(...args)).then(resolve).catch(reject);
|
||||
}
|
||||
|
||||
event.watch(wrappedHandler);
|
||||
});
|
||||
}
|
||||
|
||||
contract('Bounty', function (accounts) {
|
||||
it('sets reward', async function () {
|
||||
let owner = accounts[0];
|
||||
let reward = web3.toWei(1, 'ether');
|
||||
let bounty = await SecureTargetBounty.new();
|
||||
sendReward(owner, bounty.address, reward);
|
||||
|
||||
assert.equal(reward, web3.eth.getBalance(bounty.address).toNumber());
|
||||
});
|
||||
|
||||
it('empties itself when destroyed', async function () {
|
||||
let owner = accounts[0];
|
||||
let reward = web3.toWei(1, 'ether');
|
||||
let bounty = await SecureTargetBounty.new();
|
||||
sendReward(owner, bounty.address, reward);
|
||||
|
||||
assert.equal(reward, web3.eth.getBalance(bounty.address).toNumber());
|
||||
|
||||
await bounty.destroy();
|
||||
assert.equal(0, web3.eth.getBalance(bounty.address).toNumber());
|
||||
});
|
||||
|
||||
describe('Against secure contract', function () {
|
||||
it('cannot claim reward', async function () {
|
||||
let owner = accounts[0];
|
||||
let researcher = accounts[1];
|
||||
let reward = web3.toWei(1, 'ether');
|
||||
let bounty = await SecureTargetBounty.new();
|
||||
let event = bounty.TargetCreated({});
|
||||
|
||||
let watcher = async function (err, result) {
|
||||
event.stopWatching();
|
||||
if (err) { throw err; }
|
||||
|
||||
var targetAddress = result.args.createdAddress;
|
||||
sendReward(owner, bounty.address, reward);
|
||||
|
||||
assert.equal(reward,
|
||||
web3.eth.getBalance(bounty.address).toNumber());
|
||||
|
||||
try {
|
||||
await bounty.claim(targetAddress, { from: researcher });
|
||||
assert.isTrue(false); // should never reach here
|
||||
} catch (error) {
|
||||
let reClaimedBounty = await bounty.claimed.call();
|
||||
assert.isFalse(reClaimedBounty);
|
||||
}
|
||||
try {
|
||||
await bounty.withdrawPayments({ from: researcher });
|
||||
assert.isTrue(false); // should never reach here
|
||||
} catch (err) {
|
||||
assert.equal(reward,
|
||||
web3.eth.getBalance(bounty.address).toNumber());
|
||||
}
|
||||
};
|
||||
await bounty.createTarget({ from: researcher });
|
||||
await awaitEvent(event, watcher);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Against broken contract', function () {
|
||||
it('claims reward', async function () {
|
||||
let owner = accounts[0];
|
||||
let researcher = accounts[1];
|
||||
let reward = web3.toWei(1, 'ether');
|
||||
let bounty = await InsecureTargetBounty.new();
|
||||
let event = bounty.TargetCreated({});
|
||||
|
||||
let watcher = async function (err, result) {
|
||||
event.stopWatching();
|
||||
if (err) { throw err; }
|
||||
let targetAddress = result.args.createdAddress;
|
||||
sendReward(owner, bounty.address, reward);
|
||||
|
||||
assert.equal(reward, web3.eth.getBalance(bounty.address).toNumber());
|
||||
|
||||
await bounty.claim(targetAddress, { from: researcher });
|
||||
let claim = await bounty.claimed.call();
|
||||
|
||||
assert.isTrue(claim);
|
||||
|
||||
await bounty.withdrawPayments({ from: researcher });
|
||||
|
||||
assert.equal(0, web3.eth.getBalance(bounty.address).toNumber());
|
||||
};
|
||||
await bounty.createTarget({ from: researcher });
|
||||
await awaitEvent(event, watcher);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,88 +0,0 @@
|
||||
|
||||
import latestTime from './helpers/latestTime';
|
||||
import { increaseTimeTo, duration } from './helpers/increaseTime';
|
||||
|
||||
import assertRevert from './helpers/assertRevert';
|
||||
|
||||
const DayLimitMock = artifacts.require('DayLimitMock');
|
||||
|
||||
contract('DayLimit', function (accounts) {
|
||||
let dayLimit;
|
||||
let initLimit = 10;
|
||||
|
||||
beforeEach(async function () {
|
||||
this.startTime = latestTime();
|
||||
dayLimit = await DayLimitMock.new(initLimit);
|
||||
});
|
||||
|
||||
it('should construct with the passed daily limit', async function () {
|
||||
let dailyLimit = await dayLimit.dailyLimit();
|
||||
assert.equal(initLimit, dailyLimit);
|
||||
});
|
||||
|
||||
it('should be able to spend if daily limit is not reached', async function () {
|
||||
await dayLimit.attemptSpend(8);
|
||||
let spentToday = await dayLimit.spentToday();
|
||||
assert.equal(spentToday, 8);
|
||||
|
||||
await dayLimit.attemptSpend(2);
|
||||
spentToday = await dayLimit.spentToday();
|
||||
assert.equal(spentToday, 10);
|
||||
});
|
||||
|
||||
it('should prevent spending if daily limit is reached', async function () {
|
||||
await dayLimit.attemptSpend(8);
|
||||
let spentToday = await dayLimit.spentToday();
|
||||
assert.equal(spentToday, 8);
|
||||
await assertRevert(dayLimit.attemptSpend(3));
|
||||
});
|
||||
|
||||
it('should allow spending if daily limit is reached and then set higher', async function () {
|
||||
await dayLimit.attemptSpend(8);
|
||||
let spentToday = await dayLimit.spentToday();
|
||||
assert.equal(spentToday, 8);
|
||||
|
||||
await assertRevert(dayLimit.attemptSpend(3));
|
||||
spentToday = await dayLimit.spentToday();
|
||||
assert.equal(spentToday, 8);
|
||||
|
||||
await dayLimit.setDailyLimit(15);
|
||||
await dayLimit.attemptSpend(3);
|
||||
spentToday = await dayLimit.spentToday();
|
||||
assert.equal(spentToday, 11);
|
||||
});
|
||||
|
||||
it('should allow spending if daily limit is reached and then amount spent is reset', async function () {
|
||||
await dayLimit.attemptSpend(8);
|
||||
let spentToday = await dayLimit.spentToday();
|
||||
assert.equal(spentToday, 8);
|
||||
|
||||
await assertRevert(dayLimit.attemptSpend(3));
|
||||
spentToday = await dayLimit.spentToday();
|
||||
assert.equal(spentToday, 8);
|
||||
|
||||
await dayLimit.resetSpentToday();
|
||||
await dayLimit.attemptSpend(3);
|
||||
spentToday = await dayLimit.spentToday();
|
||||
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);
|
||||
|
||||
await assertRevert(dayLimit.attemptSpend(3));
|
||||
spentToday = await dayLimit.spentToday();
|
||||
assert.equal(spentToday, 8);
|
||||
|
||||
await increaseTimeTo(this.startTime + duration.days(1));
|
||||
|
||||
await dayLimit.attemptSpend(3);
|
||||
spentToday = await dayLimit.spentToday();
|
||||
assert.equal(spentToday, 3);
|
||||
});
|
||||
});
|
||||
@ -1,136 +0,0 @@
|
||||
import increaseTime from './helpers/increaseTime';
|
||||
import expectThrow from './helpers/expectThrow';
|
||||
import assertRevert from './helpers/assertRevert';
|
||||
|
||||
const NULL_ADDRESS = '0x0000000000000000000000000000000000000000';
|
||||
|
||||
const Heritable = artifacts.require('Heritable');
|
||||
|
||||
contract('Heritable', function (accounts) {
|
||||
let heritable;
|
||||
let owner;
|
||||
|
||||
beforeEach(async function () {
|
||||
heritable = await Heritable.new(4141);
|
||||
owner = await heritable.owner();
|
||||
});
|
||||
|
||||
it('should start off with an owner, but without heir', async function () {
|
||||
const heir = await heritable.heir();
|
||||
|
||||
assert.equal(typeof (owner), 'string');
|
||||
assert.equal(typeof (heir), 'string');
|
||||
assert.notStrictEqual(
|
||||
owner, NULL_ADDRESS,
|
||||
'Owner shouldn\'t be the null address'
|
||||
);
|
||||
assert.isTrue(
|
||||
heir === NULL_ADDRESS,
|
||||
'Heir should be the null address'
|
||||
);
|
||||
});
|
||||
|
||||
it('only owner should set heir', async function () {
|
||||
const newHeir = accounts[1];
|
||||
const someRandomAddress = accounts[2];
|
||||
assert.isTrue(owner !== someRandomAddress);
|
||||
|
||||
await heritable.setHeir(newHeir, { from: owner });
|
||||
await expectThrow(heritable.setHeir(newHeir, { from: someRandomAddress }));
|
||||
});
|
||||
|
||||
it('owner can\'t be heir', async function () {
|
||||
await assertRevert(heritable.setHeir(owner, { from: owner }));
|
||||
});
|
||||
|
||||
it('owner can remove heir', async function () {
|
||||
const newHeir = accounts[1];
|
||||
await heritable.setHeir(newHeir, { from: owner });
|
||||
let heir = await heritable.heir();
|
||||
|
||||
assert.notStrictEqual(heir, NULL_ADDRESS);
|
||||
await heritable.removeHeir();
|
||||
heir = await heritable.heir();
|
||||
assert.isTrue(heir === NULL_ADDRESS);
|
||||
});
|
||||
|
||||
it('heir can claim ownership only if owner is dead and timeout was reached', async function () {
|
||||
const heir = accounts[1];
|
||||
await heritable.setHeir(heir, { from: owner });
|
||||
await expectThrow(heritable.claimHeirOwnership({ from: heir }));
|
||||
|
||||
await heritable.proclaimDeath({ from: heir });
|
||||
await increaseTime(1);
|
||||
await expectThrow(heritable.claimHeirOwnership({ from: heir }));
|
||||
|
||||
await increaseTime(4141);
|
||||
await heritable.claimHeirOwnership({ from: heir });
|
||||
assert.isTrue(await heritable.heir() === heir);
|
||||
});
|
||||
|
||||
it('only heir can proclaim death', async function () {
|
||||
const someRandomAddress = accounts[2];
|
||||
await assertRevert(heritable.proclaimDeath({ from: owner }));
|
||||
await assertRevert(heritable.proclaimDeath({ from: someRandomAddress }));
|
||||
});
|
||||
|
||||
it('heir can\'t proclaim death if owner is death', async function () {
|
||||
const heir = accounts[1];
|
||||
await heritable.setHeir(heir, { from: owner });
|
||||
await heritable.proclaimDeath({ from: heir });
|
||||
await assertRevert(heritable.proclaimDeath({ from: heir }));
|
||||
});
|
||||
|
||||
it('heir can\'t claim ownership if owner heartbeats', async function () {
|
||||
const heir = accounts[1];
|
||||
await heritable.setHeir(heir, { from: owner });
|
||||
|
||||
await heritable.proclaimDeath({ from: heir });
|
||||
await heritable.heartbeat({ from: owner });
|
||||
await expectThrow(heritable.claimHeirOwnership({ from: heir }));
|
||||
|
||||
await heritable.proclaimDeath({ from: heir });
|
||||
await increaseTime(4141);
|
||||
await heritable.heartbeat({ from: owner });
|
||||
await expectThrow(heritable.claimHeirOwnership({ from: heir }));
|
||||
});
|
||||
|
||||
it('should log events appropriately', async function () {
|
||||
const heir = accounts[1];
|
||||
|
||||
const setHeirLogs = (await heritable.setHeir(heir, { from: owner })).logs;
|
||||
const setHeirEvent = setHeirLogs.find(e => e.event === 'HeirChanged');
|
||||
|
||||
assert.isTrue(setHeirEvent.args.owner === owner);
|
||||
assert.isTrue(setHeirEvent.args.newHeir === heir);
|
||||
|
||||
const heartbeatLogs = (await heritable.heartbeat({ from: owner })).logs;
|
||||
const heartbeatEvent = heartbeatLogs.find(e => e.event === 'OwnerHeartbeated');
|
||||
|
||||
assert.isTrue(heartbeatEvent.args.owner === owner);
|
||||
|
||||
const proclaimDeathLogs = (await heritable.proclaimDeath({ from: heir })).logs;
|
||||
const ownerDeadEvent = proclaimDeathLogs.find(e => e.event === 'OwnerProclaimedDead');
|
||||
|
||||
assert.isTrue(ownerDeadEvent.args.owner === owner);
|
||||
assert.isTrue(ownerDeadEvent.args.heir === heir);
|
||||
|
||||
await increaseTime(4141);
|
||||
const claimHeirOwnershipLogs = (await heritable.claimHeirOwnership({ from: heir })).logs;
|
||||
const ownershipTransferredEvent = claimHeirOwnershipLogs.find(e => e.event === 'OwnershipTransferred');
|
||||
const heirOwnershipClaimedEvent = claimHeirOwnershipLogs.find(e => e.event === 'HeirOwnershipClaimed');
|
||||
|
||||
assert.isTrue(ownershipTransferredEvent.args.previousOwner === owner);
|
||||
assert.isTrue(ownershipTransferredEvent.args.newOwner === heir);
|
||||
assert.isTrue(heirOwnershipClaimedEvent.args.previousOwner === owner);
|
||||
assert.isTrue(heirOwnershipClaimedEvent.args.newOwner === heir);
|
||||
});
|
||||
|
||||
it('timeOfDeath can be queried', async function () {
|
||||
assert.equal(await heritable.timeOfDeath(), 0);
|
||||
});
|
||||
|
||||
it('heartbeatTimeout can be queried', async function () {
|
||||
assert.equal(await heritable.heartbeatTimeout(), 4141);
|
||||
});
|
||||
});
|
||||
@ -1,47 +0,0 @@
|
||||
import assertRevert from './helpers/assertRevert';
|
||||
var LimitBalanceMock = artifacts.require('LimitBalanceMock');
|
||||
|
||||
contract('LimitBalance', function (accounts) {
|
||||
let lb;
|
||||
|
||||
beforeEach(async function () {
|
||||
lb = await LimitBalanceMock.new();
|
||||
});
|
||||
|
||||
let LIMIT = 1000;
|
||||
|
||||
it('should expose limit', async function () {
|
||||
let limit = await lb.limit();
|
||||
assert.equal(limit, LIMIT);
|
||||
});
|
||||
|
||||
it('should allow sending below limit', async function () {
|
||||
let amount = 1;
|
||||
await lb.limitedDeposit({ value: amount });
|
||||
|
||||
assert.equal(web3.eth.getBalance(lb.address), amount);
|
||||
});
|
||||
|
||||
it('shouldnt allow sending above limit', async function () {
|
||||
let amount = 1110;
|
||||
await assertRevert(lb.limitedDeposit({ value: amount }));
|
||||
});
|
||||
|
||||
it('should allow multiple sends below limit', async function () {
|
||||
let amount = 500;
|
||||
await lb.limitedDeposit({ value: amount });
|
||||
|
||||
assert.equal(web3.eth.getBalance(lb.address), amount);
|
||||
|
||||
await lb.limitedDeposit({ value: amount });
|
||||
assert.equal(web3.eth.getBalance(lb.address), amount * 2);
|
||||
});
|
||||
|
||||
it('shouldnt allow multiple sends above limit', async function () {
|
||||
let amount = 500;
|
||||
await lb.limitedDeposit({ value: amount });
|
||||
|
||||
assert.equal(web3.eth.getBalance(lb.address), amount);
|
||||
await assertRevert(lb.limitedDeposit({ value: amount + 1 }));
|
||||
});
|
||||
});
|
||||
@ -1,31 +0,0 @@
|
||||
|
||||
import expectThrow from './helpers/expectThrow';
|
||||
const ReentrancyMock = artifacts.require('ReentrancyMock');
|
||||
const ReentrancyAttack = artifacts.require('ReentrancyAttack');
|
||||
|
||||
contract('ReentrancyGuard', function (accounts) {
|
||||
let reentrancyMock;
|
||||
|
||||
beforeEach(async function () {
|
||||
reentrancyMock = await ReentrancyMock.new();
|
||||
let initialCounter = await reentrancyMock.counter();
|
||||
assert.equal(initialCounter, 0);
|
||||
});
|
||||
|
||||
it('should not allow remote callback', async function () {
|
||||
let attacker = await ReentrancyAttack.new();
|
||||
await expectThrow(reentrancyMock.countAndCall(attacker.address));
|
||||
});
|
||||
|
||||
// The following are more side-effects than intended behaviour:
|
||||
// I put them here as documentation, and to monitor any changes
|
||||
// in the side-effects.
|
||||
|
||||
it('should not allow local recursion', async function () {
|
||||
await expectThrow(reentrancyMock.countLocalRecursive(10));
|
||||
});
|
||||
|
||||
it('should not allow indirect local recursion', async function () {
|
||||
await expectThrow(reentrancyMock.countThisRecursive(10));
|
||||
});
|
||||
});
|
||||
@ -1,33 +0,0 @@
|
||||
|
||||
import expectThrow from './helpers/expectThrow';
|
||||
|
||||
const SimpleSavingsWallet = artifacts.require('SimpleSavingsWallet');
|
||||
|
||||
contract('SimpleSavingsWallet', function (accounts) {
|
||||
let savingsWallet;
|
||||
let owner;
|
||||
|
||||
const paymentAmount = 4242;
|
||||
|
||||
beforeEach(async function () {
|
||||
savingsWallet = await SimpleSavingsWallet.new(4141);
|
||||
owner = await savingsWallet.owner();
|
||||
});
|
||||
|
||||
it('should receive funds', async function () {
|
||||
await web3.eth.sendTransaction({ from: owner, to: savingsWallet.address, value: paymentAmount });
|
||||
assert.isTrue((new web3.BigNumber(paymentAmount)).equals(web3.eth.getBalance(savingsWallet.address)));
|
||||
});
|
||||
|
||||
it('owner can send funds', async function () {
|
||||
// Receive payment so we have some money to spend.
|
||||
await web3.eth.sendTransaction({ from: accounts[9], to: savingsWallet.address, value: 1000000 });
|
||||
await expectThrow(savingsWallet.sendTo(0, paymentAmount, { from: owner }));
|
||||
await expectThrow(savingsWallet.sendTo(savingsWallet.address, paymentAmount, { from: owner }));
|
||||
await expectThrow(savingsWallet.sendTo(accounts[1], 0, { from: owner }));
|
||||
|
||||
const balance = web3.eth.getBalance(accounts[1]);
|
||||
await savingsWallet.sendTo(accounts[1], paymentAmount, { from: owner });
|
||||
assert.isTrue(balance.plus(paymentAmount).equals(web3.eth.getBalance(accounts[1])));
|
||||
});
|
||||
});
|
||||
@ -17,7 +17,8 @@ export const getSigner = (contract, signer, data = '') => (addr) => {
|
||||
|
||||
contract('Bouncer', ([_, owner, authorizedUser, anyone, bouncerAddress, newBouncer]) => {
|
||||
before(async function () {
|
||||
this.bouncer = await Bouncer.new({ from: owner });
|
||||
this.bouncer = await Bouncer.new();
|
||||
await this.bouncer.initialize(owner);
|
||||
this.roleBouncer = await this.bouncer.ROLE_BOUNCER();
|
||||
this.genSig = getSigner(this.bouncer, bouncerAddress);
|
||||
});
|
||||
|
||||
@ -1,77 +0,0 @@
|
||||
import ether from '../helpers/ether';
|
||||
import assertRevert from '../helpers/assertRevert';
|
||||
|
||||
const BigNumber = web3.BigNumber;
|
||||
|
||||
const should = require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
|
||||
const AllowanceCrowdsale = artifacts.require('AllowanceCrowdsaleImpl');
|
||||
const SimpleToken = artifacts.require('SimpleToken');
|
||||
|
||||
contract('AllowanceCrowdsale', function ([_, investor, wallet, purchaser, tokenWallet]) {
|
||||
const rate = new BigNumber(1);
|
||||
const value = ether(0.42);
|
||||
const expectedTokenAmount = rate.mul(value);
|
||||
const tokenAllowance = new BigNumber('1e22');
|
||||
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
||||
|
||||
beforeEach(async function () {
|
||||
this.token = await SimpleToken.new({ from: tokenWallet });
|
||||
this.crowdsale = await AllowanceCrowdsale.new(rate, wallet, this.token.address, tokenWallet);
|
||||
await this.token.approve(this.crowdsale.address, tokenAllowance, { from: tokenWallet });
|
||||
});
|
||||
|
||||
describe('accepting payments', function () {
|
||||
it('should accept sends', async function () {
|
||||
await this.crowdsale.send(value).should.be.fulfilled;
|
||||
});
|
||||
|
||||
it('should accept payments', async function () {
|
||||
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }).should.be.fulfilled;
|
||||
});
|
||||
});
|
||||
|
||||
describe('high-level purchase', function () {
|
||||
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 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('check remaining allowance', function () {
|
||||
it('should report correct allowace left', async function () {
|
||||
let remainingAllowance = tokenAllowance - expectedTokenAmount;
|
||||
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
|
||||
let tokensRemaining = await this.crowdsale.remainingTokens();
|
||||
tokensRemaining.should.be.bignumber.equal(remainingAllowance);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when token wallet is different from token address', function () {
|
||||
it('creation reverts', async function () {
|
||||
this.token = await SimpleToken.new({ from: tokenWallet });
|
||||
await assertRevert(AllowanceCrowdsale.new(rate, wallet, this.token.address, ZERO_ADDRESS));
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,69 +0,0 @@
|
||||
import ether from '../helpers/ether';
|
||||
import EVMRevert from '../helpers/EVMRevert';
|
||||
|
||||
const BigNumber = web3.BigNumber;
|
||||
|
||||
require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
|
||||
const CappedCrowdsale = artifacts.require('CappedCrowdsaleImpl');
|
||||
const SimpleToken = artifacts.require('SimpleToken');
|
||||
|
||||
contract('CappedCrowdsale', function ([_, wallet]) {
|
||||
const rate = new BigNumber(1);
|
||||
const cap = ether(100);
|
||||
const lessThanCap = ether(60);
|
||||
const tokenSupply = new BigNumber('1e22');
|
||||
|
||||
beforeEach(async function () {
|
||||
this.token = await SimpleToken.new();
|
||||
this.crowdsale = await CappedCrowdsale.new(rate, wallet, this.token.address, cap);
|
||||
await this.token.transfer(this.crowdsale.address, tokenSupply);
|
||||
});
|
||||
|
||||
describe('creating a valid crowdsale', function () {
|
||||
it('should fail with zero cap', async function () {
|
||||
await CappedCrowdsale.new(rate, wallet, 0, this.token.address).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
});
|
||||
|
||||
describe('accepting payments', function () {
|
||||
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(EVMRevert);
|
||||
});
|
||||
|
||||
it('should reject payments that exceed cap', async function () {
|
||||
await this.crowdsale.send(cap.plus(1)).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ending', function () {
|
||||
it('should not reach cap if sent under cap', async function () {
|
||||
let capReached = await this.crowdsale.capReached();
|
||||
capReached.should.equal(false);
|
||||
await this.crowdsale.send(lessThanCap);
|
||||
capReached = await this.crowdsale.capReached();
|
||||
capReached.should.equal(false);
|
||||
});
|
||||
|
||||
it('should not reach cap if sent just under cap', async function () {
|
||||
await this.crowdsale.send(cap.minus(1));
|
||||
let capReached = await this.crowdsale.capReached();
|
||||
capReached.should.equal(false);
|
||||
});
|
||||
|
||||
it('should reach cap if cap sent', async function () {
|
||||
await this.crowdsale.send(cap);
|
||||
let capReached = await this.crowdsale.capReached();
|
||||
capReached.should.equal(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,81 +0,0 @@
|
||||
import ether from '../helpers/ether';
|
||||
|
||||
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 SimpleToken = artifacts.require('SimpleToken');
|
||||
|
||||
contract('Crowdsale', function ([_, investor, wallet, purchaser]) {
|
||||
const rate = new BigNumber(1);
|
||||
const value = ether(42);
|
||||
const tokenSupply = new BigNumber('1e22');
|
||||
const expectedTokenAmount = rate.mul(value);
|
||||
|
||||
beforeEach(async function () {
|
||||
this.token = await SimpleToken.new();
|
||||
this.crowdsale = await Crowdsale.new(rate, wallet, this.token.address);
|
||||
await this.token.transfer(this.crowdsale.address, tokenSupply);
|
||||
});
|
||||
|
||||
describe('accepting payments', function () {
|
||||
it('should accept payments', async function () {
|
||||
await this.crowdsale.send(value).should.be.fulfilled;
|
||||
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }).should.be.fulfilled;
|
||||
});
|
||||
});
|
||||
|
||||
describe('high-level purchase', function () {
|
||||
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 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 () {
|
||||
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 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,62 +0,0 @@
|
||||
import { advanceBlock } from '../helpers/advanceToBlock';
|
||||
import { increaseTimeTo, duration } from '../helpers/increaseTime';
|
||||
import latestTime from '../helpers/latestTime';
|
||||
import EVMRevert from '../helpers/EVMRevert';
|
||||
|
||||
const BigNumber = web3.BigNumber;
|
||||
|
||||
const should = require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
|
||||
const FinalizableCrowdsale = artifacts.require('FinalizableCrowdsaleImpl');
|
||||
const MintableToken = artifacts.require('MintableToken');
|
||||
|
||||
contract('FinalizableCrowdsale', function ([_, owner, wallet, thirdparty]) {
|
||||
const rate = new BigNumber(1000);
|
||||
|
||||
before(async function () {
|
||||
// Advance to the next block to correctly read time in the solidity "now" function interpreted by ganache
|
||||
await advanceBlock();
|
||||
});
|
||||
|
||||
beforeEach(async function () {
|
||||
this.openingTime = latestTime() + duration.weeks(1);
|
||||
this.closingTime = this.openingTime + duration.weeks(1);
|
||||
this.afterClosingTime = this.closingTime + duration.seconds(1);
|
||||
|
||||
this.token = await MintableToken.new();
|
||||
this.crowdsale = await FinalizableCrowdsale.new(
|
||||
this.openingTime, this.closingTime, rate, wallet, this.token.address, { from: owner }
|
||||
);
|
||||
await this.token.transferOwnership(this.crowdsale.address);
|
||||
});
|
||||
|
||||
it('cannot be finalized before ending', async function () {
|
||||
await this.crowdsale.finalize({ from: owner }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
|
||||
it('cannot be finalized by third party after ending', async function () {
|
||||
await increaseTimeTo(this.afterClosingTime);
|
||||
await this.crowdsale.finalize({ from: thirdparty }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
|
||||
it('can be finalized by owner after ending', async function () {
|
||||
await increaseTimeTo(this.afterClosingTime);
|
||||
await this.crowdsale.finalize({ from: owner }).should.be.fulfilled;
|
||||
});
|
||||
|
||||
it('cannot be finalized twice', async function () {
|
||||
await increaseTimeTo(this.afterClosingTime);
|
||||
await this.crowdsale.finalize({ from: owner });
|
||||
await this.crowdsale.finalize({ from: owner }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
|
||||
it('logs finalized', async function () {
|
||||
await increaseTimeTo(this.afterClosingTime);
|
||||
const { logs } = await this.crowdsale.finalize({ from: owner });
|
||||
const event = logs.find(e => e.event === 'Finalized');
|
||||
should.exist(event);
|
||||
});
|
||||
});
|
||||
@ -1,92 +0,0 @@
|
||||
import ether from '../helpers/ether';
|
||||
import { advanceBlock } from '../helpers/advanceToBlock';
|
||||
import { increaseTimeTo, duration } from '../helpers/increaseTime';
|
||||
import latestTime from '../helpers/latestTime';
|
||||
|
||||
const BigNumber = web3.BigNumber;
|
||||
|
||||
require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
|
||||
const IncreasingPriceCrowdsale = artifacts.require('IncreasingPriceCrowdsaleImpl');
|
||||
const SimpleToken = artifacts.require('SimpleToken');
|
||||
|
||||
contract('IncreasingPriceCrowdsale', function ([_, investor, wallet, purchaser]) {
|
||||
const value = ether(1);
|
||||
const tokenSupply = new BigNumber('1e22');
|
||||
|
||||
describe('rate during crowdsale should change at a fixed step every block', async function () {
|
||||
let balance;
|
||||
const initialRate = new BigNumber(9166);
|
||||
const finalRate = new BigNumber(5500);
|
||||
const rateAtTime150 = new BigNumber(9166);
|
||||
const rateAtTime300 = new BigNumber(9165);
|
||||
const rateAtTime1500 = new BigNumber(9157);
|
||||
const rateAtTime30 = new BigNumber(9166);
|
||||
const rateAtTime150000 = new BigNumber(8257);
|
||||
const rateAtTime450000 = new BigNumber(6439);
|
||||
|
||||
beforeEach(async function () {
|
||||
await advanceBlock();
|
||||
this.startTime = latestTime() + duration.weeks(1);
|
||||
this.closingTime = this.startTime + duration.weeks(1);
|
||||
this.afterClosingTime = this.closingTime + duration.seconds(1);
|
||||
this.token = await SimpleToken.new();
|
||||
this.crowdsale = await IncreasingPriceCrowdsale.new(
|
||||
this.startTime, this.closingTime, wallet, this.token.address, initialRate, finalRate
|
||||
);
|
||||
await this.token.transfer(this.crowdsale.address, tokenSupply);
|
||||
});
|
||||
|
||||
it('at start', async function () {
|
||||
await increaseTimeTo(this.startTime);
|
||||
await this.crowdsale.buyTokens(investor, { value, from: purchaser });
|
||||
balance = await this.token.balanceOf(investor);
|
||||
balance.should.be.bignumber.equal(value.mul(initialRate));
|
||||
});
|
||||
|
||||
it('at time 150', async function () {
|
||||
await increaseTimeTo(this.startTime + 150);
|
||||
await this.crowdsale.buyTokens(investor, { value, from: purchaser });
|
||||
balance = await this.token.balanceOf(investor);
|
||||
balance.should.be.bignumber.equal(value.mul(rateAtTime150));
|
||||
});
|
||||
|
||||
it('at time 300', async function () {
|
||||
await increaseTimeTo(this.startTime + 300);
|
||||
await this.crowdsale.buyTokens(investor, { value, from: purchaser });
|
||||
balance = await this.token.balanceOf(investor);
|
||||
balance.should.be.bignumber.equal(value.mul(rateAtTime300));
|
||||
});
|
||||
|
||||
it('at time 1500', async function () {
|
||||
await increaseTimeTo(this.startTime + 1500);
|
||||
await this.crowdsale.buyTokens(investor, { value, from: purchaser });
|
||||
balance = await this.token.balanceOf(investor);
|
||||
balance.should.be.bignumber.equal(value.mul(rateAtTime1500));
|
||||
});
|
||||
|
||||
it('at time 30', async function () {
|
||||
await increaseTimeTo(this.startTime + 30);
|
||||
await this.crowdsale.buyTokens(investor, { value, from: purchaser });
|
||||
balance = await this.token.balanceOf(investor);
|
||||
balance.should.be.bignumber.equal(value.mul(rateAtTime30));
|
||||
});
|
||||
|
||||
it('at time 150000', async function () {
|
||||
await increaseTimeTo(this.startTime + 150000);
|
||||
await this.crowdsale.buyTokens(investor, { value, from: purchaser });
|
||||
balance = await this.token.balanceOf(investor);
|
||||
balance.should.be.bignumber.equal(value.mul(rateAtTime150000));
|
||||
});
|
||||
|
||||
it('at time 450000', async function () {
|
||||
await increaseTimeTo(this.startTime + 450000);
|
||||
await this.crowdsale.buyTokens(investor, { value, from: purchaser });
|
||||
balance = await this.token.balanceOf(investor);
|
||||
balance.should.be.bignumber.equal(value.mul(rateAtTime450000));
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,107 +0,0 @@
|
||||
import ether from '../helpers/ether';
|
||||
import EVMRevert from '../helpers/EVMRevert';
|
||||
|
||||
const BigNumber = web3.BigNumber;
|
||||
|
||||
require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
|
||||
const CappedCrowdsale = artifacts.require('IndividuallyCappedCrowdsaleImpl');
|
||||
const SimpleToken = artifacts.require('SimpleToken');
|
||||
|
||||
contract('IndividuallyCappedCrowdsale', function ([_, wallet, alice, bob, charlie]) {
|
||||
const rate = new BigNumber(1);
|
||||
const capAlice = ether(10);
|
||||
const capBob = ether(2);
|
||||
const lessThanCapAlice = ether(6);
|
||||
const lessThanCapBoth = ether(1);
|
||||
const tokenSupply = new BigNumber('1e22');
|
||||
|
||||
describe('individual capping', function () {
|
||||
beforeEach(async function () {
|
||||
this.token = await SimpleToken.new();
|
||||
this.crowdsale = await CappedCrowdsale.new(rate, wallet, this.token.address);
|
||||
await this.crowdsale.setUserCap(alice, capAlice);
|
||||
await this.crowdsale.setUserCap(bob, capBob);
|
||||
await this.token.transfer(this.crowdsale.address, tokenSupply);
|
||||
});
|
||||
|
||||
describe('accepting payments', function () {
|
||||
it('should accept payments within cap', async function () {
|
||||
await this.crowdsale.buyTokens(alice, { value: lessThanCapAlice }).should.be.fulfilled;
|
||||
await this.crowdsale.buyTokens(bob, { value: lessThanCapBoth }).should.be.fulfilled;
|
||||
});
|
||||
|
||||
it('should reject payments outside cap', async function () {
|
||||
await this.crowdsale.buyTokens(alice, { value: capAlice });
|
||||
await this.crowdsale.buyTokens(alice, { value: 1 }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
|
||||
it('should reject payments that exceed cap', async function () {
|
||||
await this.crowdsale.buyTokens(alice, { value: capAlice.plus(1) }).should.be.rejectedWith(EVMRevert);
|
||||
await this.crowdsale.buyTokens(bob, { value: capBob.plus(1) }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
|
||||
it('should manage independent caps', async function () {
|
||||
await this.crowdsale.buyTokens(alice, { value: lessThanCapAlice }).should.be.fulfilled;
|
||||
await this.crowdsale.buyTokens(bob, { value: lessThanCapAlice }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
|
||||
it('should default to a cap of zero', async function () {
|
||||
await this.crowdsale.buyTokens(charlie, { value: lessThanCapBoth }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
});
|
||||
|
||||
describe('reporting state', function () {
|
||||
it('should report correct cap', async function () {
|
||||
let retrievedCap = await this.crowdsale.getUserCap(alice);
|
||||
retrievedCap.should.be.bignumber.equal(capAlice);
|
||||
});
|
||||
|
||||
it('should report actual contribution', async function () {
|
||||
await this.crowdsale.buyTokens(alice, { value: lessThanCapAlice });
|
||||
let retrievedContribution = await this.crowdsale.getUserContribution(alice);
|
||||
retrievedContribution.should.be.bignumber.equal(lessThanCapAlice);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('group capping', function () {
|
||||
beforeEach(async function () {
|
||||
this.token = await SimpleToken.new();
|
||||
this.crowdsale = await CappedCrowdsale.new(rate, wallet, this.token.address);
|
||||
await this.crowdsale.setGroupCap([bob, charlie], capBob);
|
||||
await this.token.transfer(this.crowdsale.address, tokenSupply);
|
||||
});
|
||||
|
||||
describe('accepting payments', function () {
|
||||
it('should accept payments within cap', async function () {
|
||||
await this.crowdsale.buyTokens(bob, { value: lessThanCapBoth }).should.be.fulfilled;
|
||||
await this.crowdsale.buyTokens(charlie, { value: lessThanCapBoth }).should.be.fulfilled;
|
||||
});
|
||||
|
||||
it('should reject payments outside cap', async function () {
|
||||
await this.crowdsale.buyTokens(bob, { value: capBob });
|
||||
await this.crowdsale.buyTokens(bob, { value: 1 }).should.be.rejectedWith(EVMRevert);
|
||||
await this.crowdsale.buyTokens(charlie, { value: capBob });
|
||||
await this.crowdsale.buyTokens(charlie, { value: 1 }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
|
||||
it('should reject payments that exceed cap', async function () {
|
||||
await this.crowdsale.buyTokens(bob, { value: capBob.plus(1) }).should.be.rejectedWith(EVMRevert);
|
||||
await this.crowdsale.buyTokens(charlie, { value: capBob.plus(1) }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
});
|
||||
|
||||
describe('reporting state', function () {
|
||||
it('should report correct cap', async function () {
|
||||
let retrievedCapBob = await this.crowdsale.getUserCap(bob);
|
||||
retrievedCapBob.should.be.bignumber.equal(capBob);
|
||||
let retrievedCapCharlie = await this.crowdsale.getUserCap(charlie);
|
||||
retrievedCapCharlie.should.be.bignumber.equal(capBob);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,61 +0,0 @@
|
||||
import ether from '../helpers/ether';
|
||||
|
||||
const BigNumber = web3.BigNumber;
|
||||
|
||||
const should = require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
|
||||
const MintedCrowdsale = artifacts.require('MintedCrowdsaleImpl');
|
||||
const MintableToken = artifacts.require('MintableToken');
|
||||
|
||||
contract('MintedCrowdsale', function ([_, investor, wallet, purchaser]) {
|
||||
const rate = new BigNumber(1000);
|
||||
const value = ether(42);
|
||||
|
||||
const expectedTokenAmount = rate.mul(value);
|
||||
|
||||
beforeEach(async function () {
|
||||
this.token = await MintableToken.new();
|
||||
this.crowdsale = await MintedCrowdsale.new(rate, wallet, this.token.address);
|
||||
await this.token.transferOwnership(this.crowdsale.address);
|
||||
});
|
||||
|
||||
describe('accepting payments', function () {
|
||||
it('should be token owner', async function () {
|
||||
const owner = await this.token.owner();
|
||||
owner.should.equal(this.crowdsale.address);
|
||||
});
|
||||
|
||||
it('should accept payments', async function () {
|
||||
await this.crowdsale.send(value).should.be.fulfilled;
|
||||
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }).should.be.fulfilled;
|
||||
});
|
||||
});
|
||||
|
||||
describe('high-level purchase', function () {
|
||||
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 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,67 +0,0 @@
|
||||
import { advanceBlock } from '../helpers/advanceToBlock';
|
||||
import { increaseTimeTo, duration } from '../helpers/increaseTime';
|
||||
import latestTime from '../helpers/latestTime';
|
||||
import EVMRevert from '../helpers/EVMRevert';
|
||||
import ether from '../helpers/ether';
|
||||
|
||||
const BigNumber = web3.BigNumber;
|
||||
|
||||
require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
|
||||
const PostDeliveryCrowdsale = artifacts.require('PostDeliveryCrowdsaleImpl');
|
||||
const SimpleToken = artifacts.require('SimpleToken');
|
||||
|
||||
contract('PostDeliveryCrowdsale', function ([_, investor, wallet, purchaser]) {
|
||||
const rate = new BigNumber(1);
|
||||
const value = ether(42);
|
||||
const tokenSupply = new BigNumber('1e22');
|
||||
|
||||
before(async function () {
|
||||
// Advance to the next block to correctly read time in the solidity "now" function interpreted by ganache
|
||||
await advanceBlock();
|
||||
});
|
||||
|
||||
beforeEach(async function () {
|
||||
this.openingTime = latestTime() + duration.weeks(1);
|
||||
this.closingTime = this.openingTime + duration.weeks(1);
|
||||
this.beforeEndTime = this.closingTime - duration.hours(1);
|
||||
this.afterClosingTime = this.closingTime + duration.seconds(1);
|
||||
this.token = await SimpleToken.new();
|
||||
this.crowdsale = await PostDeliveryCrowdsale.new(
|
||||
this.openingTime, this.closingTime, rate, wallet, this.token.address
|
||||
);
|
||||
await this.token.transfer(this.crowdsale.address, tokenSupply);
|
||||
});
|
||||
|
||||
it('should not immediately assign tokens to beneficiary', async function () {
|
||||
await increaseTimeTo(this.openingTime);
|
||||
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
|
||||
const balance = await this.token.balanceOf(investor);
|
||||
balance.should.be.bignumber.equal(0);
|
||||
});
|
||||
|
||||
it('should not allow beneficiaries to withdraw tokens before crowdsale ends', async function () {
|
||||
await increaseTimeTo(this.beforeEndTime);
|
||||
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
|
||||
await this.crowdsale.withdrawTokens({ from: investor }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
|
||||
it('should allow beneficiaries to withdraw tokens after crowdsale ends', async function () {
|
||||
await increaseTimeTo(this.openingTime);
|
||||
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
|
||||
await increaseTimeTo(this.afterClosingTime);
|
||||
await this.crowdsale.withdrawTokens({ from: investor }).should.be.fulfilled;
|
||||
});
|
||||
|
||||
it('should return the amount of tokens bought', async function () {
|
||||
await increaseTimeTo(this.openingTime);
|
||||
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
|
||||
await increaseTimeTo(this.afterClosingTime);
|
||||
await this.crowdsale.withdrawTokens({ from: investor });
|
||||
const balance = await this.token.balanceOf(investor);
|
||||
balance.should.be.bignumber.equal(value);
|
||||
});
|
||||
});
|
||||
@ -1,59 +0,0 @@
|
||||
import ether from '../helpers/ether';
|
||||
import EVMRevert from '../helpers/EVMRevert';
|
||||
|
||||
const BigNumber = web3.BigNumber;
|
||||
|
||||
require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
|
||||
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(EVMRevert);
|
||||
});
|
||||
|
||||
it('only owner can enter refund mode', async function () {
|
||||
await this.vault.enableRefunds({ from: _ }).should.be.rejectedWith(EVMRevert);
|
||||
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(EVMRevert);
|
||||
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);
|
||||
});
|
||||
});
|
||||
@ -1,82 +0,0 @@
|
||||
import ether from '../helpers/ether';
|
||||
import { advanceBlock } from '../helpers/advanceToBlock';
|
||||
import { increaseTimeTo, duration } from '../helpers/increaseTime';
|
||||
import latestTime from '../helpers/latestTime';
|
||||
import EVMRevert from '../helpers/EVMRevert';
|
||||
|
||||
const BigNumber = web3.BigNumber;
|
||||
|
||||
require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
|
||||
const RefundableCrowdsale = artifacts.require('RefundableCrowdsaleImpl');
|
||||
const SimpleToken = artifacts.require('SimpleToken');
|
||||
|
||||
contract('RefundableCrowdsale', function ([_, owner, wallet, investor, purchaser]) {
|
||||
const rate = new BigNumber(1);
|
||||
const goal = ether(50);
|
||||
const lessThanGoal = ether(45);
|
||||
const tokenSupply = new BigNumber('1e22');
|
||||
|
||||
before(async function () {
|
||||
// Advance to the next block to correctly read time in the solidity "now" function interpreted by ganache
|
||||
await advanceBlock();
|
||||
});
|
||||
|
||||
beforeEach(async function () {
|
||||
this.openingTime = latestTime() + duration.weeks(1);
|
||||
this.closingTime = this.openingTime + duration.weeks(1);
|
||||
this.afterClosingTime = this.closingTime + duration.seconds(1);
|
||||
|
||||
this.token = await SimpleToken.new();
|
||||
this.crowdsale = await RefundableCrowdsale.new(
|
||||
this.openingTime, this.closingTime, rate, wallet, this.token.address, goal, { from: owner }
|
||||
);
|
||||
await this.token.transfer(this.crowdsale.address, tokenSupply);
|
||||
});
|
||||
|
||||
describe('creating a valid crowdsale', function () {
|
||||
it('should fail with zero goal', async function () {
|
||||
await RefundableCrowdsale.new(
|
||||
this.openingTime, this.closingTime, rate, wallet, this.token.address, 0, { from: owner }
|
||||
).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
});
|
||||
|
||||
it('should deny refunds before end', async function () {
|
||||
await this.crowdsale.claimRefund({ from: investor }).should.be.rejectedWith(EVMRevert);
|
||||
await increaseTimeTo(this.openingTime);
|
||||
await this.crowdsale.claimRefund({ from: investor }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
|
||||
it('should deny refunds after end if goal was reached', async function () {
|
||||
await increaseTimeTo(this.openingTime);
|
||||
await this.crowdsale.sendTransaction({ value: goal, from: investor });
|
||||
await increaseTimeTo(this.afterClosingTime);
|
||||
await this.crowdsale.claimRefund({ from: investor }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
|
||||
it('should allow refunds after end if goal was not reached', async function () {
|
||||
await increaseTimeTo(this.openingTime);
|
||||
await this.crowdsale.sendTransaction({ value: lessThanGoal, from: investor });
|
||||
await increaseTimeTo(this.afterClosingTime);
|
||||
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 increaseTimeTo(this.openingTime);
|
||||
await this.crowdsale.sendTransaction({ value: goal, from: investor });
|
||||
await increaseTimeTo(this.afterClosingTime);
|
||||
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);
|
||||
});
|
||||
});
|
||||
@ -1,62 +0,0 @@
|
||||
import ether from '../helpers/ether';
|
||||
import { advanceBlock } from '../helpers/advanceToBlock';
|
||||
import { increaseTimeTo, duration } from '../helpers/increaseTime';
|
||||
import latestTime from '../helpers/latestTime';
|
||||
import EVMRevert from '../helpers/EVMRevert';
|
||||
|
||||
const BigNumber = web3.BigNumber;
|
||||
|
||||
require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
|
||||
const TimedCrowdsale = artifacts.require('TimedCrowdsaleImpl');
|
||||
const SimpleToken = artifacts.require('SimpleToken');
|
||||
|
||||
contract('TimedCrowdsale', function ([_, investor, wallet, purchaser]) {
|
||||
const rate = new BigNumber(1);
|
||||
const value = ether(42);
|
||||
const tokenSupply = new BigNumber('1e22');
|
||||
|
||||
before(async function () {
|
||||
// Advance to the next block to correctly read time in the solidity "now" function interpreted by ganache
|
||||
await advanceBlock();
|
||||
});
|
||||
|
||||
beforeEach(async function () {
|
||||
this.openingTime = latestTime() + duration.weeks(1);
|
||||
this.closingTime = this.openingTime + duration.weeks(1);
|
||||
this.afterClosingTime = this.closingTime + duration.seconds(1);
|
||||
this.token = await SimpleToken.new();
|
||||
this.crowdsale = await TimedCrowdsale.new(this.openingTime, this.closingTime, rate, wallet, this.token.address);
|
||||
await this.token.transfer(this.crowdsale.address, tokenSupply);
|
||||
});
|
||||
|
||||
it('should be ended only after end', async function () {
|
||||
let ended = await this.crowdsale.hasClosed();
|
||||
ended.should.equal(false);
|
||||
await increaseTimeTo(this.afterClosingTime);
|
||||
ended = await this.crowdsale.hasClosed();
|
||||
ended.should.equal(true);
|
||||
});
|
||||
|
||||
describe('accepting payments', function () {
|
||||
it('should reject payments before start', async function () {
|
||||
await this.crowdsale.send(value).should.be.rejectedWith(EVMRevert);
|
||||
await this.crowdsale.buyTokens(investor, { from: purchaser, value: value }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
|
||||
it('should accept payments after start', async function () {
|
||||
await increaseTimeTo(this.openingTime);
|
||||
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 increaseTimeTo(this.afterClosingTime);
|
||||
await this.crowdsale.send(value).should.be.rejectedWith(EVMRevert);
|
||||
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
});
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user