ETH Price: $3,092.79 (+5.01%)
Gas: 3 Gwei

Transaction Decoder

Block:
6059403 at Jul-30-2018 09:18:18 PM +UTC
Transaction Fee:
0.000106499 ETH $0.33
Gas Used:
106,499 Gas / 1 Gwei

Emitted Events:

29 GambioCrowdsale.TokenPurchaseRequest( transactionId=146, beneficiary=[Sender] 0x694dbd2d342851c202d704d177bca56b3aadcdfa, timestamp=1532985498, weiAmount=500000000000000000, tokensAmount=2500000000000000000000 )
30 MultiSigWalletWithDailyLimit.Deposit( sender=[Receiver] GambioCrowdsale, value=500000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x01e0c66D...755b31270 212.200971639590168982 Eth212.700971639590168982 Eth0.5
(Nanopool)
7,824.33066818277845299 Eth7,824.33077468177845299 Eth0.000106499
0x66323324...36498EBd6
0x694dbd2D...b3aaDcDFa
0.519494055 Eth
Nonce: 2
0.019387556 Eth
Nonce: 3
0.500106499

Execution Trace

ETH 0.5 GambioCrowdsale.CALL( )
  • ETH 0.5 MultiSigWalletWithDailyLimit.CALL( )
    File 1 of 2: GambioCrowdsale
    pragma solidity 0.4.24;
    
    // File: openzeppelin-solidity/contracts/math/SafeMath.sol
    
    /**
     * @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;
      }
    }
    
    // File: openzeppelin-solidity/contracts/ownership/Ownable.sol
    
    /**
     * @title Ownable
     * @dev The Ownable contract has an owner address, and provides basic authorization control
     * functions, this simplifies the implementation of "user permissions".
     */
    contract Ownable {
      address public owner;
    
    
      event OwnershipRenounced(address indexed previousOwner);
      event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
      );
    
    
      /**
       * @dev The Ownable constructor sets the original `owner` of the contract to the sender
       * account.
       */
      constructor() public {
        owner = msg.sender;
      }
    
      /**
       * @dev Throws if called by any account other than the owner.
       */
      modifier onlyOwner() {
        require(msg.sender == owner);
        _;
      }
    
      /**
       * @dev Allows the current owner to relinquish control of the contract.
       */
      function renounceOwnership() public onlyOwner {
        emit OwnershipRenounced(owner);
        owner = address(0);
      }
    
      /**
       * @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 {
        _transferOwnership(_newOwner);
      }
    
      /**
       * @dev Transfers control of the contract to a newOwner.
       * @param _newOwner The address to transfer ownership to.
       */
      function _transferOwnership(address _newOwner) internal {
        require(_newOwner != address(0));
        emit OwnershipTransferred(owner, _newOwner);
        owner = _newOwner;
      }
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol
    
    /**
     * @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);
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC20/BasicToken.sol
    
    /**
     * @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];
      }
    
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
    
    /**
     * @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
      );
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol
    
    /**
     * @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;
      }
    
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC20/MintableToken.sol
    
    /**
     * @title Mintable token
     * @dev Simple ERC20 Token example, with mintable token creation
     * @dev Issue: * https://github.com/OpenZeppelin/openzeppelin-solidity/issues/120
     * Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol
     */
    contract MintableToken is StandardToken, Ownable {
      event Mint(address indexed to, uint256 amount);
      event MintFinished();
    
      bool public mintingFinished = false;
    
    
      modifier canMint() {
        require(!mintingFinished);
        _;
      }
    
      modifier hasMintPermission() {
        require(msg.sender == owner);
        _;
      }
    
      /**
       * @dev Function to mint tokens
       * @param _to The address that will receive the minted tokens.
       * @param _amount The amount of tokens to mint.
       * @return A boolean that indicates if the operation was successful.
       */
      function mint(
        address _to,
        uint256 _amount
      )
        hasMintPermission
        canMint
        public
        returns (bool)
      {
        totalSupply_ = totalSupply_.add(_amount);
        balances[_to] = balances[_to].add(_amount);
        emit Mint(_to, _amount);
        emit Transfer(address(0), _to, _amount);
        return true;
      }
    
      /**
       * @dev Function to stop minting new tokens.
       * @return True if the operation was successful.
       */
      function finishMinting() onlyOwner canMint public returns (bool) {
        mintingFinished = true;
        emit MintFinished();
        return true;
      }
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC20/CappedToken.sol
    
    /**
     * @title Capped token
     * @dev Mintable token with a token cap.
     */
    contract CappedToken is MintableToken {
    
      uint256 public cap;
    
      constructor(uint256 _cap) public {
        require(_cap > 0);
        cap = _cap;
      }
    
      /**
       * @dev Function to mint tokens
       * @param _to The address that will receive the minted tokens.
       * @param _amount The amount of tokens to mint.
       * @return A boolean that indicates if the operation was successful.
       */
      function mint(
        address _to,
        uint256 _amount
      )
        onlyOwner
        canMint
        public
        returns (bool)
      {
        require(totalSupply_.add(_amount) <= cap);
    
        return super.mint(_to, _amount);
      }
    
    }
    
    // File: contracts/GambioToken.sol
    
    contract GambioToken is CappedToken {
    
    
      using SafeMath for uint256;
    
      string public name = "GMB";
      string public symbol = "GMB";
      uint8 public decimals = 18;
    
      event Burn(address indexed burner, uint256 value);
      event BurnTransferred(address indexed previousBurner, address indexed newBurner);
    
      address burnerRole;
    
      modifier onlyBurner() {
        require(msg.sender == burnerRole);
        _;
      }
    
      constructor(address _burner, uint256 _cap) public CappedToken(_cap) {
        burnerRole = _burner;
      }
    
      function transferBurnRole(address newBurner) public onlyBurner {
        require(newBurner != address(0));
        emit BurnTransferred(burnerRole, newBurner);
        burnerRole = newBurner;
      }
    
      function burn(uint256 _value) public onlyBurner {
        require(_value <= balances[msg.sender]);
        balances[msg.sender] = balances[msg.sender].sub(_value);
        totalSupply_ = totalSupply_.sub(_value);
        emit Burn(msg.sender, _value);
        emit Transfer(msg.sender, address(0), _value);
      }
    }
    
    // File: contracts/Crowdsale.sol
    
    contract Crowdsale {
    
    
      using SafeMath for uint256;
    
      // The token being sold
      GambioToken public token;
    
      // start and end timestamps where investments are allowed (both inclusive)
      uint256 public startTime;
      uint256 public endTime;
    
      uint256 public rate;
    
      // address where funds are collected
      address public wallet;
    
      // amount of raised money in wei
      uint256 public weiRaised;
    
      event TokenPurchase(address indexed beneficiary, uint256 indexed value, uint256 indexed amount, uint256 transactionId);
    
      constructor(
        uint256 _startTime,
        uint256 _endTime,
        uint256 _rate,
        address _wallet,
        uint256 _initialWeiRaised,
        uint256 _tokenCap) public {
        require(_startTime >= now);
        require(_endTime >= _startTime);
        require(_wallet != address(0));
        require(_rate > 0);
        require(_tokenCap > 0);
    
        token = new GambioToken(_wallet, _tokenCap);
        startTime = _startTime;
        endTime = _endTime;
        rate = _rate;
        wallet = _wallet;
        weiRaised = _initialWeiRaised;
      }
    
      // @return true if crowdsale event has ended
      function hasEnded() public view returns (bool) {
        return now > endTime;
      }
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol
    
    /**
     * @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));
      }
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC20/TokenVesting.sol
    
    /* solium-disable security/no-block-members */
    
    pragma solidity ^0.4.23;
    
    
    
    
    
    
    /**
     * @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);
        }
      }
    }
    
    // File: contracts/GambioVesting.sol
    
    contract GambioVesting is TokenVesting {
    
    
      using SafeMath for uint256;
    
      uint256 public previousRelease;
      uint256 period;
    
      constructor(uint256 _period, address _beneficiary, uint256 _start, uint256 _cliff, uint256 _duration, bool _revocable)
      public
      TokenVesting(_beneficiary, _start, _cliff, _duration, _revocable) {
        //require(period > 0);
    
        period = _period;
        previousRelease = now;
      }
    
      //overriding release function
      function release(ERC20Basic token) public {
        require(now >= previousRelease.add(period));
    
        uint256 unreleased = releasableAmount(token);
    
        require(unreleased > 0);
    
        released[token] = released[token].add(unreleased);
    
        token.safeTransfer(beneficiary, unreleased);
    
        previousRelease = now;
    
        emit Released(unreleased);
      }
    
    }
    
    // File: contracts/CappedCrowdsale.sol
    
    contract CappedCrowdsale is Crowdsale, Ownable {
    
    
      using SafeMath for uint256;
    
      uint256 public hardCap;
      bool public isFinalized = false;
    
      //vesting
      uint256 public vestingTokens;
      uint256 public vestingDuration;
      uint256 public vestingPeriod;
      address public vestingBeneficiary;
      GambioVesting public vesting;
    
      event Finalized();
      event FinishMinting();
    
      event TokensMinted(
        address indexed beneficiary,
        uint256 indexed amount
      );
    
      constructor(uint256 _hardCap, uint256[] _vestingData, address _beneficiary)
      public {
    
        require(_vestingData.length == 3);
        require(_hardCap > 0);
        require(_vestingData[0] > 0);
        require(_vestingData[1] > 0);
        require(_vestingData[2] > 0);
        require(_beneficiary != address(0));
    
        hardCap = _hardCap;
        vestingTokens = _vestingData[0];
        vestingDuration = _vestingData[1];
        vestingPeriod = _vestingData[2];
        vestingBeneficiary = _beneficiary;
      }
    
      /**
         * @dev Must be called after crowdsale ends, to do some extra finalization
         * work. Calls the contract's finalization function.
         */
      function finalize() public onlyOwner {
        require(!isFinalized);
    
        vesting = new GambioVesting(vestingPeriod, vestingBeneficiary, now, 0, vestingDuration, false);
    
        token.mint(address(vesting), vestingTokens);
    
        emit Finalized();
        isFinalized = true;
      }
    
      function finishMinting() public onlyOwner {
        require(token.mintingFinished() == false);
        require(isFinalized);
        token.finishMinting();
    
        emit FinishMinting();
      }
    
      function mint(address beneficiary, uint256 amount) public onlyOwner {
        require(!token.mintingFinished());
        require(isFinalized);
        require(amount > 0);
        require(beneficiary != address(0));
        token.mint(beneficiary, amount);
    
        emit TokensMinted(beneficiary, amount);
      }
    
      // overriding Crowdsale#hasEnded to add cap logic
      // @return true if crowdsale event has ended
      function hasEnded() public view returns (bool) {
        bool capReached = weiRaised >= hardCap;
        return super.hasEnded() || capReached || isFinalized;
      }
    
    }
    
    // File: contracts/OnlyWhiteListedAddresses.sol
    
    contract OnlyWhiteListedAddresses is Ownable {
    
    
      using SafeMath for uint256;
      address utilityAccount;
      mapping(address => bool) whitelist;
      mapping(address => address) public referrals;
    
      modifier onlyOwnerOrUtility() {
        require(msg.sender == owner || msg.sender == utilityAccount);
        _;
      }
    
      event WhitelistedAddresses(
        address[] users
      );
    
      event ReferralsAdded(
        address[] user,
        address[] referral
      );
    
      constructor(address _utilityAccount) public {
        utilityAccount = _utilityAccount;
      }
    
      function whitelistAddress(address[] users) public onlyOwnerOrUtility {
        for (uint i = 0; i < users.length; i++) {
          whitelist[users[i]] = true;
        }
        emit WhitelistedAddresses(users);
      }
    
      function addAddressReferrals(address[] users, address[] _referrals) public onlyOwnerOrUtility {
        require(users.length == _referrals.length);
        for (uint i = 0; i < users.length; i++) {
          require(isWhiteListedAddress(users[i]));
    
          referrals[users[i]] = _referrals[i];
        }
        emit ReferralsAdded(users, _referrals);
      }
    
      function isWhiteListedAddress(address addr) public view returns (bool) {
        return whitelist[addr];
      }
    }
    
    // File: contracts/GambioCrowdsale.sol
    
    contract GambioCrowdsale is CappedCrowdsale, OnlyWhiteListedAddresses {
      using SafeMath for uint256;
    
      struct TokenPurchaseRecord {
        uint256 timestamp;
        uint256 weiAmount;
        address beneficiary;
      }
    
      uint256 transactionId = 1;
    
      mapping(uint256 => TokenPurchaseRecord) pendingTransactions;
    
      mapping(uint256 => bool) completedTransactions;
    
      uint256 public referralPercentage;
    
      uint256 public individualCap;
    
      /**
       * event for token purchase logging
       * @param transactionId transaction identifier
       * @param beneficiary who will get the tokens
       * @param timestamp when the token purchase request was made
       * @param weiAmount wei invested
       */
      event TokenPurchaseRequest(
        uint256 indexed transactionId,
        address beneficiary,
        uint256 indexed timestamp,
        uint256 indexed weiAmount,
        uint256 tokensAmount
      );
    
      event ReferralTokensSent(
        address indexed beneficiary,
        uint256 indexed tokensAmount,
        uint256 indexed transactionId
      );
    
      event BonusTokensSent(
        address indexed beneficiary,
        uint256 indexed tokensAmount,
        uint256 indexed transactionId
      );
    
      constructor(
        uint256 _startTime,
        uint256 _endTime,
        uint256 _icoHardCapWei,
        uint256 _referralPercentage,
        uint256 _rate,
        address _wallet,
        uint256 _privateWeiRaised,
        uint256 _individualCap,
        address _utilityAccount,
        uint256 _tokenCap,
        uint256[] _vestingData
      )
      public
      OnlyWhiteListedAddresses(_utilityAccount)
      CappedCrowdsale(_icoHardCapWei, _vestingData, _wallet)
      Crowdsale(_startTime, _endTime, _rate, _wallet, _privateWeiRaised, _tokenCap)
      {
        referralPercentage = _referralPercentage;
        individualCap = _individualCap;
      }
    
      // fallback function can be used to buy tokens
      function() external payable {
        buyTokens(msg.sender);
      }
    
      // low level token purchase function
      function buyTokens(address beneficiary) public payable {
        require(!isFinalized);
        require(beneficiary == msg.sender);
        require(msg.value != 0);
        require(msg.value >= individualCap);
    
        uint256 weiAmount = msg.value;
        require(isWhiteListedAddress(beneficiary));
        require(validPurchase(weiAmount));
    
        // update state
        weiRaised = weiRaised.add(weiAmount);
    
        uint256 _transactionId = transactionId;
        uint256 tokensAmount = weiAmount.mul(rate);
    
        pendingTransactions[_transactionId] = TokenPurchaseRecord(now, weiAmount, beneficiary);
        transactionId += 1;
    
    
        emit TokenPurchaseRequest(_transactionId, beneficiary, now, weiAmount, tokensAmount);
        forwardFunds();
      }
    
      function delayIcoEnd(uint256 newDate) public onlyOwner {
        require(newDate != 0);
        require(newDate > now);
        require(!hasEnded());
        require(newDate > endTime);
    
        endTime = newDate;
      }
    
      function increaseWeiRaised(uint256 amount) public onlyOwner {
        require(now < startTime);
        require(amount > 0);
        require(weiRaised.add(amount) <= hardCap);
    
        weiRaised = weiRaised.add(amount);
      }
    
      function decreaseWeiRaised(uint256 amount) public onlyOwner {
        require(now < startTime);
        require(amount > 0);
        require(weiRaised > 0);
        require(weiRaised >= amount);
    
        weiRaised = weiRaised.sub(amount);
      }
    
      function issueTokensMultiple(uint256[] _transactionIds, uint256[] bonusTokensAmounts) public onlyOwner {
        require(isFinalized);
        require(_transactionIds.length == bonusTokensAmounts.length);
        for (uint i = 0; i < _transactionIds.length; i++) {
          issueTokens(_transactionIds[i], bonusTokensAmounts[i]);
        }
      }
    
      function issueTokens(uint256 _transactionId, uint256 bonusTokensAmount) internal {
        require(completedTransactions[_transactionId] != true);
        require(pendingTransactions[_transactionId].timestamp != 0);
    
        TokenPurchaseRecord memory record = pendingTransactions[_transactionId];
        uint256 tokens = record.weiAmount.mul(rate);
        address referralAddress = referrals[record.beneficiary];
    
        token.mint(record.beneficiary, tokens);
        emit TokenPurchase(record.beneficiary, record.weiAmount, tokens, _transactionId);
    
        completedTransactions[_transactionId] = true;
    
        if (bonusTokensAmount != 0) {
          require(bonusTokensAmount != 0);
          token.mint(record.beneficiary, bonusTokensAmount);
          emit BonusTokensSent(record.beneficiary, bonusTokensAmount, _transactionId);
        }
    
        if (referralAddress != address(0)) {
          uint256 referralAmount = tokens.mul(referralPercentage).div(uint256(100));
          token.mint(referralAddress, referralAmount);
          emit ReferralTokensSent(referralAddress, referralAmount, _transactionId);
        }
      }
    
      function validPurchase(uint256 weiAmount) internal view returns (bool) {
        bool withinCap = weiRaised.add(weiAmount) <= hardCap;
        bool withinCrowdsaleInterval = now >= startTime && now <= endTime;
        return withinCrowdsaleInterval && withinCap;
      }
    
      function forwardFunds() internal {
        wallet.transfer(msg.value);
      }
    }
    
    // File: contracts/Migrations.sol
    
    contract Migrations {
    
    
      address public owner;
      uint public lastCompletedMigration;
    
      modifier restricted() {
        if (msg.sender == owner) _;
      }
    
      constructor() public {
        owner = msg.sender;
      }
    
      function setCompleted(uint completed) public restricted {
        lastCompletedMigration = completed;
      }
    
      function upgrade(address newAddress) public restricted {
        Migrations upgraded = Migrations(newAddress);
        upgraded.setCompleted(lastCompletedMigration);
      }
    }

    File 2 of 2: MultiSigWalletWithDailyLimit
    contract Factory {
    
        /*
         *  Events
         */
        event ContractInstantiation(address sender, address instantiation);
    
        /*
         *  Storage
         */
        mapping(address => bool) public isInstantiation;
        mapping(address => address[]) public instantiations;
    
        /*
         * Public functions
         */
        /// @dev Returns number of instantiations by creator.
        /// @param creator Contract creator.
        /// @return Returns number of instantiations by creator.
        function getInstantiationCount(address creator)
            public
            constant
            returns (uint)
        {
            return instantiations[creator].length;
        }
    
        /*
         * Internal functions
         */
        /// @dev Registers contract in factory registry.
        /// @param instantiation Address of contract instantiation.
        function register(address instantiation)
            internal
        {
            isInstantiation[instantiation] = true;
            instantiations[msg.sender].push(instantiation);
            ContractInstantiation(msg.sender, instantiation);
        }
    }
    
    /// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution.
    /// @author Stefan George - <[email protected]>
    contract MultiSigWallet {
    
        /*
         *  Events
         */
        event Confirmation(address indexed sender, uint indexed transactionId);
        event Revocation(address indexed sender, uint indexed transactionId);
        event Submission(uint indexed transactionId);
        event Execution(uint indexed transactionId);
        event ExecutionFailure(uint indexed transactionId);
        event Deposit(address indexed sender, uint value);
        event OwnerAddition(address indexed owner);
        event OwnerRemoval(address indexed owner);
        event RequirementChange(uint required);
    
        /*
         *  Constants
         */
        uint constant public MAX_OWNER_COUNT = 50;
    
        /*
         *  Storage
         */
        mapping (uint => Transaction) public transactions;
        mapping (uint => mapping (address => bool)) public confirmations;
        mapping (address => bool) public isOwner;
        address[] public owners;
        uint public required;
        uint public transactionCount;
    
        struct Transaction {
            address destination;
            uint value;
            bytes data;
            bool executed;
        }
    
        /*
         *  Modifiers
         */
        modifier onlyWallet() {
            require(msg.sender == address(this));
            _;
        }
    
        modifier ownerDoesNotExist(address owner) {
            require(!isOwner[owner]);
            _;
        }
    
        modifier ownerExists(address owner) {
            require(isOwner[owner]);
            _;
        }
    
        modifier transactionExists(uint transactionId) {
            require(transactions[transactionId].destination != 0);
            _;
        }
    
        modifier confirmed(uint transactionId, address owner) {
            require(confirmations[transactionId][owner]);
            _;
        }
    
        modifier notConfirmed(uint transactionId, address owner) {
            require(!confirmations[transactionId][owner]);
            _;
        }
    
        modifier notExecuted(uint transactionId) {
            require(!transactions[transactionId].executed);
            _;
        }
    
        modifier notNull(address _address) {
            require(_address != 0);
            _;
        }
    
        modifier validRequirement(uint ownerCount, uint _required) {
            require(ownerCount <= MAX_OWNER_COUNT
                && _required <= ownerCount
                && _required != 0
                && ownerCount != 0);
            _;
        }
    
        /// @dev Fallback function allows to deposit ether.
        function()
            payable
        {
            if (msg.value > 0)
                Deposit(msg.sender, msg.value);
        }
    
        /*
         * Public functions
         */
        /// @dev Contract constructor sets initial owners and required number of confirmations.
        /// @param _owners List of initial owners.
        /// @param _required Number of required confirmations.
        function MultiSigWallet(address[] _owners, uint _required)
            public
            validRequirement(_owners.length, _required)
        {
            for (uint i=0; i<_owners.length; i++) {
                require(!isOwner[_owners[i]] && _owners[i] != 0);
                isOwner[_owners[i]] = true;
            }
            owners = _owners;
            required = _required;
        }
    
        /// @dev Allows to add a new owner. Transaction has to be sent by wallet.
        /// @param owner Address of new owner.
        function addOwner(address owner)
            public
            onlyWallet
            ownerDoesNotExist(owner)
            notNull(owner)
            validRequirement(owners.length + 1, required)
        {
            isOwner[owner] = true;
            owners.push(owner);
            OwnerAddition(owner);
        }
    
        /// @dev Allows to remove an owner. Transaction has to be sent by wallet.
        /// @param owner Address of owner.
        function removeOwner(address owner)
            public
            onlyWallet
            ownerExists(owner)
        {
            isOwner[owner] = false;
            for (uint i=0; i<owners.length - 1; i++)
                if (owners[i] == owner) {
                    owners[i] = owners[owners.length - 1];
                    break;
                }
            owners.length -= 1;
            if (required > owners.length)
                changeRequirement(owners.length);
            OwnerRemoval(owner);
        }
    
        /// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet.
        /// @param owner Address of owner to be replaced.
        /// @param newOwner Address of new owner.
        function replaceOwner(address owner, address newOwner)
            public
            onlyWallet
            ownerExists(owner)
            ownerDoesNotExist(newOwner)
        {
            for (uint i=0; i<owners.length; i++)
                if (owners[i] == owner) {
                    owners[i] = newOwner;
                    break;
                }
            isOwner[owner] = false;
            isOwner[newOwner] = true;
            OwnerRemoval(owner);
            OwnerAddition(newOwner);
        }
    
        /// @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet.
        /// @param _required Number of required confirmations.
        function changeRequirement(uint _required)
            public
            onlyWallet
            validRequirement(owners.length, _required)
        {
            required = _required;
            RequirementChange(_required);
        }
    
        /// @dev Allows an owner to submit and confirm a transaction.
        /// @param destination Transaction target address.
        /// @param value Transaction ether value.
        /// @param data Transaction data payload.
        /// @return Returns transaction ID.
        function submitTransaction(address destination, uint value, bytes data)
            public
            returns (uint transactionId)
        {
            transactionId = addTransaction(destination, value, data);
            confirmTransaction(transactionId);
        }
    
        /// @dev Allows an owner to confirm a transaction.
        /// @param transactionId Transaction ID.
        function confirmTransaction(uint transactionId)
            public
            ownerExists(msg.sender)
            transactionExists(transactionId)
            notConfirmed(transactionId, msg.sender)
        {
            confirmations[transactionId][msg.sender] = true;
            Confirmation(msg.sender, transactionId);
            executeTransaction(transactionId);
        }
    
        /// @dev Allows an owner to revoke a confirmation for a transaction.
        /// @param transactionId Transaction ID.
        function revokeConfirmation(uint transactionId)
            public
            ownerExists(msg.sender)
            confirmed(transactionId, msg.sender)
            notExecuted(transactionId)
        {
            confirmations[transactionId][msg.sender] = false;
            Revocation(msg.sender, transactionId);
        }
    
        /// @dev Allows anyone to execute a confirmed transaction.
        /// @param transactionId Transaction ID.
        function executeTransaction(uint transactionId)
            public
            ownerExists(msg.sender)
            confirmed(transactionId, msg.sender)
            notExecuted(transactionId)
        {
            if (isConfirmed(transactionId)) {
                Transaction storage txn = transactions[transactionId];
                txn.executed = true;
                if (txn.destination.call.value(txn.value)(txn.data))
                    Execution(transactionId);
                else {
                    ExecutionFailure(transactionId);
                    txn.executed = false;
                }
            }
        }
    
        /// @dev Returns the confirmation status of a transaction.
        /// @param transactionId Transaction ID.
        /// @return Confirmation status.
        function isConfirmed(uint transactionId)
            public
            constant
            returns (bool)
        {
            uint count = 0;
            for (uint i=0; i<owners.length; i++) {
                if (confirmations[transactionId][owners[i]])
                    count += 1;
                if (count == required)
                    return true;
            }
        }
    
        /*
         * Internal functions
         */
        /// @dev Adds a new transaction to the transaction mapping, if transaction does not exist yet.
        /// @param destination Transaction target address.
        /// @param value Transaction ether value.
        /// @param data Transaction data payload.
        /// @return Returns transaction ID.
        function addTransaction(address destination, uint value, bytes data)
            internal
            notNull(destination)
            returns (uint transactionId)
        {
            transactionId = transactionCount;
            transactions[transactionId] = Transaction({
                destination: destination,
                value: value,
                data: data,
                executed: false
            });
            transactionCount += 1;
            Submission(transactionId);
        }
    
        /*
         * Web3 call functions
         */
        /// @dev Returns number of confirmations of a transaction.
        /// @param transactionId Transaction ID.
        /// @return Number of confirmations.
        function getConfirmationCount(uint transactionId)
            public
            constant
            returns (uint count)
        {
            for (uint i=0; i<owners.length; i++)
                if (confirmations[transactionId][owners[i]])
                    count += 1;
        }
    
        /// @dev Returns total number of transactions after filers are applied.
        /// @param pending Include pending transactions.
        /// @param executed Include executed transactions.
        /// @return Total number of transactions after filters are applied.
        function getTransactionCount(bool pending, bool executed)
            public
            constant
            returns (uint count)
        {
            for (uint i=0; i<transactionCount; i++)
                if (   pending && !transactions[i].executed
                    || executed && transactions[i].executed)
                    count += 1;
        }
    
        /// @dev Returns list of owners.
        /// @return List of owner addresses.
        function getOwners()
            public
            constant
            returns (address[])
        {
            return owners;
        }
    
        /// @dev Returns array with owner addresses, which confirmed transaction.
        /// @param transactionId Transaction ID.
        /// @return Returns array of owner addresses.
        function getConfirmations(uint transactionId)
            public
            constant
            returns (address[] _confirmations)
        {
            address[] memory confirmationsTemp = new address[](owners.length);
            uint count = 0;
            uint i;
            for (i=0; i<owners.length; i++)
                if (confirmations[transactionId][owners[i]]) {
                    confirmationsTemp[count] = owners[i];
                    count += 1;
                }
            _confirmations = new address[](count);
            for (i=0; i<count; i++)
                _confirmations[i] = confirmationsTemp[i];
        }
    
        /// @dev Returns list of transaction IDs in defined range.
        /// @param from Index start position of transaction array.
        /// @param to Index end position of transaction array.
        /// @param pending Include pending transactions.
        /// @param executed Include executed transactions.
        /// @return Returns array of transaction IDs.
        function getTransactionIds(uint from, uint to, bool pending, bool executed)
            public
            constant
            returns (uint[] _transactionIds)
        {
            uint[] memory transactionIdsTemp = new uint[](transactionCount);
            uint count = 0;
            uint i;
            for (i=0; i<transactionCount; i++)
                if (   pending && !transactions[i].executed
                    || executed && transactions[i].executed)
                {
                    transactionIdsTemp[count] = i;
                    count += 1;
                }
            _transactionIds = new uint[](to - from);
            for (i=from; i<to; i++)
                _transactionIds[i - from] = transactionIdsTemp[i];
        }
    }
    
    /// @title Multisignature wallet with daily limit - Allows an owner to withdraw a daily limit without multisig.
    /// @author Stefan George - <[email protected]>
    contract MultiSigWalletWithDailyLimit is MultiSigWallet {
    
        /*
         *  Events
         */
        event DailyLimitChange(uint dailyLimit);
    
        /*
         *  Storage
         */
        uint public dailyLimit;
        uint public lastDay;
        uint public spentToday;
    
        /*
         * Public functions
         */
        /// @dev Contract constructor sets initial owners, required number of confirmations and daily withdraw limit.
        /// @param _owners List of initial owners.
        /// @param _required Number of required confirmations.
        /// @param _dailyLimit Amount in wei, which can be withdrawn without confirmations on a daily basis.
        function MultiSigWalletWithDailyLimit(address[] _owners, uint _required, uint _dailyLimit)
            public
            MultiSigWallet(_owners, _required)
        {
            dailyLimit = _dailyLimit;
        }
    
        /// @dev Allows to change the daily limit. Transaction has to be sent by wallet.
        /// @param _dailyLimit Amount in wei.
        function changeDailyLimit(uint _dailyLimit)
            public
            onlyWallet
        {
            dailyLimit = _dailyLimit;
            DailyLimitChange(_dailyLimit);
        }
    
        /// @dev Allows anyone to execute a confirmed transaction or ether withdraws until daily limit is reached.
        /// @param transactionId Transaction ID.
        function executeTransaction(uint transactionId)
            public
            ownerExists(msg.sender)
            confirmed(transactionId, msg.sender)
            notExecuted(transactionId)
        {
            Transaction storage txn = transactions[transactionId];
            bool _confirmed = isConfirmed(transactionId);
            if (_confirmed || txn.data.length == 0 && isUnderLimit(txn.value)) {
                txn.executed = true;
                if (!_confirmed)
                    spentToday += txn.value;
                if (txn.destination.call.value(txn.value)(txn.data))
                    Execution(transactionId);
                else {
                    ExecutionFailure(transactionId);
                    txn.executed = false;
                    if (!_confirmed)
                        spentToday -= txn.value;
                }
            }
        }
    
        /*
         * Internal functions
         */
        /// @dev Returns if amount is within daily limit and resets spentToday after one day.
        /// @param amount Amount to withdraw.
        /// @return Returns if amount is under daily limit.
        function isUnderLimit(uint amount)
            internal
            returns (bool)
        {
            if (now > lastDay + 24 hours) {
                lastDay = now;
                spentToday = 0;
            }
            if (spentToday + amount > dailyLimit || spentToday + amount < spentToday)
                return false;
            return true;
        }
    
        /*
         * Web3 call functions
         */
        /// @dev Returns maximum withdraw amount.
        /// @return Returns amount.
        function calcMaxWithdraw()
            public
            constant
            returns (uint)
        {
            if (now > lastDay + 24 hours)
                return dailyLimit;
            if (dailyLimit < spentToday)
                return 0;
            return dailyLimit - spentToday;
        }
    }