ETH Price: $3,065.52 (-2.87%)

Contract

0x8B8E088c7aD40D70d0A8183a399c8f9c24b5c8d8
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

More Info

Private Name Tags

TokenTracker

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Transfer232111602025-08-24 13:10:2384 days ago1756041023IN
Chellecoin.com: CHL Token
0 ETH0.000012110.22199415
Approve231862692025-08-21 1:47:2387 days ago1755740843IN
Chellecoin.com: CHL Token
0 ETH0.000012070.26
Approve231733702025-08-19 6:37:1189 days ago1755585431IN
Chellecoin.com: CHL Token
0 ETH0.000015320.63421511
Transfer220810192025-03-19 12:49:11242 days ago1742388551IN
Chellecoin.com: CHL Token
0 ETH0.000066751.22349378
Approve217045692025-01-25 22:40:35294 days ago1737844835IN
Chellecoin.com: CHL Token
0 ETH0.000213924.61337436
Transfer204530482024-08-04 5:18:35469 days ago1722748715IN
Chellecoin.com: CHL Token
0 ETH0.000054571
Approve198423122024-05-10 21:25:59555 days ago1715376359IN
Chellecoin.com: CHL Token
0 ETH0.000145426.02245386
Approve197825432024-05-02 12:49:35563 days ago1714654175IN
Chellecoin.com: CHL Token
0 ETH0.0007427316.01299204
Transfer197771832024-05-01 18:50:23564 days ago1714589423IN
Chellecoin.com: CHL Token
0 ETH0.0008372915.33682479
Approve188479862023-12-23 10:42:11694 days ago1703328131IN
Chellecoin.com: CHL Token
0 ETH0.000898119.36270551
Approve180494412023-09-02 14:30:59806 days ago1693665059IN
Chellecoin.com: CHL Token
0 ETH0.00066614.3589073
Approve178986842023-08-12 12:09:23827 days ago1691842163IN
Chellecoin.com: CHL Token
0 ETH0.0005752312.38593229
Transfer178038442023-07-30 5:43:59840 days ago1690695839IN
Chellecoin.com: CHL Token
0 ETH0.0007892813.79629284
Approve177804042023-07-26 23:02:23843 days ago1690412543IN
Chellecoin.com: CHL Token
0 ETH0.0014199530.5740599
Transfer177789562023-07-26 18:10:23844 days ago1690395023IN
Chellecoin.com: CHL Token
0 ETH0.0011670431.13615181
Approve169602252023-04-02 8:28:47959 days ago1680424127IN
Chellecoin.com: CHL Token
0 ETH0.00082917.97542486
Approve165766022023-02-07 11:27:231013 days ago1675769243IN
Chellecoin.com: CHL Token
0 ETH0.001174125.31328625
Transfer165765742023-02-07 11:21:471013 days ago1675768907IN
Chellecoin.com: CHL Token
0 ETH0.0015008727.48552424
Approve164621092023-01-22 11:41:471029 days ago1674387707IN
Chellecoin.com: CHL Token
0 ETH0.0006856614.78267281
Transfer164171892023-01-16 5:12:591035 days ago1673845979IN
Chellecoin.com: CHL Token
0 ETH0.0008183715
Approve163830672023-01-11 10:46:591040 days ago1673434019IN
Chellecoin.com: CHL Token
0 ETH0.0008006917.24030171
Approve163639202023-01-08 18:40:231043 days ago1673203223IN
Chellecoin.com: CHL Token
0 ETH0.0010591822.80609859
Approve161832912022-12-14 13:40:351068 days ago1671025235IN
Chellecoin.com: CHL Token
0 ETH0.0006739414.51120174
Approve161824002022-12-14 10:41:111068 days ago1671014471IN
Chellecoin.com: CHL Token
0 ETH0.0006462213.91443168
Approve161421532022-12-08 19:43:111074 days ago1670528591IN
Chellecoin.com: CHL Token
0 ETH0.00087618.86201451
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CHLToken

Compiler Version
v0.4.24+commit.e67f0147

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
/**
 *Submitted for verification at Etherscan.io on 2019-02-14
*/

/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {

  /**
  * @dev Multiplies two numbers, throws on overflow.
  */
  function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
    // Gas optimization: this is cheaper than asserting 'a' not being zero, but the
    // benefit is lost if 'b' is also tested.
    // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
    if (a == 0) {
      return 0;
    }

    c = a * b;
    assert(c / a == b);
    return c;
  }

  /**
  * @dev Integer division of two numbers, truncating the quotient.
  */
  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    // uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return a / b;
  }

  /**
  * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
  */
  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b <= a);
    return a - b;
  }

  /**
  * @dev Adds two numbers, throws on overflow.
  */
  function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
    c = a + b;
    assert(c >= a);
    return c;
  }
}
/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure.
 * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
  function safeTransfer(ERC20Basic token, address to, uint256 value) internal {
    require(token.transfer(to, value));
  }

  function safeTransferFrom(
    ERC20 token,
    address from,
    address to,
    uint256 value
  )
    internal
  {
    require(token.transferFrom(from, to, value));
  }

  function safeApprove(ERC20 token, address spender, uint256 value) internal {
    require(token.approve(spender, value));
  }
}
/**
 * @title ERC20Basic
 * @dev Simpler version of ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/179
 */
contract ERC20Basic {
  function totalSupply() public view returns (uint256);
  function balanceOf(address who) public view returns (uint256);
  function transfer(address to, uint256 value) public returns (bool);
  event Transfer(address indexed from, address indexed to, uint256 value);
}
/**
 * @title Basic token
 * @dev Basic version of StandardToken, with no allowances.
 */
contract BasicToken is ERC20Basic {
  using SafeMath for uint256;

  mapping(address => uint256) balances;

  uint256 totalSupply_;

  /**
  * @dev total number of tokens in existence
  */
  function totalSupply() public view returns (uint256) {
    return totalSupply_;
  }

  /**
  * @dev transfer token for a specified address
  * @param _to The address to transfer to.
  * @param _value The amount to be transferred.
  */
  function transfer(address _to, uint256 _value) public returns (bool) {
    require(_to != address(0));
    require(_value <= balances[msg.sender]);

    balances[msg.sender] = balances[msg.sender].sub(_value);
    balances[_to] = balances[_to].add(_value);
    emit Transfer(msg.sender, _to, _value);
    return true;
  }

  /**
  * @dev Gets the balance of the specified address.
  * @param _owner The address to query the the balance of.
  * @return An uint256 representing the amount owned by the passed address.
  */
  function balanceOf(address _owner) public view returns (uint256) {
    return balances[_owner];
  }

}
/**
 * @title ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/20
 */
contract ERC20 is ERC20Basic {
  function allowance(address owner, address spender)
    public view returns (uint256);

  function transferFrom(address from, address to, uint256 value)
    public returns (bool);

  function approve(address spender, uint256 value) public returns (bool);
  event Approval(
    address indexed owner,
    address indexed spender,
    uint256 value
  );
}
/**
 * @title Standard ERC20 token
 *
 * @dev Implementation of the basic standard token.
 * @dev https://github.com/ethereum/EIPs/issues/20
 * @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
 */
contract StandardToken is ERC20, BasicToken {

  mapping (address => mapping (address => uint256)) internal allowed;


  /**
   * @dev Transfer tokens from one address to another
   * @param _from address The address which you want to send tokens from
   * @param _to address The address which you want to transfer to
   * @param _value uint256 the amount of tokens to be transferred
   */
  function transferFrom(
    address _from,
    address _to,
    uint256 _value
  )
    public
    returns (bool)
  {
    require(_to != address(0));
    require(_value <= balances[_from]);
    require(_value <= allowed[_from][msg.sender]);

    balances[_from] = balances[_from].sub(_value);
    balances[_to] = balances[_to].add(_value);
    allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
    emit Transfer(_from, _to, _value);
    return true;
  }

  /**
   * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
   *
   * Beware that changing an allowance with this method brings the risk that someone may use both the old
   * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
   * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
   * @param _spender The address which will spend the funds.
   * @param _value The amount of tokens to be spent.
   */
  function approve(address _spender, uint256 _value) public returns (bool) {
    allowed[msg.sender][_spender] = _value;
    emit Approval(msg.sender, _spender, _value);
    return true;
  }

  /**
   * @dev Function to check the amount of tokens that an owner allowed to a spender.
   * @param _owner address The address which owns the funds.
   * @param _spender address The address which will spend the funds.
   * @return A uint256 specifying the amount of tokens still available for the spender.
   */
  function allowance(
    address _owner,
    address _spender
   )
    public
    view
    returns (uint256)
  {
    return allowed[_owner][_spender];
  }

  /**
   * @dev Increase the amount of tokens that an owner allowed to a spender.
   *
   * approve should be called when allowed[_spender] == 0. To increment
   * allowed value is better to use this function to avoid 2 calls (and wait until
   * the first transaction is mined)
   * From MonolithDAO Token.sol
   * @param _spender The address which will spend the funds.
   * @param _addedValue The amount of tokens to increase the allowance by.
   */
  function increaseApproval(
    address _spender,
    uint _addedValue
  )
    public
    returns (bool)
  {
    allowed[msg.sender][_spender] = (
      allowed[msg.sender][_spender].add(_addedValue));
    emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
    return true;
  }

  /**
   * @dev Decrease the amount of tokens that an owner allowed to a spender.
   *
   * approve should be called when allowed[_spender] == 0. To decrement
   * allowed value is better to use this function to avoid 2 calls (and wait until
   * the first transaction is mined)
   * From MonolithDAO Token.sol
   * @param _spender The address which will spend the funds.
   * @param _subtractedValue The amount of tokens to decrease the allowance by.
   */
  function decreaseApproval(
    address _spender,
    uint _subtractedValue
  )
    public
    returns (bool)
  {
    uint oldValue = allowed[msg.sender][_spender];
    if (_subtractedValue > oldValue) {
      allowed[msg.sender][_spender] = 0;
    } else {
      allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
    }
    emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
    return true;
  }

}
/// @title Ownable
/// @author Applicature
/// @notice helper mixed to other contracts to link contract on an owner
/// @dev Base class
contract Ownable {
    //Variables
    address public owner;
    address public newOwner;

    //    Modifiers
    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

    /**
     * @dev The Ownable constructor sets the original `owner` of the contract to the sender
     * account.
     */
    constructor() public {
        owner = msg.sender;
    }

    /**
     * @dev Allows the current owner to transfer control of the contract to a newOwner.
     * @param _newOwner The address to transfer ownership to.
     */
    function transferOwnership(address _newOwner) public onlyOwner {
        require(_newOwner != address(0));
        newOwner = _newOwner;

    }

    function acceptOwnership() public {
        if (msg.sender == newOwner) {
            owner = newOwner;
        }
    }
}
/// @title OpenZeppelinERC20
/// @author Applicature
/// @notice Open Zeppelin implementation of standart ERC20
/// @dev Base class
contract OpenZeppelinERC20 is StandardToken, Ownable {
    using SafeMath for uint256;

    uint8 public decimals;
    string public name;
    string public symbol;
    string public standard;

    constructor(
        uint256 _totalSupply,
        string _tokenName,
        uint8 _decimals,
        string _tokenSymbol,
        bool _transferAllSupplyToOwner
    ) public {
        standard = 'ERC20 0.1';
        totalSupply_ = _totalSupply;

        if (_transferAllSupplyToOwner) {
            balances[msg.sender] = _totalSupply;
        } else {
            balances[this] = _totalSupply;
        }

        name = _tokenName;
        // Set the name for display purposes
        symbol = _tokenSymbol;
        // Set the symbol for display purposes
        decimals = _decimals;
    }

}
/**
 * @title Burnable Token
 * @dev Token that can be irreversibly burned (destroyed).
 */
contract BurnableToken is BasicToken {

  event Burn(address indexed burner, uint256 value);

  /**
   * @dev Burns a specific amount of tokens.
   * @param _value The amount of token to be burned.
   */
  function burn(uint256 _value) public {
    _burn(msg.sender, _value);
  }

  function _burn(address _who, uint256 _value) internal {
    require(_value <= balances[_who]);
    // no need to require value <= totalSupply, since that would imply the
    // sender's balance is greater than the totalSupply, which *should* be an assertion failure

    balances[_who] = balances[_who].sub(_value);
    totalSupply_ = totalSupply_.sub(_value);
    emit Burn(_who, _value);
    emit Transfer(_who, address(0), _value);
  }
}
/// @title MintableToken
/// @author Applicature
/// @notice allow to mint tokens
/// @dev Base class
contract MintableToken is BasicToken, Ownable {

    using SafeMath for uint256;

    uint256 public maxSupply;
    bool public allowedMinting;
    mapping(address => bool) public mintingAgents;
    mapping(address => bool) public stateChangeAgents;

    event Mint(address indexed holder, uint256 tokens);

    modifier onlyMintingAgents () {
        require(mintingAgents[msg.sender]);
        _;
    }

    modifier onlyStateChangeAgents () {
        require(stateChangeAgents[msg.sender]);
        _;
    }

    constructor(uint256 _maxSupply, uint256 _mintedSupply, bool _allowedMinting) public {
        maxSupply = _maxSupply;
        totalSupply_ = totalSupply_.add(_mintedSupply);
        allowedMinting = _allowedMinting;
        mintingAgents[msg.sender] = true;
    }

    /// @notice allow to mint tokens
    function mint(address _holder, uint256 _tokens) public onlyMintingAgents() {
        require(allowedMinting == true && totalSupply_.add(_tokens) <= maxSupply);

        totalSupply_ = totalSupply_.add(_tokens);

        balances[_holder] = balanceOf(_holder).add(_tokens);

        if (totalSupply_ == maxSupply) {
            allowedMinting = false;
        }
        emit Transfer(address(0), _holder, _tokens);
        emit Mint(_holder, _tokens);
    }

    /// @notice update allowedMinting flat
    function disableMinting() public onlyStateChangeAgents() {
        allowedMinting = false;
    }

    /// @notice update minting agent
    function updateMintingAgent(address _agent, bool _status) public onlyOwner {
        mintingAgents[_agent] = _status;
    }

    /// @notice update state change agent
    function updateStateChangeAgent(address _agent, bool _status) public onlyOwner {
        stateChangeAgents[_agent] = _status;
    }

    /// @return available tokens
    function availableTokens() public view returns (uint256 tokens) {
        return maxSupply.sub(totalSupply_);
    }
}
/// @title MintableBurnableToken
/// @author Applicature
/// @notice helper mixed to other contracts to burn tokens
/// @dev implementation
contract MintableBurnableToken is MintableToken, BurnableToken {

    mapping (address => bool) public burnAgents;

    modifier onlyBurnAgents () {
        require(burnAgents[msg.sender]);
        _;
    }

    event Burn(address indexed burner, uint256 value);

    constructor(
        uint256 _maxSupply,
        uint256 _mintedSupply,
        bool _allowedMinting
    ) public MintableToken(
        _maxSupply,
        _mintedSupply,
        _allowedMinting
    ) {

    }

    /// @notice update minting agent
    function updateBurnAgent(address _agent, bool _status) public onlyOwner {
        burnAgents[_agent] = _status;
    }

    function burnByAgent(address _holder, uint256 _tokensToBurn) public onlyBurnAgents() returns (uint256) {
        if (_tokensToBurn == 0) {
            _tokensToBurn = balanceOf(_holder);
        }
        _burn(_holder, _tokensToBurn);

        return _tokensToBurn;
    }

    function _burn(address _who, uint256 _value) internal {
        require(_value <= balances[_who]);
        // no need to require value <= totalSupply, since that would imply the
        // sender's balance is greater than the totalSupply, which *should* be an assertion failure

        balances[_who] = balances[_who].sub(_value);
        totalSupply_ = totalSupply_.sub(_value);
        maxSupply = maxSupply.sub(_value);
        emit Burn(_who, _value);
        emit Transfer(_who, address(0), _value);
    }
}
/// @title TimeLocked
/// @author Applicature
/// @notice helper mixed to other contracts to lock contract on a timestamp
/// @dev Base class
contract TimeLocked {
    uint256 public time;
    mapping(address => bool) public excludedAddresses;

    modifier isTimeLocked(address _holder, bool _timeLocked) {
        bool locked = (block.timestamp < time);
        require(excludedAddresses[_holder] == true || locked == _timeLocked);
        _;
    }

    constructor(uint256 _time) public {
        time = _time;
    }

    function updateExcludedAddress(address _address, bool _status) public;
}
/// @title TimeLockedToken
/// @author Applicature
/// @notice helper mixed to other contracts to lock contract on a timestamp
/// @dev Base class
contract TimeLockedToken is TimeLocked, StandardToken {

    constructor(uint256 _time) public TimeLocked(_time) {}

    function transfer(address _to, uint256 _tokens) public isTimeLocked(msg.sender, false) returns (bool) {
        return super.transfer(_to, _tokens);
    }

    function transferFrom(
        address _holder,
        address _to,
        uint256 _tokens
    ) public isTimeLocked(_holder, false) returns (bool) {
        return super.transferFrom(_holder, _to, _tokens);
    }
}
contract CHLToken is OpenZeppelinERC20, MintableBurnableToken, TimeLockedToken {

    CHLCrowdsale public crowdsale;

    bool public isSoftCapAchieved;

    //_unlockTokensTime - Lockup 3 months after end of the ICO
    constructor(uint256 _unlockTokensTime) public
    OpenZeppelinERC20(0, 'ChelleCoin', 18, 'CHL', false)
    MintableBurnableToken(59500000e18, 0, true)
    TimeLockedToken(_unlockTokensTime) {

    }

    function updateMaxSupply(uint256 _newMaxSupply) public onlyOwner {
        require(_newMaxSupply > 0);
        maxSupply = _newMaxSupply;
    }

    function updateExcludedAddress(address _address, bool _status) public onlyOwner {
        excludedAddresses[_address] = _status;
    }

    function setCrowdSale(address _crowdsale) public onlyOwner {
        require(_crowdsale != address(0));
        crowdsale = CHLCrowdsale(_crowdsale);
    }

    function setUnlockTime(uint256 _unlockTokensTime) public onlyStateChangeAgents {
        time = _unlockTokensTime;
    }

    function setIsSoftCapAchieved() public onlyStateChangeAgents {
        isSoftCapAchieved = true;
    }

    function transfer(address _to, uint256 _tokens) public returns (bool) {
        require(true == isTransferAllowed(msg.sender, _tokens));
        return super.transfer(_to, _tokens);
    }

    function transferFrom(address _holder, address _to, uint256 _tokens) public returns (bool) {
        require(true == isTransferAllowed(_holder, _tokens));
        return super.transferFrom(_holder, _to, _tokens);
    }

    function isTransferAllowed(address _address, uint256 _value) public view returns (bool) {
        if (excludedAddresses[_address] == true) {
            return true;
        }

        if (!isSoftCapAchieved && (address(crowdsale) == address(0) || false == crowdsale.isSoftCapAchieved(0))) {
            return false;
        }

        return true;
    }

    function burnUnsoldTokens(uint256 _tokensToBurn) public onlyBurnAgents() returns (uint256) {
        require(totalSupply_.add(_tokensToBurn) <= maxSupply);

        maxSupply = maxSupply.sub(_tokensToBurn);

        emit Burn(address(0), _tokensToBurn);

        return _tokensToBurn;
    }

}
/// @title Agent
/// @author Applicature
/// @notice Contract which takes actions on state change and contribution
/// @dev Base class
contract Agent {
    using SafeMath for uint256;

    function isInitialized() public constant returns (bool) {
        return false;
    }
}
/// @title CrowdsaleAgent
/// @author Applicature
/// @notice Contract which takes actions on state change and contribution
/// @dev Base class
contract CrowdsaleAgent is Agent {


    Crowdsale public crowdsale;
    bool public _isInitialized;

    modifier onlyCrowdsale() {
        require(msg.sender == address(crowdsale));
        _;
    }

    constructor(Crowdsale _crowdsale) public {
        crowdsale = _crowdsale;

        if (address(0) != address(_crowdsale)) {
            _isInitialized = true;
        } else {
            _isInitialized = false;
        }
    }

    function isInitialized() public constant returns (bool) {
        return _isInitialized;
    }

    function onContribution(address _contributor, uint256 _weiAmount, uint256 _tokens, uint256 _bonus)
        public onlyCrowdsale();

    function onStateChange(Crowdsale.State _state) public onlyCrowdsale();

    function onRefund(address _contributor, uint256 _tokens) public onlyCrowdsale() returns (uint256 burned);
}
/// @title MintableCrowdsaleOnSuccessAgent
/// @author Applicature
/// @notice Contract which takes actions on state change and contribution
/// un-pause tokens and disable minting on Crowdsale success
/// @dev implementation
contract MintableCrowdsaleOnSuccessAgent is CrowdsaleAgent {

    Crowdsale public crowdsale;
    MintableToken public token;
    bool public _isInitialized;

    constructor(Crowdsale _crowdsale, MintableToken _token) public CrowdsaleAgent(_crowdsale) {
        crowdsale = _crowdsale;
        token = _token;

        if (address(0) != address(_token) &&
        address(0) != address(_crowdsale)) {
            _isInitialized = true;
        } else {
            _isInitialized = false;
        }
    }

    /// @notice Check whether contract is initialised
    /// @return true if initialized
    function isInitialized() public constant returns (bool) {
        return _isInitialized;
    }

    /// @notice Takes actions on contribution
    function onContribution(address _contributor, uint256 _weiAmount, uint256 _tokens, uint256 _bonus)
    public onlyCrowdsale() {
        _contributor = _contributor;
        _weiAmount = _weiAmount;
        _tokens = _tokens;
        _bonus = _bonus;
        // TODO: add impl
    }

    /// @notice Takes actions on state change,
    /// un-pause tokens and disable minting on Crowdsale success
    /// @param _state Crowdsale.State
    function onStateChange(Crowdsale.State _state) public onlyCrowdsale() {
        if (_state == Crowdsale.State.Success) {
            token.disableMinting();
        }
    }

    function onRefund(address _contributor, uint256 _tokens) public onlyCrowdsale() returns (uint256 burned) {
        _contributor = _contributor;
        _tokens = _tokens;
    }
}
contract CHLAgent is MintableCrowdsaleOnSuccessAgent, Ownable {

    CHLPricingStrategy public strategy;
    CHLCrowdsale public crowdsale;
    CHLAllocation public allocation;

    bool public isEndProcessed;

    constructor(
        CHLCrowdsale _crowdsale,
        CHLToken _token,
        CHLPricingStrategy _strategy,
        CHLAllocation _allocation
    ) public MintableCrowdsaleOnSuccessAgent(_crowdsale, _token) {
        strategy = _strategy;
        crowdsale = _crowdsale;
        allocation = _allocation;
    }

    /// @notice update pricing strategy
    function setPricingStrategy(CHLPricingStrategy _strategy) public onlyOwner {
        strategy = _strategy;
    }

    /// @notice update allocation
    function setAllocation(CHLAllocation _allocation) public onlyOwner {
        allocation = _allocation;
    }

    function burnUnsoldTokens(uint256 _tierId) public onlyOwner {
        uint256 tierUnsoldTokensAmount = strategy.getTierUnsoldTokens(_tierId);
        require(tierUnsoldTokensAmount > 0);

        CHLToken(token).burnUnsoldTokens(tierUnsoldTokensAmount);
    }

    /// @notice Takes actions on contribution
    function onContribution(
        address,
        uint256 _tierId,
        uint256 _tokens,
        uint256 _bonus
    ) public onlyCrowdsale() {
        strategy.updateTierTokens(_tierId, _tokens, _bonus);
    }

    function onStateChange(Crowdsale.State _state) public onlyCrowdsale() {
        CHLToken chlToken = CHLToken(token);
        if (
            chlToken.isSoftCapAchieved() == false
            && (_state == Crowdsale.State.Success || _state == Crowdsale.State.Finalized)
            && crowdsale.isSoftCapAchieved(0)
        ) {
            chlToken.setIsSoftCapAchieved();
        }

        if (_state > Crowdsale.State.InCrowdsale && isEndProcessed == false) {
            allocation.allocateFoundersTokens(strategy.getSaleEndDate());
        }
    }

    function onRefund(address _contributor, uint256 _tokens) public onlyCrowdsale() returns (uint256 burned) {
        burned = CHLToken(token).burnByAgent(_contributor, _tokens);
    }

    function updateStateWithPrivateSale(
        uint256 _tierId,
        uint256 _tokensAmount,
        uint256 _usdAmount
    ) public {
        require(msg.sender == address(allocation));

        strategy.updateMaxTokensCollected(_tierId, _tokensAmount);
        crowdsale.updateStatsVars(_usdAmount, _tokensAmount);
    }

    function updateLockPeriod(uint256 _time) public {
        require(msg.sender == address(strategy));
        CHLToken(token).setUnlockTime(_time.add(12 weeks));
    }

}
/// @title TokenAllocator
/// @author Applicature
/// @notice Contract responsible for defining distribution logic of tokens.
/// @dev Base class
contract TokenAllocator is Ownable {


    mapping(address => bool) public crowdsales;

    modifier onlyCrowdsale() {
        require(crowdsales[msg.sender]);
        _;
    }

    function addCrowdsales(address _address) public onlyOwner {
        crowdsales[_address] = true;
    }

    function removeCrowdsales(address _address) public onlyOwner {
        crowdsales[_address] = false;
    }

    function isInitialized() public constant returns (bool) {
        return false;
    }

    function allocate(address _holder, uint256 _tokens) public onlyCrowdsale() {
        internalAllocate(_holder, _tokens);
    }

    function tokensAvailable() public constant returns (uint256);

    function internalAllocate(address _holder, uint256 _tokens) internal onlyCrowdsale();
}
/// @title MintableTokenAllocator
/// @author Applicature
/// @notice Contract responsible for defining distribution logic of tokens.
/// @dev implementation
contract MintableTokenAllocator is TokenAllocator {

    using SafeMath for uint256;

    MintableToken public token;

    constructor(MintableToken _token) public {
        require(address(0) != address(_token));
        token = _token;
    }

    /// @return available tokens
    function tokensAvailable() public constant returns (uint256) {
        return token.availableTokens();
    }

    /// @notice transfer tokens on holder account
    function allocate(address _holder, uint256 _tokens) public onlyCrowdsale() {
        internalAllocate(_holder, _tokens);
    }

    /// @notice Check whether contract is initialised
    /// @return true if initialized
    function isInitialized() public constant returns (bool) {
        return token.mintingAgents(this);
    }

    /// @notice update instance of MintableToken
    function setToken(MintableToken _token) public onlyOwner {
        token = _token;
    }

    function internalAllocate(address _holder, uint256 _tokens) internal {
        token.mint(_holder, _tokens);
    }

}
/// @title ContributionForwarder
/// @author Applicature
/// @notice Contract is responsible for distributing collected ethers, that are received from CrowdSale.
/// @dev Base class
contract ContributionForwarder {

    using SafeMath for uint256;

    uint256 public weiCollected;
    uint256 public weiForwarded;

    event ContributionForwarded(address receiver, uint256 weiAmount);

    function isInitialized() public constant returns (bool) {
        return false;
    }

    /// @notice transfer wei to receiver
    function forward() public payable {
        require(msg.value > 0);

        weiCollected += msg.value;

        internalForward();
    }

    function internalForward() internal;
}
/// @title DistributedDirectContributionForwarder
/// @author Applicature
/// @notice Contract is responsible for distributing collected ethers, that are received from CrowdSale.
/// @dev implementation
contract DistributedDirectContributionForwarder is ContributionForwarder {
    Receiver[] public receivers;
    uint256 public proportionAbsMax;
    bool public isInitialized_;

    struct Receiver {
        address receiver;
        uint256 proportion; // abslolute value in range of 0 - proportionAbsMax
        uint256 forwardedWei;
    }

    // @TODO: should we use uint256 [] for receivers & proportions?
    constructor(uint256 _proportionAbsMax, address[] _receivers, uint256[] _proportions) public {
        proportionAbsMax = _proportionAbsMax;

        require(_receivers.length == _proportions.length);

        require(_receivers.length > 0);

        uint256 totalProportion;

        for (uint256 i = 0; i < _receivers.length; i++) {
            uint256 proportion = _proportions[i];

            totalProportion = totalProportion.add(proportion);

            receivers.push(Receiver(_receivers[i], proportion, 0));
        }

        require(totalProportion == proportionAbsMax);
        isInitialized_ = true;
    }

    /// @notice Check whether contract is initialised
    /// @return true if initialized
    function isInitialized() public constant returns (bool) {
        return isInitialized_;
    }

    function internalForward() internal {
        uint256 transferred;

        for (uint256 i = 0; i < receivers.length; i++) {
            Receiver storage receiver = receivers[i];

            uint256 value = msg.value.mul(receiver.proportion).div(proportionAbsMax);

            if (i == receivers.length - 1) {
                value = msg.value.sub(transferred);
            }

            transferred = transferred.add(value);

            receiver.receiver.transfer(value);

            emit ContributionForwarded(receiver.receiver, value);
        }

        weiForwarded = weiForwarded.add(transferred);
    }
}
contract Crowdsale {

    uint256 public tokensSold;

    enum State {Unknown, Initializing, BeforeCrowdsale, InCrowdsale, Success, Finalized, Refunding}

    function externalContribution(address _contributor, uint256 _wei) public payable;

    function contribute(uint8 _v, bytes32 _r, bytes32 _s) public payable;

    function updateState() public;

    function internalContribution(address _contributor, uint256 _wei) internal;

    function getState() public view returns (State);

}
/// @title Crowdsale
/// @author Applicature
/// @notice Contract is responsible for collecting, refunding, allocating tokens during different stages of Crowdsale.
contract CrowdsaleImpl is Crowdsale, Ownable {

    using SafeMath for uint256;

    State public currentState;
    TokenAllocator public allocator;
    ContributionForwarder public contributionForwarder;
    PricingStrategy public pricingStrategy;
    CrowdsaleAgent public crowdsaleAgent;
    bool public finalized;
    uint256 public startDate;
    uint256 public endDate;
    bool public allowWhitelisted;
    bool public allowSigned;
    bool public allowAnonymous;
    mapping(address => bool) public whitelisted;
    mapping(address => bool) public signers;
    mapping(address => bool) public externalContributionAgents;

    event Contribution(address _contributor, uint256 _wei, uint256 _tokensExcludingBonus, uint256 _bonus);

    constructor(
        TokenAllocator _allocator,
        ContributionForwarder _contributionForwarder,
        PricingStrategy _pricingStrategy,
        uint256 _startDate,
        uint256 _endDate,
        bool _allowWhitelisted,
        bool _allowSigned,
        bool _allowAnonymous
    ) public {
        allocator = _allocator;
        contributionForwarder = _contributionForwarder;
        pricingStrategy = _pricingStrategy;

        startDate = _startDate;
        endDate = _endDate;

        allowWhitelisted = _allowWhitelisted;
        allowSigned = _allowSigned;
        allowAnonymous = _allowAnonymous;

        currentState = State.Unknown;
    }

    /// @notice default payable function
    function() public payable {
        require(allowWhitelisted || allowAnonymous);

        if (!allowAnonymous) {
            if (allowWhitelisted) {
                require(whitelisted[msg.sender]);
            }
        }

        internalContribution(msg.sender, msg.value);
    }

    /// @notice update crowdsale agent
    function setCrowdsaleAgent(CrowdsaleAgent _crowdsaleAgent) public onlyOwner {
        crowdsaleAgent = _crowdsaleAgent;
    }

    /// @notice allows external user to do contribution
    function externalContribution(address _contributor, uint256 _wei) public payable {
        require(externalContributionAgents[msg.sender]);
        internalContribution(_contributor, _wei);
    }

    /// @notice update external contributor
    function addExternalContributor(address _contributor) public onlyOwner {
        externalContributionAgents[_contributor] = true;
    }

    /// @notice update external contributor
    function removeExternalContributor(address _contributor) public onlyOwner {
        externalContributionAgents[_contributor] = false;
    }

    /// @notice update whitelisting address
    function updateWhitelist(address _address, bool _status) public onlyOwner {
        whitelisted[_address] = _status;
    }

    /// @notice update signer
    function addSigner(address _signer) public onlyOwner {
        signers[_signer] = true;
    }

    /// @notice update signer
    function removeSigner(address _signer) public onlyOwner {
        signers[_signer] = false;
    }

    /// @notice allows to do signed contributions
    function contribute(uint8 _v, bytes32 _r, bytes32 _s) public payable {
        address recoveredAddress = verify(msg.sender, _v, _r, _s);
        require(signers[recoveredAddress]);
        internalContribution(msg.sender, msg.value);
    }

    /// @notice Crowdsale state
    function updateState() public {
        State state = getState();

        if (currentState != state) {
            if (crowdsaleAgent != address(0)) {
                crowdsaleAgent.onStateChange(state);
            }

            currentState = state;
        }
    }

    function internalContribution(address _contributor, uint256 _wei) internal {
        require(getState() == State.InCrowdsale);

        uint256 tokensAvailable = allocator.tokensAvailable();
        uint256 collectedWei = contributionForwarder.weiCollected();

        uint256 tokens;
        uint256 tokensExcludingBonus;
        uint256 bonus;

        (tokens, tokensExcludingBonus, bonus) = pricingStrategy.getTokens(
            _contributor, tokensAvailable, tokensSold, _wei, collectedWei);

        require(tokens > 0 && tokens <= tokensAvailable);
        tokensSold = tokensSold.add(tokens);

        allocator.allocate(_contributor, tokens);

        if (msg.value > 0) {
            contributionForwarder.forward.value(msg.value)();
        }

        emit Contribution(_contributor, _wei, tokensExcludingBonus, bonus);
    }

    /// @notice check sign
    function verify(address _sender, uint8 _v, bytes32 _r, bytes32 _s) public view returns (address) {
        bytes32 hash = keccak256(abi.encodePacked(this, _sender));

        bytes memory prefix = '\x19Ethereum Signed Message:\n32';

        return ecrecover(keccak256(abi.encodePacked(prefix, hash)), _v, _r, _s);
    }

    /// @return Crowdsale state
    function getState() public view returns (State) {
        if (finalized) {
            return State.Finalized;
        } else if (allocator.isInitialized() == false) {
            return State.Initializing;
        } else if (contributionForwarder.isInitialized() == false) {
            return State.Initializing;
        } else if (pricingStrategy.isInitialized() == false) {
            return State.Initializing;
        } else if (block.timestamp < startDate) {
            return State.BeforeCrowdsale;
        } else if (block.timestamp >= startDate && block.timestamp <= endDate) {
            return State.InCrowdsale;
        } else if (block.timestamp > endDate) {
            return State.Success;
        }

        return State.Unknown;
    }
}
/// @title HardCappedCrowdsale
/// @author Applicature
/// @notice Contract is responsible for collecting, refunding, allocating tokens during different stages of Crowdsale.
/// with hard limit
contract HardCappedCrowdsale is CrowdsaleImpl {

    using SafeMath for uint256;

    uint256 public hardCap;

    constructor(
        TokenAllocator _allocator,
        ContributionForwarder _contributionForwarder,
        PricingStrategy _pricingStrategy,
        uint256 _startDate,
        uint256 _endDate,
        bool _allowWhitelisted,
        bool _allowSigned,
        bool _allowAnonymous,
        uint256 _hardCap
    ) public CrowdsaleImpl(
        _allocator,
        _contributionForwarder,
        _pricingStrategy,
        _startDate,
        _endDate,
        _allowWhitelisted,
        _allowSigned,
        _allowAnonymous
    ) {
        hardCap = _hardCap;
    }

    /// @return Crowdsale state
    function getState() public view returns (State) {
        State state = super.getState();

        if (state == State.InCrowdsale) {
            if (isHardCapAchieved(0)) {
                return State.Success;
            }
        }

        return state;
    }

    function isHardCapAchieved(uint256 _value) public view returns (bool) {
        if (hardCap <= tokensSold.add(_value)) {
            return true;
        }
        return false;
    }

    function internalContribution(address _contributor, uint256 _wei) internal {
        require(getState() == State.InCrowdsale);

        uint256 tokensAvailable = allocator.tokensAvailable();
        uint256 collectedWei = contributionForwarder.weiCollected();

        uint256 tokens;
        uint256 tokensExcludingBonus;
        uint256 bonus;

        (tokens, tokensExcludingBonus, bonus) = pricingStrategy.getTokens(
            _contributor, tokensAvailable, tokensSold, _wei, collectedWei);

        require(tokens <= tokensAvailable && tokens > 0 && false == isHardCapAchieved(tokens.sub(1)));

        tokensSold = tokensSold.add(tokens);

        allocator.allocate(_contributor, tokens);

        if (msg.value > 0) {
            contributionForwarder.forward.value(msg.value)();
        }
        crowdsaleAgent.onContribution(_contributor, _wei, tokensExcludingBonus, bonus);
        emit Contribution(_contributor, _wei, tokensExcludingBonus, bonus);
    }
}
/// @title RefundableCrowdsale
/// @author Applicature
/// @notice Contract is responsible for collecting, refunding, allocating tokens during different stages of Crowdsale.
/// with hard and soft limits
contract RefundableCrowdsale is HardCappedCrowdsale {

    using SafeMath for uint256;

    uint256 public softCap;
    mapping(address => uint256) public contributorsWei;
    address[] public contributors;

    event Refund(address _holder, uint256 _wei, uint256 _tokens);

    constructor(
        TokenAllocator _allocator,
        ContributionForwarder _contributionForwarder,
        PricingStrategy _pricingStrategy,
        uint256 _startDate,
        uint256 _endDate,
        bool _allowWhitelisted,
        bool _allowSigned,
        bool _allowAnonymous,
        uint256 _softCap,
        uint256 _hardCap

    ) public HardCappedCrowdsale(
        _allocator, _contributionForwarder, _pricingStrategy,
        _startDate, _endDate,
        _allowWhitelisted, _allowSigned, _allowAnonymous, _hardCap
    ) {
        softCap = _softCap;
    }

    /// @notice refund ethers to contributor
    function refund() public {
        internalRefund(msg.sender);
    }

    /// @notice refund ethers to delegate
    function delegatedRefund(address _address) public {
        internalRefund(_address);
    }

    function internalContribution(address _contributor, uint256 _wei) internal {
        require(block.timestamp >= startDate && block.timestamp <= endDate);

        uint256 tokensAvailable = allocator.tokensAvailable();
        uint256 collectedWei = contributionForwarder.weiCollected();

        uint256 tokens;
        uint256 tokensExcludingBonus;
        uint256 bonus;

        (tokens, tokensExcludingBonus, bonus) = pricingStrategy.getTokens(
            _contributor, tokensAvailable, tokensSold, _wei, collectedWei);

        require(tokens <= tokensAvailable && tokens > 0 && hardCap > tokensSold.add(tokens));

        tokensSold = tokensSold.add(tokens);

        allocator.allocate(_contributor, tokens);

        // transfer only if softcap is reached
        if (isSoftCapAchieved(0)) {
            if (msg.value > 0) {
                contributionForwarder.forward.value(address(this).balance)();
            }
        } else {
            // store contributor if it is not stored before
            if (contributorsWei[_contributor] == 0) {
                contributors.push(_contributor);
            }
            contributorsWei[_contributor] = contributorsWei[_contributor].add(msg.value);
        }
        crowdsaleAgent.onContribution(_contributor, _wei, tokensExcludingBonus, bonus);
        emit Contribution(_contributor, _wei, tokensExcludingBonus, bonus);
    }

    function internalRefund(address _holder) internal {
        updateState();
        require(block.timestamp > endDate);
        require(!isSoftCapAchieved(0));
        require(crowdsaleAgent != address(0));

        uint256 value = contributorsWei[_holder];

        require(value > 0);

        contributorsWei[_holder] = 0;
        uint256 burnedTokens = crowdsaleAgent.onRefund(_holder, 0);

        _holder.transfer(value);

        emit Refund(_holder, value, burnedTokens);
    }

    /// @return Crowdsale state
    function getState() public view returns (State) {
        State state = super.getState();

        if (state == State.Success) {
            if (!isSoftCapAchieved(0)) {
                return State.Refunding;
            }
        }

        return state;
    }

    function isSoftCapAchieved(uint256 _value) public view returns (bool) {
        if (softCap <= tokensSold.add(_value)) {
            return true;
        }
        return false;
    }
}
contract CHLCrowdsale is RefundableCrowdsale {

    uint256 public maxSaleSupply = 38972500e18;

    uint256 public usdCollected;

    address public processingFeeAddress;
    uint256 public percentageAbsMax = 1000;
    uint256 public processingFeePercentage = 25;

    event ProcessingFeeAllocation(address _contributor, uint256 _feeAmount);

    event Contribution(address _contributor, uint256 _usdAmount, uint256 _tokensExcludingBonus, uint256 _bonus);

    constructor(
        MintableTokenAllocator _allocator,
        DistributedDirectContributionForwarder _contributionForwarder,
        CHLPricingStrategy _pricingStrategy,
        uint256 _startTime,
        uint256 _endTime,
        address _processingFeeAddress
    ) public RefundableCrowdsale(
        _allocator,
        _contributionForwarder,
        _pricingStrategy,
        _startTime,
        _endTime,
        true,
        true,
        false,
        10000000e5,//softCap
        102860625e5//hardCap
    ) {
        require(_processingFeeAddress != address(0));
        processingFeeAddress = _processingFeeAddress;
    }

    function() public payable {
        require(allowWhitelisted || allowAnonymous);

        if (!allowAnonymous) {
            if (allowWhitelisted) {
                require(whitelisted[msg.sender]);
            }
        }

        internalContribution(
            msg.sender,
            CHLPricingStrategy(pricingStrategy).getUSDAmountByWeis(msg.value)
        );
    }

    /// @notice allows to do signed contributions
    function contribute(uint8 _v, bytes32 _r, bytes32 _s) public payable {
        address recoveredAddress = verify(msg.sender, _v, _r, _s);
        require(signers[recoveredAddress]);
        internalContribution(
            msg.sender,
            CHLPricingStrategy(pricingStrategy).getUSDAmountByWeis(msg.value)
        );
    }

    /// @notice allows external user to do contribution
    function externalContribution(address _contributor, uint256 _usdAmount) public payable {
        require(externalContributionAgents[msg.sender]);
        internalContribution(_contributor, _usdAmount);
    }

    function updateState() public {
        (startDate, endDate) = CHLPricingStrategy(pricingStrategy).getActualDates();
        super.updateState();
    }

    function isHardCapAchieved(uint256 _value) public view returns (bool) {
        if (hardCap <= usdCollected.add(_value)) {
            return true;
        }
        return false;
    }

    function isSoftCapAchieved(uint256 _value) public view returns (bool) {
        if (softCap <= usdCollected.add(_value)) {
            return true;
        }
        return false;
    }

    function getUnsoldTokensAmount() public view returns (uint256) {
        return maxSaleSupply.sub(tokensSold);
    }

    function updateStatsVars(uint256 _usdAmount, uint256 _tokensAmount) public {
        require(msg.sender == address(crowdsaleAgent) && _tokensAmount > 0);

        tokensSold = tokensSold.add(_tokensAmount);
        usdCollected = usdCollected.add(_usdAmount);
    }

    function internalContribution(address _contributor, uint256 _usdAmount) internal {
        updateState();

        require(currentState == State.InCrowdsale);

        CHLPricingStrategy pricing = CHLPricingStrategy(pricingStrategy);

        require(!isHardCapAchieved(_usdAmount.sub(1)));

        uint256 tokensAvailable = allocator.tokensAvailable();
        uint256 collectedWei = contributionForwarder.weiCollected();
        uint256 tierIndex = pricing.getTierIndex();
        uint256 tokens;
        uint256 tokensExcludingBonus;
        uint256 bonus;

        (tokens, tokensExcludingBonus, bonus) = pricing.getTokens(
            _contributor, tokensAvailable, tokensSold, _usdAmount, collectedWei);

        require(tokens > 0);

        tokensSold = tokensSold.add(tokens);

        allocator.allocate(_contributor, tokens);

        //allocate Processing fee
        uint256 processingFeeAmount = tokens.mul(processingFeePercentage).div(percentageAbsMax);
        allocator.allocate(processingFeeAddress, processingFeeAmount);

        if (isSoftCapAchieved(_usdAmount)) {
            if (msg.value > 0) {
                contributionForwarder.forward.value(address(this).balance)();
            }
        } else {
            // store contributor if it is not stored before
            if (contributorsWei[_contributor] == 0) {
                contributors.push(_contributor);
            }
            if (msg.value > 0) {
                contributorsWei[_contributor] = contributorsWei[_contributor].add(msg.value);
            }
        }

        usdCollected = usdCollected.add(_usdAmount);

        crowdsaleAgent.onContribution(_contributor, tierIndex, tokensExcludingBonus, bonus);

        emit Contribution(_contributor, _usdAmount, tokensExcludingBonus, bonus);
        emit ProcessingFeeAllocation(_contributor, processingFeeAmount);
    }

}
contract USDExchange is Ownable {

    using SafeMath for uint256;

    uint256 public etherPriceInUSD;
    uint256 public priceUpdateAt;
    mapping(address => bool) public trustedAddresses;

    event NewPriceTicker(string _price);

    modifier onlyTursted() {
        require(trustedAddresses[msg.sender] == true);
        _;
    }

    constructor(uint256 _etherPriceInUSD) public {
        etherPriceInUSD = _etherPriceInUSD;
        priceUpdateAt = block.timestamp;
        trustedAddresses[msg.sender] = true;
    }

    function setTrustedAddress(address _address, bool _status) public onlyOwner {
        trustedAddresses[_address] = _status;
    }

    // set ether price in USD with 5 digits after the decimal point
    //ex. 308.75000
    //for updating the price through  multivest
    function setEtherInUSD(string _price) public onlyTursted {
        bytes memory bytePrice = bytes(_price);
        uint256 dot = bytePrice.length.sub(uint256(6));

        // check if dot is in 6 position  from  the last
        require(0x2e == uint(bytePrice[dot]));

        uint256 newPrice = uint256(10 ** 23).div(parseInt(_price, 5));

        require(newPrice > 0);

        etherPriceInUSD = parseInt(_price, 5);

        priceUpdateAt = block.timestamp;

        emit NewPriceTicker(_price);
    }

    function parseInt(string _a, uint _b) internal pure returns (uint) {
        bytes memory bresult = bytes(_a);
        uint res = 0;
        bool decimals = false;
        for (uint i = 0; i < bresult.length; i++) {
            if ((bresult[i] >= 48) && (bresult[i] <= 57)) {
                if (decimals) {
                    if (_b == 0) break;
                    else _b--;
                }
                res *= 10;
                res += uint(bresult[i]) - 48;
            } else if (bresult[i] == 46) decimals = true;
        }
        if (_b > 0) res *= 10 ** _b;
        return res;
    }
}
/// @title PricingStrategy
/// @author Applicature
/// @notice Contract is responsible for calculating tokens amount depending on different criterias
/// @dev Base class
contract PricingStrategy {

    function isInitialized() public view returns (bool);

    function getTokens(
        address _contributor,
        uint256 _tokensAvailable,
        uint256 _tokensSold,
        uint256 _weiAmount,
        uint256 _collectedWei
    )
        public
        view
        returns (uint256 tokens, uint256 tokensExcludingBonus, uint256 bonus);

    function getWeis(
        uint256 _collectedWei,
        uint256 _tokensSold,
        uint256 _tokens
    )
        public
        view
        returns (uint256 weiAmount, uint256 tokensBonus);

}
/// @title USDDateTiersPricingStrategy
/// @author Applicature
/// @notice Contract is responsible for calculating tokens amount depending on price in USD
/// @dev implementation
contract USDDateTiersPricingStrategy is PricingStrategy, USDExchange {

    using SafeMath for uint256;

    //tokenInUSD token price in usd * 10 ^ 5
    //maxTokensCollected max tokens amount that can be distributed
    //bonusCap tokens amount cap; while sold tokens < bonus cap - contributors will receive bonus % tokens
    //soldTierTokens tokens that already been sold
    //bonusTierTokens bonus tokens that already been allocated
    //bonusPercents bonus percentage
    //minInvestInUSD min investment in usd * 10 * 5
    //startDate tier start time
    //endDate tier end time
    struct Tier {
        uint256 tokenInUSD;
        uint256 maxTokensCollected;
        uint256 bonusCap;
        uint256 soldTierTokens;
        uint256 bonusTierTokens;
        uint256 bonusPercents;
        uint256 minInvestInUSD;
        uint256 startDate;
        uint256 endDate;
    }

    Tier[] public tiers;
    uint256 public decimals;

    constructor(uint256[] _tiers, uint256 _decimals, uint256 _etherPriceInUSD) public USDExchange(_etherPriceInUSD) {
        decimals = _decimals;
        trustedAddresses[msg.sender] = true;
        require(_tiers.length % 9 == 0);

        uint256 length = _tiers.length / 9;

        for (uint256 i = 0; i < length; i++) {
            tiers.push(
                Tier(
                    _tiers[i * 9],
                    _tiers[i * 9 + 1],
                    _tiers[i * 9 + 2],
                    _tiers[i * 9 + 3],
                    _tiers[i * 9 + 4],
                    _tiers[i * 9 + 5],
                    _tiers[i * 9 + 6],
                    _tiers[i * 9 + 7],
                    _tiers[i * 9 + 8]
                )
            );
        }
    }

    /// @return tier index
    function getTierIndex() public view returns (uint256) {
        for (uint256 i = 0; i < tiers.length; i++) {
            if (
                block.timestamp >= tiers[i].startDate &&
                block.timestamp < tiers[i].endDate &&
                tiers[i].maxTokensCollected > tiers[i].soldTierTokens
            ) {
                return i;
            }
        }

        return tiers.length;
    }

    function getActualTierIndex() public view returns (uint256) {
        for (uint256 i = 0; i < tiers.length; i++) {
            if (
                block.timestamp >= tiers[i].startDate
                && block.timestamp < tiers[i].endDate
                && tiers[i].maxTokensCollected > tiers[i].soldTierTokens
                || block.timestamp < tiers[i].startDate
            ) {
                return i;
            }
        }

        return tiers.length.sub(1);
    }

    /// @return actual dates
    function getActualDates() public view returns (uint256 startDate, uint256 endDate) {
        uint256 tierIndex = getActualTierIndex();
        startDate = tiers[tierIndex].startDate;
        endDate = tiers[tierIndex].endDate;
    }

    /// @return tokens based on sold tokens and wei amount
    function getTokens(
        address,
        uint256 _tokensAvailable,
        uint256,
        uint256 _usdAmount,
        uint256
    ) public view returns (uint256 tokens, uint256 tokensExcludingBonus, uint256 bonus) {
        if (_usdAmount == 0) {
            return (0, 0, 0);
        }

        uint256 tierIndex = getTierIndex();

        if (tierIndex < tiers.length && _usdAmount < tiers[tierIndex].minInvestInUSD) {
            return (0, 0, 0);
        }
        if (tierIndex == tiers.length) {
            return (0, 0, 0);
        }
        tokensExcludingBonus = _usdAmount.mul(1e18).div(getTokensInUSD(tierIndex));
        if (tiers[tierIndex].maxTokensCollected < tiers[tierIndex].soldTierTokens.add(tokensExcludingBonus)) {
            return (0, 0, 0);
        }

        bonus = calculateBonusAmount(tierIndex, tokensExcludingBonus);

        tokens = tokensExcludingBonus.add(bonus);

        if (tokens > _tokensAvailable) {
            return (0, 0, 0);
        }
    }

    /// @return usd amount based on required tokens
    function getUSDAmountByTokens(
        uint256 _tokens
    ) public view returns (uint256 totalUSDAmount, uint256 tokensBonus) {
        if (_tokens == 0) {
            return (0, 0);
        }

        uint256 tierIndex = getTierIndex();
        if (tierIndex == tiers.length) {
            return (0, 0);
        }
        if (tiers[tierIndex].maxTokensCollected < tiers[tierIndex].soldTierTokens.add(_tokens)) {
            return (0, 0);
        }

        totalUSDAmount = _tokens.mul(getTokensInUSD(tierIndex)).div(1e18);

        if (totalUSDAmount < tiers[tierIndex].minInvestInUSD) {
            return (0, 0);
        }

        tokensBonus = calculateBonusAmount(tierIndex, _tokens);
    }

    /// @return weis based on sold and required tokens
    function getWeis(
        uint256,
        uint256,
        uint256 _tokens
    ) public view returns (uint256 totalWeiAmount, uint256 tokensBonus) {
        uint256 usdAmount;
        (usdAmount, tokensBonus) = getUSDAmountByTokens(_tokens);

        if (usdAmount == 0) {
            return (0, 0);
        }

        totalWeiAmount = usdAmount.mul(1e18).div(etherPriceInUSD);
    }

    /// calculates bonus tokens amount by bonusPercents in case if bonusCap is not reached;
    /// if reached returns 0
    /// @return bonus tokens amount
    function calculateBonusAmount(uint256 _tierIndex, uint256 _tokens) public view returns (uint256 bonus) {
        if (tiers[_tierIndex].soldTierTokens < tiers[_tierIndex].bonusCap) {
            if (tiers[_tierIndex].soldTierTokens.add(_tokens) <= tiers[_tierIndex].bonusCap) {
                bonus = _tokens.mul(tiers[_tierIndex].bonusPercents).div(100);
            } else {
                bonus = (tiers[_tierIndex].bonusCap.sub(tiers[_tierIndex].soldTierTokens))
                    .mul(tiers[_tierIndex].bonusPercents).div(100);
            }
        }
    }

    function getTokensInUSD(uint256 _tierIndex) public view returns (uint256) {
        if (_tierIndex < uint256(tiers.length)) {
            return tiers[_tierIndex].tokenInUSD;
        }
    }

    function getMinEtherInvest(uint256 _tierIndex) public view returns (uint256) {
        if (_tierIndex < uint256(tiers.length)) {
            return tiers[_tierIndex].minInvestInUSD.mul(1 ether).div(etherPriceInUSD);
        }
    }

    function getUSDAmountByWeis(uint256 _weiAmount) public view returns (uint256) {
        return _weiAmount.mul(etherPriceInUSD).div(1 ether);
    }

    /// @notice Check whether contract is initialised
    /// @return true if initialized
    function isInitialized() public view returns (bool) {
        return true;
    }

    /// @notice updates tier start/end dates by id
    function updateDates(uint8 _tierId, uint256 _start, uint256 _end) public onlyOwner() {
        if (_start != 0 && _start < _end && _tierId < tiers.length) {
            Tier storage tier = tiers[_tierId];
            tier.startDate = _start;
            tier.endDate = _end;
        }
    }
}
contract CHLPricingStrategy is USDDateTiersPricingStrategy {

    CHLAgent public agent;

    modifier onlyAgent() {
        require(msg.sender == address(agent));
        _;
    }

    event MaxTokensCollectedDecreased(uint256 tierId, uint256 oldValue, uint256 amount);

    constructor(
        uint256[] _emptyArray,
        uint256[4] _periods,
        uint256 _etherPriceInUSD
    ) public USDDateTiersPricingStrategy(_emptyArray, 18, _etherPriceInUSD) {
        //pre-ico
        tiers.push(Tier(0.75e5, 6247500e18, 0, 0, 0, 0, 100e5, _periods[0], _periods[1]));
        //public ico
        tiers.push(Tier(3e5, 32725000e18, 0, 0, 0, 0, 100e5, _periods[2], _periods[3]));
    }

    function getArrayOfTiers() public view returns (uint256[12] tiersData) {
        uint256 j = 0;
        for (uint256 i = 0; i < tiers.length; i++) {
            tiersData[j++] = uint256(tiers[i].tokenInUSD);
            tiersData[j++] = uint256(tiers[i].maxTokensCollected);
            tiersData[j++] = uint256(tiers[i].soldTierTokens);
            tiersData[j++] = uint256(tiers[i].minInvestInUSD);
            tiersData[j++] = uint256(tiers[i].startDate);
            tiersData[j++] = uint256(tiers[i].endDate);
        }
    }

    function updateTier(
        uint256 _tierId,
        uint256 _start,
        uint256 _end,
        uint256 _minInvest,
        uint256 _price,
        uint256 _bonusCap,
        uint256 _bonus,
        bool _updateLockNeeded
    ) public onlyOwner() {
        require(
            _start != 0 &&
            _price != 0 &&
            _start < _end &&
            _tierId < tiers.length
        );

        if (_updateLockNeeded) {
            agent.updateLockPeriod(_end);
        }

        Tier storage tier = tiers[_tierId];
        tier.tokenInUSD = _price;
        tier.minInvestInUSD = _minInvest;
        tier.startDate = _start;
        tier.endDate = _end;
        tier.bonusCap = _bonusCap;
        tier.bonusPercents = _bonus;
    }

    function setCrowdsaleAgent(CHLAgent _crowdsaleAgent) public onlyOwner {
        agent = _crowdsaleAgent;
    }

    function updateTierTokens(uint256 _tierId, uint256 _soldTokens, uint256 _bonusTokens) public onlyAgent {
        require(_tierId < tiers.length && _soldTokens > 0);

        Tier storage tier = tiers[_tierId];
        tier.soldTierTokens = tier.soldTierTokens.add(_soldTokens);
        tier.bonusTierTokens = tier.bonusTierTokens.add(_bonusTokens);
    }

    function updateMaxTokensCollected(uint256 _tierId, uint256 _amount) public onlyAgent {
        require(_tierId < tiers.length && _amount > 0);

        Tier storage tier = tiers[_tierId];

        require(tier.maxTokensCollected.sub(_amount) >= tier.soldTierTokens.add(tier.bonusTierTokens));

        emit MaxTokensCollectedDecreased(_tierId, tier.maxTokensCollected, _amount);

        tier.maxTokensCollected = tier.maxTokensCollected.sub(_amount);
    }

    function getTokensWithoutRestrictions(uint256 _usdAmount) public view returns (
        uint256 tokens,
        uint256 tokensExcludingBonus,
        uint256 bonus
    ) {
        if (_usdAmount == 0) {
            return (0, 0, 0);
        }

        uint256 tierIndex = getActualTierIndex();

        tokensExcludingBonus = _usdAmount.mul(1e18).div(getTokensInUSD(tierIndex));
        bonus = calculateBonusAmount(tierIndex, tokensExcludingBonus);
        tokens = tokensExcludingBonus.add(bonus);
    }

    function getTierUnsoldTokens(uint256 _tierId) public view returns (uint256) {
        if (_tierId >= tiers.length) {
            return 0;
        }

        return tiers[_tierId].maxTokensCollected.sub(tiers[_tierId].soldTierTokens);
    }

    function getSaleEndDate() public view returns (uint256) {
        return tiers[tiers.length.sub(1)].endDate;
    }

}
contract Referral is Ownable {

    using SafeMath for uint256;

    MintableTokenAllocator public allocator;
    CrowdsaleImpl public crowdsale;

    uint256 public constant DECIMALS = 18;

    uint256 public totalSupply;
    bool public unLimited;
    bool public sentOnce;

    mapping(address => bool) public claimed;
    mapping(address => uint256) public claimedBalances;

    constructor(
        uint256 _totalSupply,
        address _allocator,
        address _crowdsale,
        bool _sentOnce
    ) public {
        require(_allocator != address(0) && _crowdsale != address(0));
        totalSupply = _totalSupply;
        if (totalSupply == 0) {
            unLimited = true;
        }
        allocator = MintableTokenAllocator(_allocator);
        crowdsale = CrowdsaleImpl(_crowdsale);
        sentOnce = _sentOnce;
    }

    function setAllocator(address _allocator) public onlyOwner {
        if (_allocator != address(0)) {
            allocator = MintableTokenAllocator(_allocator);
        }
    }

    function setCrowdsale(address _crowdsale) public onlyOwner {
        require(_crowdsale != address(0));
        crowdsale = CrowdsaleImpl(_crowdsale);
    }

    function multivestMint(
        address _address,
        uint256 _amount,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    ) public {
        require(true == crowdsale.signers(verify(msg.sender, _amount, _v, _r, _s)));
        if (true == sentOnce) {
            require(claimed[_address] == false);
            claimed[_address] = true;
        }
        require(
            _address == msg.sender &&
            _amount > 0 &&
            (true == unLimited || _amount <= totalSupply)
        );
        claimedBalances[_address] = claimedBalances[_address].add(_amount);
        if (false == unLimited) {
            totalSupply = totalSupply.sub(_amount);
        }
        allocator.allocate(_address, _amount);
    }

    /// @notice check sign
    function verify(address _sender, uint256 _amount, uint8 _v, bytes32 _r, bytes32 _s) public pure returns (address) {
        bytes32 hash = keccak256(abi.encodePacked(_sender, _amount));

        bytes memory prefix = '\x19Ethereum Signed Message:\n32';

        return ecrecover(keccak256(abi.encodePacked(prefix, hash)), _v, _r, _s);
    }

}
contract CHLReferral is Referral {

    CHLPricingStrategy public pricingStrategy;

    constructor(
        address _allocator,
        address _crowdsale,
        CHLPricingStrategy _strategy
    ) public Referral(1190000e18, _allocator, _crowdsale, true) {
        require(_strategy != address(0));
        pricingStrategy = _strategy;
    }

    function multivestMint(
        address _address,
        uint256 _amount,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    ) public {
        require(pricingStrategy.getSaleEndDate() <= block.timestamp);
        super.multivestMint(_address, _amount, _v, _r, _s);
    }
}
contract CHLAllocation is Ownable {

    using SafeMath for uint256;

    MintableTokenAllocator public allocator;

    CHLAgent public agent;
    //manualMintingSupply = Advisors 2975000 + Bounty 1785000 + LWL (Non Profit Initiative) 1190000
    uint256 public manualMintingSupply = 5950000e18;

    uint256 public foundersVestingAmountPeriodOne = 7140000e18;
    uint256 public foundersVestingAmountPeriodTwo = 2975000e18;
    uint256 public foundersVestingAmountPeriodThree = 1785000e18;

    address[] public vestings;

    address public foundersAddress;

    bool public isFoundersTokensSent;

    event VestingCreated(
        address _vesting,
        address _beneficiary,
        uint256 _start,
        uint256 _cliff,
        uint256 _duration,
        uint256 _periods,
        bool _revocable
    );

    event VestingRevoked(address _vesting);

    constructor(MintableTokenAllocator _allocator, address _foundersAddress) public {
        require(_foundersAddress != address(0));
        foundersAddress = _foundersAddress;
        allocator = _allocator;
    }

    function setAllocator(MintableTokenAllocator _allocator) public onlyOwner {
        require(_allocator != address(0));
        allocator = _allocator;
    }

    function setAgent(CHLAgent _agent) public onlyOwner {
        require(_agent != address(0));
        agent = _agent;
    }

    function allocateManualMintingTokens(address[] _addresses, uint256[] _tokens) public onlyOwner {
        require(_addresses.length == _tokens.length);
        for (uint256 i = 0; i < _addresses.length; i++) {
            require(_addresses[i] != address(0) && _tokens[i] > 0 && _tokens[i] <= manualMintingSupply);
            manualMintingSupply -= _tokens[i];

            allocator.allocate(_addresses[i], _tokens[i]);
        }
    }

    function allocatePrivateSaleTokens(
        uint256 _tierId,
        uint256 _totalTokensSupply,
        uint256 _tokenPriceInUsd,
        address[] _addresses,
        uint256[] _tokens
    ) public onlyOwner {
        require(
            _addresses.length == _tokens.length &&
            _totalTokensSupply > 0
        );

        agent.updateStateWithPrivateSale(_tierId, _totalTokensSupply, _totalTokensSupply.mul(_tokenPriceInUsd).div(1e18));

        for (uint256 i = 0; i < _addresses.length; i++) {
            require(_addresses[i] != address(0) && _tokens[i] > 0 && _tokens[i] <= _totalTokensSupply);
            _totalTokensSupply = _totalTokensSupply.sub(_tokens[i]);

            allocator.allocate(_addresses[i], _tokens[i]);
        }

        require(_totalTokensSupply == 0);
    }

    function allocateFoundersTokens(uint256 _start) public {
        require(!isFoundersTokensSent && msg.sender == address(agent));

        isFoundersTokensSent = true;

        allocator.allocate(foundersAddress, foundersVestingAmountPeriodOne);

        createVestingInternal(
            foundersAddress,
            _start,
            0,
            365 days,
            1,
            true,
            owner,
            foundersVestingAmountPeriodTwo
        );

        createVestingInternal(
            foundersAddress,
            _start,
            0,
            730 days,
            1,
            true,
            owner,
            foundersVestingAmountPeriodThree
        );
    }

    function createVesting(
        address _beneficiary,
        uint256 _start,
        uint256 _cliff,
        uint256 _duration,
        uint256 _periods,
        bool _revocable,
        address _unreleasedHolder,
        uint256 _amount
    ) public onlyOwner returns (PeriodicTokenVesting vesting) {

        vesting = createVestingInternal(
            _beneficiary,
            _start,
            _cliff,
            _duration,
            _periods,
            _revocable,
            _unreleasedHolder,
            _amount
        );
    }

    function revokeVesting(PeriodicTokenVesting _vesting, ERC20Basic token) public onlyOwner() {
        _vesting.revoke(token);

        emit VestingRevoked(_vesting);
    }

    function createVestingInternal(
        address _beneficiary,
        uint256 _start,
        uint256 _cliff,
        uint256 _duration,
        uint256 _periods,
        bool _revocable,
        address _unreleasedHolder,
        uint256 _amount
    ) internal returns (PeriodicTokenVesting) {
        PeriodicTokenVesting vesting = new PeriodicTokenVesting(
            _beneficiary, _start, _cliff, _duration, _periods, _revocable, _unreleasedHolder
        );

        vestings.push(vesting);

        emit VestingCreated(vesting, _beneficiary, _start, _cliff, _duration, _periods, _revocable);

        allocator.allocate(address(vesting), _amount);

        return vesting;
    }

}
/**
 * @title TokenVesting
 * @dev A token holder contract that can release its token balance gradually like a
 * typical vesting scheme, with a cliff and vesting period. Optionally revocable by the
 * owner.
 */
contract TokenVesting is Ownable {
  using SafeMath for uint256;
  using SafeERC20 for ERC20Basic;

  event Released(uint256 amount);
  event Revoked();

  // beneficiary of tokens after they are released
  address public beneficiary;

  uint256 public cliff;
  uint256 public start;
  uint256 public duration;

  bool public revocable;

  mapping (address => uint256) public released;
  mapping (address => bool) public revoked;

  /**
   * @dev Creates a vesting contract that vests its balance of any ERC20 token to the
   * _beneficiary, gradually in a linear fashion until _start + _duration. By then all
   * of the balance will have vested.
   * @param _beneficiary address of the beneficiary to whom vested tokens are transferred
   * @param _cliff duration in seconds of the cliff in which tokens will begin to vest
   * @param _start the time (as Unix time) at which point vesting starts 
   * @param _duration duration in seconds of the period in which the tokens will vest
   * @param _revocable whether the vesting is revocable or not
   */
  constructor(
    address _beneficiary,
    uint256 _start,
    uint256 _cliff,
    uint256 _duration,
    bool _revocable
  )
    public
  {
    require(_beneficiary != address(0));
    require(_cliff <= _duration);

    beneficiary = _beneficiary;
    revocable = _revocable;
    duration = _duration;
    cliff = _start.add(_cliff);
    start = _start;
  }

  /**
   * @notice Transfers vested tokens to beneficiary.
   * @param token ERC20 token which is being vested
   */
  function release(ERC20Basic token) public {
    uint256 unreleased = releasableAmount(token);

    require(unreleased > 0);

    released[token] = released[token].add(unreleased);

    token.safeTransfer(beneficiary, unreleased);

    emit Released(unreleased);
  }

  /**
   * @notice Allows the owner to revoke the vesting. Tokens already vested
   * remain in the contract, the rest are returned to the owner.
   * @param token ERC20 token which is being vested
   */
  function revoke(ERC20Basic token) public onlyOwner {
    require(revocable);
    require(!revoked[token]);

    uint256 balance = token.balanceOf(this);

    uint256 unreleased = releasableAmount(token);
    uint256 refund = balance.sub(unreleased);

    revoked[token] = true;

    token.safeTransfer(owner, refund);

    emit Revoked();
  }

  /**
   * @dev Calculates the amount that has already vested but hasn't been released yet.
   * @param token ERC20 token which is being vested
   */
  function releasableAmount(ERC20Basic token) public view returns (uint256) {
    return vestedAmount(token).sub(released[token]);
  }

  /**
   * @dev Calculates the amount that has already vested.
   * @param token ERC20 token which is being vested
   */
  function vestedAmount(ERC20Basic token) public view returns (uint256) {
    uint256 currentBalance = token.balanceOf(this);
    uint256 totalBalance = currentBalance.add(released[token]);

    if (block.timestamp < cliff) {
      return 0;
    } else if (block.timestamp >= start.add(duration) || revoked[token]) {
      return totalBalance;
    } else {
      return totalBalance.mul(block.timestamp.sub(start)).div(duration);
    }
  }
}
contract PeriodicTokenVesting is TokenVesting {
    address public unreleasedHolder;
    uint256 public periods;

    constructor(
        address _beneficiary,
        uint256 _start,
        uint256 _cliff,
        uint256 _periodDuration,
        uint256 _periods,
        bool _revocable,
        address _unreleasedHolder
    ) public TokenVesting(_beneficiary, _start, _cliff, _periodDuration, _revocable) {
        require(_revocable == false || _unreleasedHolder != address(0));
        periods = _periods;
        unreleasedHolder = _unreleasedHolder;
    }

    /**
    * @dev Calculates the amount that has already vested.
    * @param token ERC20 token which is being vested
    */
    function vestedAmount(ERC20Basic token) public view returns (uint256) {
        uint256 currentBalance = token.balanceOf(this);
        uint256 totalBalance = currentBalance.add(released[token]);

        if (now < cliff) {
            return 0;
        } else if (now >= start.add(duration * periods) || revoked[token]) {
            return totalBalance;
        } else {

            uint256 periodTokens = totalBalance.div(periods);

            uint256 periodsOver = now.sub(start).div(duration);

            if (periodsOver >= periods) {
                return totalBalance;
            }

            return periodTokens.mul(periodsOver);
        }
    }

    /**
 * @notice Allows the owner to revoke the vesting. Tokens already vested
 * remain in the contract, the rest are returned to the owner.
 * @param token ERC20 token which is being vested
 */
    function revoke(ERC20Basic token) public onlyOwner {
        require(revocable);
        require(!revoked[token]);

        uint256 balance = token.balanceOf(this);

        uint256 unreleased = releasableAmount(token);
        uint256 refund = balance.sub(unreleased);

        revoked[token] = true;

        token.safeTransfer(unreleasedHolder, refund);

        emit Revoked();
    }
}
contract Stats {

    using SafeMath for uint256;

    MintableToken public token;
    MintableTokenAllocator public allocator;
    CHLCrowdsale public crowdsale;
    CHLPricingStrategy public pricing;

    constructor(
        MintableToken _token,
        MintableTokenAllocator _allocator,
        CHLCrowdsale _crowdsale,
        CHLPricingStrategy _pricing
    ) public {
        token = _token;
        allocator = _allocator;
        crowdsale = _crowdsale;
        pricing = _pricing;
    }

    function getTokens(
        uint256 _type,
        uint256 _usdAmount
    ) public view returns (uint256 tokens, uint256 tokensExcludingBonus, uint256 bonus) {
        _type = _type;

        return pricing.getTokensWithoutRestrictions(_usdAmount);
    }

    function getWeis(
        uint256 _type,
        uint256 _tokenAmount
    ) public view returns (uint256 totalWeiAmount, uint256 tokensBonus) {
        _type = _type;

        return pricing.getWeis(0, 0, _tokenAmount);
    }

    function getUSDAmount(
        uint256 _type,
        uint256 _tokenAmount
    ) public view returns (uint256 totalUSDAmount, uint256 tokensBonus) {
        _type = _type;

        return pricing.getUSDAmountByTokens(_tokenAmount);
    }

    function getStats(uint256 _userType, uint256[7] _ethPerCurrency) public view returns (
        uint256[8] stats,
        uint256[26] tiersData,
        uint256[21] currencyContr //tokensPerEachCurrency,
    ) {
        stats = getStatsData(_userType);
        tiersData = getTiersData(_userType);
        currencyContr = getCurrencyContrData(_userType, _ethPerCurrency);
    }

    function getTiersData(uint256 _type) public view returns (
        uint256[26] tiersData
    ) {
        _type = _type;
        uint256[12] memory tiers = pricing.getArrayOfTiers();
        uint256 length = tiers.length / 6;

        uint256 j = 0;
        for (uint256 i = 0; i < length; i++) {
            tiersData[j++] = uint256(1e23).div(tiers[i.mul(6)]);// tokenInUSD;
            tiersData[j++] = 0;// tokenInWei;
            tiersData[j++] = uint256(tiers[i.mul(6).add(1)]);// maxTokensCollected;
            tiersData[j++] = uint256(tiers[i.mul(6).add(2)]);// soldTierTokens;
            tiersData[j++] = 0;// discountPercents;
            tiersData[j++] = 0;// bonusPercents;
            tiersData[j++] = uint256(tiers[i.mul(6).add(3)]);// minInvestInUSD;
            tiersData[j++] = 0;// minInvestInWei;
            tiersData[j++] = 0;// maxInvestInUSD;
            tiersData[j++] = 0;// maxInvestInWei;
            tiersData[j++] = uint256(tiers[i.mul(6).add(4)]); // startDate;
            tiersData[j++] = uint256(tiers[i.mul(6).add(5)]); // endDate;
            tiersData[j++] = 1;
        }

        tiersData[25] = 2;

    }

    function getStatsData(uint256 _type) public view returns (
        uint256[8] stats
    ) {
        _type = _type;
        stats[0] = token.maxSupply();
        stats[1] = token.totalSupply();
        stats[2] = crowdsale.maxSaleSupply();
        stats[3] = crowdsale.tokensSold();
        stats[4] = uint256(crowdsale.currentState());
        stats[5] = pricing.getActualTierIndex();
        stats[6] = pricing.getTierUnsoldTokens(stats[5]);
        stats[7] = pricing.getMinEtherInvest(stats[5]);
    }

    function getCurrencyContrData(uint256 _type, uint256[7] _usdPerCurrency) public view returns (
        uint256[21] currencyContr
    ) {
        _type = _type;
        uint256 j = 0;
        for (uint256 i = 0; i < _usdPerCurrency.length; i++) {
            (currencyContr[j++], currencyContr[j++], currencyContr[j++]) = pricing.getTokensWithoutRestrictions(
                _usdPerCurrency[i]
            );
        }
    }
}

Contract Security Audit

Contract ABI

API
[{"constant":false,"inputs":[{"name":"_agent","type":"address"},{"name":"_status","type":"bool"}],"name":"updateBurnAgent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_address","type":"address"},{"name":"_status","type":"bool"}],"name":"updateExcludedAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"time","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_holder","type":"address"},{"name":"_to","type":"address"},{"name":"_tokens","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"burnAgents","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"allowedMinting","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_holder","type":"address"},{"name":"_tokens","type":"uint256"}],"name":"mint","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_value","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"isSoftCapAchieved","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_holder","type":"address"},{"name":"_tokensToBurn","type":"uint256"}],"name":"burnByAgent","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"standard","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_address","type":"address"},{"name":"_value","type":"uint256"}],"name":"isTransferAllowed","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseApproval","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"availableTokens","outputs":[{"name":"tokens","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_agent","type":"address"},{"name":"_status","type":"bool"}],"name":"updateStateChangeAgent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"disableMinting","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"setIsSoftCapAchieved","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"crowdsale","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"mintingAgents","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_tokens","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"stateChangeAgents","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_agent","type":"address"},{"name":"_status","type":"bool"}],"name":"updateMintingAgent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"excludedAddresses","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_tokensToBurn","type":"uint256"}],"name":"burnUnsoldTokens","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"newOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseApproval","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_unlockTokensTime","type":"uint256"}],"name":"setUnlockTime","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newMaxSupply","type":"uint256"}],"name":"updateMaxSupply","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_crowdsale","type":"address"}],"name":"setCrowdSale","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_unlockTokensTime","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"burner","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"holder","type":"address"},{"indexed":false,"name":"tokens","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]

60806040523480156200001157600080fd5b506040516020806200190f83398101604081815291518282018352600a82527f4368656c6c65436f696e0000000000000000000000000000000000000000000060208084019190915283518085018552600381527f43484c000000000000000000000000000000000000000000000000000000000081830152600083815560058054600160a060020a03191633179055855180870190965260098087527f455243323020302e31000000000000000000000000000000000000000000000096909301958652929485946a31379d7690a13aeb8000009493600193869386938693859391926012929185916200010891908162000213565b50600385905580156200012d5733600090815260026020526040902085905562000140565b3060009081526002602052604090208590555b83516200015590600790602087019062000213565b5081516200016b90600890602085019062000213565b50506006805460ff909316740100000000000000000000000000000000000000000260a060020a60ff021990931692909217909155505050600a839055600354620001c590836401000000006200124c620001ff82021704565b600355600b805491151560ff19928316179055336000908152600c602052604090208054909116600117905550620002b895505050505050565b818101828110156200020d57fe5b92915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200025657805160ff191683800117855562000286565b8280016001018555821562000286579182015b828111156200028657825182559160200191906001019062000269565b506200029492915062000298565b5090565b620002b591905b808211156200029457600081556001016200029f565b90565b61164780620002c86000396000f3006080604052600436106101ed5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166305f6ee2181146101f257806306fdde031461021a5780630764ebd9146102a4578063095ea7b3146102ca57806316ada5471461030257806318160ddd1461032957806323b872dd1461033e5780632d0d0c0914610368578063313ce5671461038957806335b7588f146103b457806340c10f19146103c957806342966c68146103ed57806345bcdbab14610405578063569e9c821461041a5780635a3b7e421461043e5780635eae177c14610453578063661884631461047757806369bb4dc21461049b57806370a08231146104b0578063757f7302146104d157806379ba5097146104f75780637e5cd5c11461050c5780638da5cb5b146105215780639250d59f1461055257806395d89b41146105675780639c1e03a01461057c5780639c7beb8a14610591578063a9059cbb146105b2578063abe2a18d146105d6578063cd8f8b3c146105f7578063cf011b261461061d578063d0479abc1461063e578063d4ee1d9014610656578063d5abeb011461066b578063d73dd62314610680578063dace4557146106a4578063dd62ed3e146106bc578063f103b433146106e3578063f2fde38b146106fb578063f4b5cbc41461071c575b600080fd5b3480156101fe57600080fd5b50610218600160a060020a0360043516602435151561073d565b005b34801561022657600080fd5b5061022f61077f565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610269578181015183820152602001610251565b50505050905090810190601f1680156102965780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156102b057600080fd5b50610218600160a060020a0360043516602435151561080d565b3480156102d657600080fd5b506102ee600160a060020a036004351660243561084f565b604080519115158252519081900360200190f35b34801561030e57600080fd5b506103176108b6565b60408051918252519081900360200190f35b34801561033557600080fd5b506103176108bc565b34801561034a57600080fd5b506102ee600160a060020a03600435811690602435166044356108c2565b34801561037457600080fd5b506102ee600160a060020a03600435166108ef565b34801561039557600080fd5b5061039e610904565b6040805160ff9092168252519081900360200190f35b3480156103c057600080fd5b506102ee610925565b3480156103d557600080fd5b50610218600160a060020a036004351660243561092e565b3480156103f957600080fd5b50610218600435610a53565b34801561041157600080fd5b506102ee610a60565b34801561042657600080fd5b50610317600160a060020a0360043516602435610a81565b34801561044a57600080fd5b5061022f610ac2565b34801561045f57600080fd5b506102ee600160a060020a0360043516602435610b1d565b34801561048357600080fd5b506102ee600160a060020a0360043516602435610c32565b3480156104a757600080fd5b50610317610d22565b3480156104bc57600080fd5b50610317600160a060020a0360043516610d40565b3480156104dd57600080fd5b50610218600160a060020a03600435166024351515610d5b565b34801561050357600080fd5b50610218610d9d565b34801561051857600080fd5b50610218610de2565b34801561052d57600080fd5b50610536610e0c565b60408051600160a060020a039092168252519081900360200190f35b34801561055e57600080fd5b50610218610e1b565b34801561057357600080fd5b5061022f610e70565b34801561058857600080fd5b50610536610ecb565b34801561059d57600080fd5b506102ee600160a060020a0360043516610eda565b3480156105be57600080fd5b506102ee600160a060020a0360043516602435610eef565b3480156105e257600080fd5b506102ee600160a060020a0360043516610f1a565b34801561060357600080fd5b50610218600160a060020a03600435166024351515610f2f565b34801561062957600080fd5b506102ee600160a060020a0360043516610f71565b34801561064a57600080fd5b50610317600435610f86565b34801561066257600080fd5b50610536611016565b34801561067757600080fd5b50610317611025565b34801561068c57600080fd5b506102ee600160a060020a036004351660243561102b565b3480156106b057600080fd5b506102186004356110c4565b3480156106c857600080fd5b50610317600160a060020a03600435811690602435166110e7565b3480156106ef57600080fd5b50610218600435611112565b34801561070757600080fd5b50610218600160a060020a036004351661113b565b34801561072857600080fd5b50610218600160a060020a0360043516611196565b600554600160a060020a0316331461075457600080fd5b600160a060020a03919091166000908152600e60205260409020805460ff1916911515919091179055565b6007805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156108055780601f106107da57610100808354040283529160200191610805565b820191906000526020600020905b8154815290600101906020018083116107e857829003601f168201915b505050505081565b600554600160a060020a0316331461082457600080fd5b600160a060020a03919091166000908152600160205260409020805460ff1916911515919091179055565b336000818152600460209081526040808320600160a060020a038716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a35060015b92915050565b60005481565b60035490565b60006108ce8483610b1d565b15156001146108dc57600080fd5b6108e78484846111f1565b949350505050565b600e6020526000908152604090205460ff1681565b60065474010000000000000000000000000000000000000000900460ff1681565b600b5460ff1681565b336000908152600c602052604090205460ff16151561094c57600080fd5b600b5460ff16151560011480156109775750600a54600354610974908363ffffffff61124c16565b11155b151561098257600080fd5b600354610995908263ffffffff61124c16565b6003556109b1816109a584610d40565b9063ffffffff61124c16565b600160a060020a038316600090815260026020526040902055600a5460035414156109e157600b805460ff191690555b604080518281529051600160a060020a038416916000916000805160206115fc8339815191529181900360200190a3604080518281529051600160a060020a038416917f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885919081900360200190a25050565b610a5d3382611259565b50565b600f5474010000000000000000000000000000000000000000900460ff1681565b336000908152600e602052604081205460ff161515610a9f57600080fd5b811515610ab257610aaf83610d40565b91505b610abc8383611259565b50919050565b6009805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156108055780601f106107da57610100808354040283529160200191610805565b600160a060020a038216600090815260016020819052604082205460ff1615151415610b4b575060016108b0565b600f5474010000000000000000000000000000000000000000900460ff16158015610c1c5750600f54600160a060020a03161580610c1c5750600f54604080517f3158c52b0000000000000000000000000000000000000000000000000000000081526000600482018190529151600160a060020a0390931692633158c52b92602480840193602093929083900390910190829087803b158015610bee57600080fd5b505af1158015610c02573d6000803e3d6000fd5b505050506040513d6020811015610c1857600080fd5b5051155b15610c29575060006108b0565b50600192915050565b336000908152600460209081526040808320600160a060020a038616845290915281205480831115610c8757336000908152600460209081526040808320600160a060020a0388168452909152812055610cbc565b610c97818463ffffffff61135e16565b336000908152600460209081526040808320600160a060020a03891684529091529020555b336000818152600460209081526040808320600160a060020a0389168085529083529281902054815190815290519293927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060019392505050565b6000610d3b600354600a5461135e90919063ffffffff16565b905090565b600160a060020a031660009081526002602052604090205490565b600554600160a060020a03163314610d7257600080fd5b600160a060020a03919091166000908152600d60205260409020805460ff1916911515919091179055565b600654600160a060020a0316331415610de0576006546005805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a039092169190911790555b565b336000908152600d602052604090205460ff161515610e0057600080fd5b600b805460ff19169055565b600554600160a060020a031681565b336000908152600d602052604090205460ff161515610e3957600080fd5b600f805474ff0000000000000000000000000000000000000000191674010000000000000000000000000000000000000000179055565b6008805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156108055780601f106107da57610100808354040283529160200191610805565b600f54600160a060020a031681565b600c6020526000908152604090205460ff1681565b6000610efb3383610b1d565b1515600114610f0957600080fd5b610f138383611370565b9392505050565b600d6020526000908152604090205460ff1681565b600554600160a060020a03163314610f4657600080fd5b600160a060020a03919091166000908152600c60205260409020805460ff1916911515919091179055565b60016020526000908152604090205460ff1681565b336000908152600e602052604081205460ff161515610fa457600080fd5b600a54600354610fba908463ffffffff61124c16565b1115610fc557600080fd5b600a54610fd8908363ffffffff61135e16565b600a556040805183815290516000917fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5919081900360200190a25090565b600654600160a060020a031681565b600a5481565b336000908152600460209081526040808320600160a060020a038616845290915281205461105f908363ffffffff61124c16565b336000818152600460209081526040808320600160a060020a0389168085529083529281902085905580519485525191937f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929081900390910190a350600192915050565b336000908152600d602052604090205460ff1615156110e257600080fd5b600055565b600160a060020a03918216600090815260046020908152604080832093909416825291909152205490565b600554600160a060020a0316331461112957600080fd5b6000811161113657600080fd5b600a55565b600554600160a060020a0316331461115257600080fd5b600160a060020a038116151561116757600080fd5b6006805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b600554600160a060020a031633146111ad57600080fd5b600160a060020a03811615156111c257600080fd5b600f805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b60008054600160a060020a03851682526001602081905260408320548692849242919091109160ff161515148061122b5750811515811515145b151561123657600080fd5b6112418787876113c3565b979650505050505050565b818101828110156108b057fe5b600160a060020a03821660009081526002602052604090205481111561127e57600080fd5b600160a060020a0382166000908152600260205260409020546112a7908263ffffffff61135e16565b600160a060020a0383166000908152600260205260409020556003546112d3908263ffffffff61135e16565b600355600a546112e9908263ffffffff61135e16565b600a55604080518281529051600160a060020a038416917fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5919081900360200190a2604080518281529051600091600160a060020a038516916000805160206115fc8339815191529181900360200190a35050565b60008282111561136a57fe5b50900390565b60008054338083526001602081905260408420549192849242919091109160ff909116151514806113a45750811515811515145b15156113af57600080fd5b6113b9868661152a565b9695505050505050565b6000600160a060020a03831615156113da57600080fd5b600160a060020a0384166000908152600260205260409020548211156113ff57600080fd5b600160a060020a038416600090815260046020908152604080832033845290915290205482111561142f57600080fd5b600160a060020a038416600090815260026020526040902054611458908363ffffffff61135e16565b600160a060020a03808616600090815260026020526040808220939093559085168152205461148d908363ffffffff61124c16565b600160a060020a0380851660009081526002602090815260408083209490945591871681526004825282812033825290915220546114d1908363ffffffff61135e16565b600160a060020a03808616600081815260046020908152604080832033845282529182902094909455805186815290519287169391926000805160206115fc833981519152929181900390910190a35060019392505050565b6000600160a060020a038316151561154157600080fd5b3360009081526002602052604090205482111561155d57600080fd5b3360009081526002602052604090205461157d908363ffffffff61135e16565b3360009081526002602052604080822092909255600160a060020a038516815220546115af908363ffffffff61124c16565b600160a060020a0384166000818152600260209081526040918290209390935580518581529051919233926000805160206115fc8339815191529281900390910190a3506001929150505600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a723058200bd746049343df967f9095ecc2c40370e3d129a91f26e7eb9617a3d34c1719310029000000000000000000000000000000000000000000000000000000005cf04450

Deployed Bytecode

0x6080604052600436106101ed5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166305f6ee2181146101f257806306fdde031461021a5780630764ebd9146102a4578063095ea7b3146102ca57806316ada5471461030257806318160ddd1461032957806323b872dd1461033e5780632d0d0c0914610368578063313ce5671461038957806335b7588f146103b457806340c10f19146103c957806342966c68146103ed57806345bcdbab14610405578063569e9c821461041a5780635a3b7e421461043e5780635eae177c14610453578063661884631461047757806369bb4dc21461049b57806370a08231146104b0578063757f7302146104d157806379ba5097146104f75780637e5cd5c11461050c5780638da5cb5b146105215780639250d59f1461055257806395d89b41146105675780639c1e03a01461057c5780639c7beb8a14610591578063a9059cbb146105b2578063abe2a18d146105d6578063cd8f8b3c146105f7578063cf011b261461061d578063d0479abc1461063e578063d4ee1d9014610656578063d5abeb011461066b578063d73dd62314610680578063dace4557146106a4578063dd62ed3e146106bc578063f103b433146106e3578063f2fde38b146106fb578063f4b5cbc41461071c575b600080fd5b3480156101fe57600080fd5b50610218600160a060020a0360043516602435151561073d565b005b34801561022657600080fd5b5061022f61077f565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610269578181015183820152602001610251565b50505050905090810190601f1680156102965780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156102b057600080fd5b50610218600160a060020a0360043516602435151561080d565b3480156102d657600080fd5b506102ee600160a060020a036004351660243561084f565b604080519115158252519081900360200190f35b34801561030e57600080fd5b506103176108b6565b60408051918252519081900360200190f35b34801561033557600080fd5b506103176108bc565b34801561034a57600080fd5b506102ee600160a060020a03600435811690602435166044356108c2565b34801561037457600080fd5b506102ee600160a060020a03600435166108ef565b34801561039557600080fd5b5061039e610904565b6040805160ff9092168252519081900360200190f35b3480156103c057600080fd5b506102ee610925565b3480156103d557600080fd5b50610218600160a060020a036004351660243561092e565b3480156103f957600080fd5b50610218600435610a53565b34801561041157600080fd5b506102ee610a60565b34801561042657600080fd5b50610317600160a060020a0360043516602435610a81565b34801561044a57600080fd5b5061022f610ac2565b34801561045f57600080fd5b506102ee600160a060020a0360043516602435610b1d565b34801561048357600080fd5b506102ee600160a060020a0360043516602435610c32565b3480156104a757600080fd5b50610317610d22565b3480156104bc57600080fd5b50610317600160a060020a0360043516610d40565b3480156104dd57600080fd5b50610218600160a060020a03600435166024351515610d5b565b34801561050357600080fd5b50610218610d9d565b34801561051857600080fd5b50610218610de2565b34801561052d57600080fd5b50610536610e0c565b60408051600160a060020a039092168252519081900360200190f35b34801561055e57600080fd5b50610218610e1b565b34801561057357600080fd5b5061022f610e70565b34801561058857600080fd5b50610536610ecb565b34801561059d57600080fd5b506102ee600160a060020a0360043516610eda565b3480156105be57600080fd5b506102ee600160a060020a0360043516602435610eef565b3480156105e257600080fd5b506102ee600160a060020a0360043516610f1a565b34801561060357600080fd5b50610218600160a060020a03600435166024351515610f2f565b34801561062957600080fd5b506102ee600160a060020a0360043516610f71565b34801561064a57600080fd5b50610317600435610f86565b34801561066257600080fd5b50610536611016565b34801561067757600080fd5b50610317611025565b34801561068c57600080fd5b506102ee600160a060020a036004351660243561102b565b3480156106b057600080fd5b506102186004356110c4565b3480156106c857600080fd5b50610317600160a060020a03600435811690602435166110e7565b3480156106ef57600080fd5b50610218600435611112565b34801561070757600080fd5b50610218600160a060020a036004351661113b565b34801561072857600080fd5b50610218600160a060020a0360043516611196565b600554600160a060020a0316331461075457600080fd5b600160a060020a03919091166000908152600e60205260409020805460ff1916911515919091179055565b6007805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156108055780601f106107da57610100808354040283529160200191610805565b820191906000526020600020905b8154815290600101906020018083116107e857829003601f168201915b505050505081565b600554600160a060020a0316331461082457600080fd5b600160a060020a03919091166000908152600160205260409020805460ff1916911515919091179055565b336000818152600460209081526040808320600160a060020a038716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a35060015b92915050565b60005481565b60035490565b60006108ce8483610b1d565b15156001146108dc57600080fd5b6108e78484846111f1565b949350505050565b600e6020526000908152604090205460ff1681565b60065474010000000000000000000000000000000000000000900460ff1681565b600b5460ff1681565b336000908152600c602052604090205460ff16151561094c57600080fd5b600b5460ff16151560011480156109775750600a54600354610974908363ffffffff61124c16565b11155b151561098257600080fd5b600354610995908263ffffffff61124c16565b6003556109b1816109a584610d40565b9063ffffffff61124c16565b600160a060020a038316600090815260026020526040902055600a5460035414156109e157600b805460ff191690555b604080518281529051600160a060020a038416916000916000805160206115fc8339815191529181900360200190a3604080518281529051600160a060020a038416917f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885919081900360200190a25050565b610a5d3382611259565b50565b600f5474010000000000000000000000000000000000000000900460ff1681565b336000908152600e602052604081205460ff161515610a9f57600080fd5b811515610ab257610aaf83610d40565b91505b610abc8383611259565b50919050565b6009805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156108055780601f106107da57610100808354040283529160200191610805565b600160a060020a038216600090815260016020819052604082205460ff1615151415610b4b575060016108b0565b600f5474010000000000000000000000000000000000000000900460ff16158015610c1c5750600f54600160a060020a03161580610c1c5750600f54604080517f3158c52b0000000000000000000000000000000000000000000000000000000081526000600482018190529151600160a060020a0390931692633158c52b92602480840193602093929083900390910190829087803b158015610bee57600080fd5b505af1158015610c02573d6000803e3d6000fd5b505050506040513d6020811015610c1857600080fd5b5051155b15610c29575060006108b0565b50600192915050565b336000908152600460209081526040808320600160a060020a038616845290915281205480831115610c8757336000908152600460209081526040808320600160a060020a0388168452909152812055610cbc565b610c97818463ffffffff61135e16565b336000908152600460209081526040808320600160a060020a03891684529091529020555b336000818152600460209081526040808320600160a060020a0389168085529083529281902054815190815290519293927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060019392505050565b6000610d3b600354600a5461135e90919063ffffffff16565b905090565b600160a060020a031660009081526002602052604090205490565b600554600160a060020a03163314610d7257600080fd5b600160a060020a03919091166000908152600d60205260409020805460ff1916911515919091179055565b600654600160a060020a0316331415610de0576006546005805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a039092169190911790555b565b336000908152600d602052604090205460ff161515610e0057600080fd5b600b805460ff19169055565b600554600160a060020a031681565b336000908152600d602052604090205460ff161515610e3957600080fd5b600f805474ff0000000000000000000000000000000000000000191674010000000000000000000000000000000000000000179055565b6008805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156108055780601f106107da57610100808354040283529160200191610805565b600f54600160a060020a031681565b600c6020526000908152604090205460ff1681565b6000610efb3383610b1d565b1515600114610f0957600080fd5b610f138383611370565b9392505050565b600d6020526000908152604090205460ff1681565b600554600160a060020a03163314610f4657600080fd5b600160a060020a03919091166000908152600c60205260409020805460ff1916911515919091179055565b60016020526000908152604090205460ff1681565b336000908152600e602052604081205460ff161515610fa457600080fd5b600a54600354610fba908463ffffffff61124c16565b1115610fc557600080fd5b600a54610fd8908363ffffffff61135e16565b600a556040805183815290516000917fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5919081900360200190a25090565b600654600160a060020a031681565b600a5481565b336000908152600460209081526040808320600160a060020a038616845290915281205461105f908363ffffffff61124c16565b336000818152600460209081526040808320600160a060020a0389168085529083529281902085905580519485525191937f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929081900390910190a350600192915050565b336000908152600d602052604090205460ff1615156110e257600080fd5b600055565b600160a060020a03918216600090815260046020908152604080832093909416825291909152205490565b600554600160a060020a0316331461112957600080fd5b6000811161113657600080fd5b600a55565b600554600160a060020a0316331461115257600080fd5b600160a060020a038116151561116757600080fd5b6006805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b600554600160a060020a031633146111ad57600080fd5b600160a060020a03811615156111c257600080fd5b600f805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b60008054600160a060020a03851682526001602081905260408320548692849242919091109160ff161515148061122b5750811515811515145b151561123657600080fd5b6112418787876113c3565b979650505050505050565b818101828110156108b057fe5b600160a060020a03821660009081526002602052604090205481111561127e57600080fd5b600160a060020a0382166000908152600260205260409020546112a7908263ffffffff61135e16565b600160a060020a0383166000908152600260205260409020556003546112d3908263ffffffff61135e16565b600355600a546112e9908263ffffffff61135e16565b600a55604080518281529051600160a060020a038416917fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5919081900360200190a2604080518281529051600091600160a060020a038516916000805160206115fc8339815191529181900360200190a35050565b60008282111561136a57fe5b50900390565b60008054338083526001602081905260408420549192849242919091109160ff909116151514806113a45750811515811515145b15156113af57600080fd5b6113b9868661152a565b9695505050505050565b6000600160a060020a03831615156113da57600080fd5b600160a060020a0384166000908152600260205260409020548211156113ff57600080fd5b600160a060020a038416600090815260046020908152604080832033845290915290205482111561142f57600080fd5b600160a060020a038416600090815260026020526040902054611458908363ffffffff61135e16565b600160a060020a03808616600090815260026020526040808220939093559085168152205461148d908363ffffffff61124c16565b600160a060020a0380851660009081526002602090815260408083209490945591871681526004825282812033825290915220546114d1908363ffffffff61135e16565b600160a060020a03808616600081815260046020908152604080832033845282529182902094909455805186815290519287169391926000805160206115fc833981519152929181900390910190a35060019392505050565b6000600160a060020a038316151561154157600080fd5b3360009081526002602052604090205482111561155d57600080fd5b3360009081526002602052604090205461157d908363ffffffff61135e16565b3360009081526002602052604080822092909255600160a060020a038516815220546115af908363ffffffff61124c16565b600160a060020a0384166000818152600260209081526040918290209390935580518581529051919233926000805160206115fc8339815191529281900390910190a3506001929150505600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a723058200bd746049343df967f9095ecc2c40370e3d129a91f26e7eb9617a3d34c1719310029

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000000000000000000000000000000000005cf04450

-----Decoded View---------------
Arg [0] : _unlockTokensTime (uint256): 1559250000

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000000000000000000000000000000000005cf04450


Swarm Source

bzzr://0bd746049343df967f9095ecc2c40370e3d129a91f26e7eb9617a3d34c171931

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

OVERVIEW

Users allocate tokens within the Chelle App and platform to collect a customized stream of residual income pro rata in the form of ETH.

Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.