ETH Price: $1,860.64 (-0.44%)
 

Overview

ETH Balance

6.4 ETH

Eth Value

$11,908.12 (@ $1,860.64/ETH)

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Request Payment98469902020-04-10 21:35:301796 days ago1586554530IN
0xbf6969F5...6D28d387F
6.4 ETH0.0013086610
Transfer98194352020-04-06 15:54:311800 days ago1586188471IN
0xbf6969F5...6D28d387F
1.34102185 ETH0.0004911723.33793445
Create Order97718832020-03-30 8:11:591807 days ago1585555919IN
0xbf6969F5...6D28d387F
0 ETH0.0097163928
Request Payment97537472020-03-27 13:31:301810 days ago1585315890IN
0xbf6969F5...6D28d387F
1.7 ETH0.0013088610
Create Order97335422020-03-24 10:01:561813 days ago1585044116IN
0xbf6969F5...6D28d387F
0 ETH0.0079633928
Request Payment97231672020-03-22 19:17:401815 days ago1584904660IN
0xbf6969F5...6D28d387F
3.98 ETH0.0013086610
Create Order96504292020-03-11 13:18:011826 days ago1583932681IN
0xbf6969F5...6D28d387F
0 ETH0.0075428328
Request Payment96137782020-03-05 22:04:411832 days ago1583445881IN
0xbf6969F5...6D28d387F
2.6758 ETH0.0013086610
Create Order96106812020-03-05 10:28:501832 days ago1583404130IN
0xbf6969F5...6D28d387F
0 ETH0.0097169528
Request Payment95923812020-03-02 14:51:451835 days ago1583160705IN
0xbf6969F5...6D28d387F
0.54 ETH0.0013088610
Create Order95140352020-02-19 13:58:121847 days ago1582120692IN
0xbf6969F5...6D28d387F
0 ETH0.0017554828
Create Order95140342020-02-19 13:57:481847 days ago1582120668IN
0xbf6969F5...6D28d387F
0 ETH0.0097169528
Request Payment95058272020-02-18 7:46:171848 days ago1582011977IN
0xbf6969F5...6D28d387F
2.0075 ETH0.0013086610
Create Order94813122020-02-14 13:11:471852 days ago1581685907IN
0xbf6969F5...6D28d387F
0 ETH0.0017554828
Create Order94813122020-02-14 13:11:471852 days ago1581685907IN
0xbf6969F5...6D28d387F
0 ETH0.0076379528
Create Order94813082020-02-14 13:11:031852 days ago1581685863IN
0xbf6969F5...6D28d387F
0 ETH0.0097169528
Create Order94813032020-02-14 13:09:501852 days ago1581685790IN
0xbf6969F5...6D28d387F
0 ETH0.0017633228
Create Order94813032020-02-14 13:09:501852 days ago1581685790IN
0xbf6969F5...6D28d387F
0 ETH0.0075428328
Request Payment94671502020-02-12 8:42:431854 days ago1581496963IN
0xbf6969F5...6D28d387F
6.08 ETH0.0013426310
Request Payment94568142020-02-10 18:34:091856 days ago1581359649IN
0xbf6969F5...6D28d387F
1.6 ETH0.0013086610
Request Payment94359792020-02-07 14:04:041859 days ago1581084244IN
0xbf6969F5...6D28d387F
1.003 ETH0.000392653
Transfer93691272020-01-28 7:15:331869 days ago1580195733IN
0xbf6969F5...6D28d387F
0.34192663 ETH0.000042092
Create Order93331532020-01-22 18:53:291875 days ago1579719209IN
0xbf6969F5...6D28d387F
0 ETH0.0097169528
Request Payment93250982020-01-21 13:27:261876 days ago1579613246IN
0xbf6969F5...6D28d387F
1 ETH0.0013088610
Create Order92391542020-01-08 9:16:231889 days ago1578474983IN
0xbf6969F5...6D28d387F
0 ETH0.0017554828
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
-97718832020-03-30 8:11:591807 days ago1585555919
0xbf6969F5...6D28d387F
1.7 ETH
-97335422020-03-24 10:01:561813 days ago1585044116
0xbf6969F5...6D28d387F
3.98 ETH
-96504292020-03-11 13:18:011826 days ago1583932681
0xbf6969F5...6D28d387F
2.6758 ETH
-96106812020-03-05 10:28:501832 days ago1583404130
0xbf6969F5...6D28d387F
0.54 ETH
-95140342020-02-19 13:57:481847 days ago1582120668
0xbf6969F5...6D28d387F
2.0075 ETH
-94813122020-02-14 13:11:471852 days ago1581685907
0xbf6969F5...6D28d387F
6.08 ETH
-94813082020-02-14 13:11:031852 days ago1581685863
0xbf6969F5...6D28d387F
1.6 ETH
-94813032020-02-14 13:09:501852 days ago1581685790
0xbf6969F5...6D28d387F
1.003 ETH
-93331532020-01-22 18:53:291875 days ago1579719209
0xbf6969F5...6D28d387F
1 ETH
-92391532020-01-08 9:16:111889 days ago1578474971
0xbf6969F5...6D28d387F
4.7 ETH
-90426422019-12-03 8:15:131925 days ago1575360913
0xbf6969F5...6D28d387F
0.75 ETH
-90087652019-11-27 8:03:171931 days ago1574841797
0xbf6969F5...6D28d387F
3.9 ETH
-89792132019-11-22 7:48:361936 days ago1574408916
0xbf6969F5...6D28d387F
1.94 ETH
-89311992019-11-14 7:35:201944 days ago1573716920
0xbf6969F5...6D28d387F
0.64 ETH
-89192012019-11-12 7:43:101946 days ago1573544590
0xbf6969F5...6D28d387F
1 ETH
-89139092019-11-11 10:35:161947 days ago1573468516
0xbf6969F5...6D28d387F
6.56696 ETH
-89133732019-11-11 8:29:501947 days ago1573460990
0xbf6969F5...6D28d387F
0.6 ETH
-88451842019-10-31 7:30:191958 days ago1572507019
0xbf6969F5...6D28d387F
1 ETH
-88268302019-10-28 8:48:161961 days ago1572252496
0xbf6969F5...6D28d387F
0.6 ETH
-86486562019-09-30 6:58:411989 days ago1569826721
0xbf6969F5...6D28d387F
1 ETH
-85782992019-09-19 6:52:462000 days ago1568875966
0xbf6969F5...6D28d387F
12.9758 ETH
-85654712019-09-17 6:46:002002 days ago1568702760
0xbf6969F5...6D28d387F
1.3758 ETH
-85333692019-09-12 6:49:152007 days ago1568270955
0xbf6969F5...6D28d387F
1.3024 ETH
-84062072019-08-23 11:14:222027 days ago1566558862
0xbf6969F5...6D28d387F
0.99 ETH
-83985312019-08-22 6:39:412028 days ago1566455981
0xbf6969F5...6D28d387F
1.998 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CrowdliExchangeVault

Compiler Version
v0.5.0+commit.1d4f565a

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Multiple files format)

File 1 of 22: CrowdliExchangeVault.sol
pragma solidity 0.5.0;

import "./CrowdliSTO.sol";
import "./Ownable.sol";
import "./SafeMath.sol";
import "./Pausable.sol";

/**
* This contract can be in one of the following states:
* - Active      The contract is open to new payment requests
* - Closed      No new payments will be accepted nor payments can be rejected though refunds can be claimed for payments that had been prior to closing.
*/
contract CrowdliExchangeVault is Ownable, Pausable {

    struct EtherPayment {
        address from;
        uint64 date;
        PaymentStatus status;
        uint weiAmount;
        uint pendingTokens;
        uint mintedTokens;
        uint exchangeRate;
    }

    struct ExchangeOrder {
        uint256 exchangeRate;
        uint64 date;
        address exchangeWallet;
        ExchangeStatus status;
    }
    
    /**
     * Defines the statuses an exchange order can have
     */
    enum ExchangeStatus { Pending, Confirmed }

    /**
    * Defines the statuses an payment can have
    */
    enum PaymentStatus { None, Requested, Accepted, TokensDelivered, Rejected, Refunded, PurchaseFailed }
    
    /**
    * The safe math library for safety math operations provided by Zeppelin
    */
    using SafeMath for uint256;

    /**
    * Holds all exchange orders, each of them containing multiple payments
    */
   	ExchangeOrder[] public exchangeOrders;
   
    /**
    * Holds all ether payments in different states (PaymentStatu
    */
    EtherPayment[] public payments;
    
    /**
     * A dictionary holind the number of requested payment per investor
     */
    mapping(address => uint) public nrRequestedPayments; 
    
    /**
     * A dictionary to lookup the related payments (paymentsIds: uint[]) for a given exchange order (exchangeOrderId: uint)
     */
    mapping(uint => uint[]) private exchangeOrderForPayments; //exchangeOrderId => array of paymentsIds
    
    
    address public paymentConfirmer;
    
    /**
     * Used to process payments once they are confirmed 
     */
    CrowdliSTO private crowdliSTO;
    
     /**
     * Event will be fired whenever payments processing is enabled
     * @param sender The account that has enabled the payment processing
     */
    event PaymentsEnabled(address indexed sender);
    
    /**
     * Event will be fired whenever payments processing is disabled
     * @param sender The account that has disabled the payment processing
     */
    event PaymentsDisabled(address indexed sender);
    event EtherPaymentRefunded(address indexed beneficiary, uint256 weiAmount);
    event EtherPaymentRequested(address indexed beneficiary, uint256 weiAmount, uint paymentIndex);
    event EtherPaymentRejected(address indexed sender, uint etherPaymentIndex);
    event LogGasUsed(address indexed sender, uint indexed value);
    event EtherPaymentPurchaseFailed(address indexed sender, uint indexed etherPaymentIndex);
    event OrderCreated(address indexed sender, uint[] payments);
    event OrderConfirmed(address indexed sender, uint indexed etherPaymentIndex);

	modifier isInInvestmentState() {
         require(crowdliSTO.hasState(CrowdliSTO.States.Investment) || !crowdliSTO.paused(), "bot in state investment");
        _;
    }

    modifier onlyCrowdliSTO() {
        require((msg.sender == address(crowdliSTO)), "Sender should be CrowdliSTO");
        _;
    }
    
    modifier onlyEtherPaymentConfirmer() {
        require((msg.sender == paymentConfirmer), "Sender should be EtherPaymentConfirmer");
        _;
    }
    
    constructor(address _paymentConfirmer) public {
        paymentConfirmer = _paymentConfirmer; 
    }
    
	function setCrowdliSTO(CrowdliSTO _crowdliSTO) external onlyOwner {
    	crowdliSTO = _crowdliSTO;
    }

	function initExchangeVault(address _directorsBoard, address _crowdliSTO) external onlyOwner{
    	crowdliSTO = CrowdliSTO(_crowdliSTO);
    	transferOwnership(_crowdliSTO);
    	addPauser(_directorsBoard);
    	addPauser(_crowdliSTO);
    }
    
    function confirmMintedTokensForPayment(uint paymentId, uint _mintedTokens) external onlyOwner {
        payments[paymentId].mintedTokens = payments[paymentId].mintedTokens.add(_mintedTokens);
    }
    /**
    * @dev The ether provided by the investor will be collected for a new fiat exchange order will be triggered by the owner
    * @dev Since the exact conversion rate that will be used for the fiat exchange is unknown the tokens will be minted AFTER once the order is completed
    */

    function requestPayment() external whenNotPaused payable  {
        uint[] memory tokenStatement = crowdliSTO.calculateTokenStatementEther(msg.sender, msg.value, CrowdliSTO.Currency.ETH, false, 0); 
        // only process if validation code == OK
        require(CrowdliSTO.TokenStatementValidation(tokenStatement[8]) == CrowdliSTO.TokenStatementValidation.OK, crowdliSTO.resolvePaymentError(CrowdliSTO.TokenStatementValidation(tokenStatement[8])));
        
        payments.push(EtherPayment(msg.sender, uint64(now), PaymentStatus.Requested, msg.value, 0, 0, 0));
        nrRequestedPayments[msg.sender] = nrRequestedPayments[msg.sender].add(1);
        emit EtherPaymentRequested(msg.sender, msg.value, payments.length.sub(1));
    }
    
    /**
    * @dev An investor can be subsequently rejected if the AML and PEP checks were negative
    */
    function rejectPayment(uint[] calldata _paymentIds) external onlyEtherPaymentConfirmer {
        for(uint id = 0; id < _paymentIds.length; id++){
        	uint paymentId = _paymentIds[id];
            // we only allow payments that have not been confirmed, rejected or refunded yet
            require(payments[paymentId].status == PaymentStatus.Requested, "Payment must be in state Requested");
    
            // mark ether payment as rejected and therby allowing the investor to claim refund
            payments[paymentId].status = PaymentStatus.Rejected;
            
            nrRequestedPayments[payments[paymentId].from] = nrRequestedPayments[payments[paymentId].from].sub(1);
            // fire an event so the investor can be informed that his payment was rejected
            emit EtherPaymentRejected(payments[paymentId].from, paymentId);
        }
    }

    /**
    * @dev Once an investor has been rejected a refund can be claimed
    */
    function refundPayment(uint index) external {
    
        EtherPayment storage etherPayment = payments[index];
        uint256 depositedValue = etherPayment.weiAmount;

        // only allow refund for payments which have been rejected 
        require((etherPayment.from == msg.sender) || (msg.sender == paymentConfirmer), "Refund are not enabled for sender");
        require(etherPayment.status == PaymentStatus.Rejected , "etherPayment.status should be PaymentStatus.Rejected");
		require(address(this).balance >= depositedValue , "Exchange Vault balance doesn't have enough funds.");
        // mark ether payment status to refunded
        etherPayment.status = PaymentStatus.Refunded;

        // send the ether back to investors address
        msg.sender.transfer(depositedValue);

        emit EtherPaymentRefunded(msg.sender, depositedValue);
    }

    /**
     * @param _exchangeWallet The wallet of the exchange provider where the ether will be sent for FIAT exchange
     */
    function createOrder(address payable _exchangeWallet, uint[] calldata _paymentsToAccept) external whenNotPaused onlyEtherPaymentConfirmer isInInvestmentState {
        require(payments.length > 0, "At least one payment is required to exchange");
        ExchangeOrder memory exchangeOrder = ExchangeOrder(0, uint64(now), _exchangeWallet, ExchangeStatus.Pending);
        exchangeOrders.push(exchangeOrder);
        uint weiAmountForTransfering = 0;
        // iterate through all payments which are not assigned to an exchange order
       	uint[] storage orderForPaymentIds = exchangeOrderForPayments[exchangeOrders.length-1];
        for (uint64 i = 0; i < _paymentsToAccept.length; i++) {
            uint paymentId = _paymentsToAccept[i];
            EtherPayment storage etherPayment = payments[paymentId];
            require(etherPayment.status == PaymentStatus.Requested, "should be in status requested"); 
            etherPayment.status = PaymentStatus.Accepted;
            orderForPaymentIds.push(paymentId);
            processPayment(paymentId);
            weiAmountForTransfering = weiAmountForTransfering.add(etherPayment.weiAmount);
        }
        emit OrderCreated(msg.sender, orderForPaymentIds);
        _exchangeWallet.transfer(weiAmountForTransfering);
    }

	/**
	* buy tokens on behalf of the investor
	*/
	function processPayment(uint _paymentId) internal {
		EtherPayment storage etherPayment = payments[_paymentId];
	    nrRequestedPayments[etherPayment.from] = nrRequestedPayments[etherPayment.from].sub(1);
	    crowdliSTO.processEtherPayment(etherPayment.from, etherPayment.weiAmount, _paymentId);
	    etherPayment.status = PaymentStatus.TokensDelivered;
	    etherPayment.exchangeRate = crowdliSTO.exchangeRate();
    }
    
    function confirmOrder(uint64 _orderIndex, uint256 _exchangeRate) external whenNotPaused onlyEtherPaymentConfirmer {
        require(_orderIndex < exchangeOrders.length, "_orderIndex is too high");
        ExchangeOrder storage exchangeOrder = exchangeOrders[_orderIndex];
        require(exchangeOrder.status != ExchangeStatus.Confirmed, "exchangeOrder.status is confirmed");
        exchangeOrder.exchangeRate = _exchangeRate;
        exchangeOrder.status = ExchangeStatus.Confirmed;
    }
    
    function hasRequestedPayments(address _beneficiary) public view returns(bool) {
        return (nrRequestedPayments[_beneficiary] != 0);
    }    
        
    function getEtherPaymentsCount() external view returns(uint256) {
        return payments.length;
    }
    
    function getExchangeOrdersCount() external view returns(uint256) {
        return exchangeOrders.length;
    }
    
    function getExchangeOrdersToPayments(uint orderId) external view returns (uint[] memory) {
        return exchangeOrderForPayments[orderId];
    }     
    
}

File 2 of 22: Address.sol
pragma solidity ^0.5.0;

/**
 * @dev Collection of functions related to the address type,
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * This test is non-exhaustive, and there may be false-negatives: during the
     * execution of a contract's constructor, its address will be reported as
     * not containing a contract.
     *
     * > It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies in extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }
}

File 3 of 22: CapperRole.sol
pragma solidity ^0.5.0;

import "../Roles.sol";

contract CapperRole {
    using Roles for Roles.Role;

    event CapperAdded(address indexed account);
    event CapperRemoved(address indexed account);

    Roles.Role private _cappers;

    constructor () internal {
        _addCapper(msg.sender);
    }

    modifier onlyCapper() {
        require(isCapper(msg.sender), "CapperRole: caller does not have the Capper role");
        _;
    }

    function isCapper(address account) public view returns (bool) {
        return _cappers.has(account);
    }

    function addCapper(address account) public onlyCapper {
        _addCapper(account);
    }

    function renounceCapper() public {
        _removeCapper(msg.sender);
    }

    function _addCapper(address account) internal {
        _cappers.add(account);
        emit CapperAdded(account);
    }

    function _removeCapper(address account) internal {
        _cappers.remove(account);
        emit CapperRemoved(account);
    }
}

File 4 of 22: CrowdliKYCProvider.sol
pragma solidity 0.5.0;

import "./Pausable.sol";
import "./WhitelistAdminRole.sol";

contract CrowdliKYCProvider is Pausable, WhitelistAdminRole {

	/**
	 * The verification levels supported by this ICO
	 */
	enum VerificationTier { None, KYCAccepted, VideoVerified, ExternalTokenAgent } 
    
    /**
     * Defines the max. amount of tokens an investor can purchase for a given verification level (tier)
     */
	mapping (uint => uint) public maxTokenAmountPerTier; 
    
    /**
    * Dictionary that maps addresses to investors which have successfully been verified by the external KYC process
    */
    mapping (address => VerificationTier) public verificationTiers;

    /**
    * This event is fired when a user has been successfully verified by the external KYC verification process
    */
    event LogKYCConfirmation(address indexed sender, VerificationTier verificationTier);

	/**
	 * This constructor initializes a new  CrowdliKYCProvider initializing the provided token amount threshold for the supported verification tiers
	 */
    constructor(address _kycConfirmer, uint _maxTokenForKYCAcceptedTier, uint _maxTokensForVideoVerifiedTier, uint _maxTokensForExternalTokenAgent) public {
        addWhitelistAdmin(_kycConfirmer);
        // Max token amount for non-verified investors
        maxTokenAmountPerTier[uint(VerificationTier.None)] = 0;
        
        // Max token amount for auto KYC auto verified investors
        maxTokenAmountPerTier[uint(VerificationTier.KYCAccepted)] = _maxTokenForKYCAcceptedTier;
        
        // Max token amount for auto KYC video verified investors
        maxTokenAmountPerTier[uint(VerificationTier.VideoVerified)] = _maxTokensForVideoVerifiedTier;
        
        // Max token amount for external token sell providers
        maxTokenAmountPerTier[uint(VerificationTier.ExternalTokenAgent)] = _maxTokensForExternalTokenAgent;
    }

    function confirmKYC(address _addressId, VerificationTier _verificationTier) public onlyWhitelistAdmin whenNotPaused {
        emit LogKYCConfirmation(_addressId, _verificationTier);
        verificationTiers[_addressId] = _verificationTier;
    }

    function hasVerificationLevel(address _investor, VerificationTier _verificationTier) public view returns (bool) {
        return (verificationTiers[_investor] == _verificationTier);
    }
    
    function getMaxChfAmountForInvestor(address _investor) public view returns (uint) {
        return maxTokenAmountPerTier[uint(verificationTiers[_investor])];
    }    
}

File 5 of 22: CrowdliSTO.sol
pragma solidity 0.5.0;

import "./CrowdliToken.sol";
import "./CrowdliKYCProvider.sol";
import "./CrowdliExchangeVault.sol";
import "./Ownable.sol";
import "./Pausable.sol";
import "./SafeMath.sol";

/**
 * @title Crowdli STO Contract
 */
contract CrowdliSTO is Pausable, Ownable {
    /**
     * The safe math library for safety math operations provided by Open Zeppelin
     */
    using SafeMath for uint;

    /**
     * Defines all states the STO can be in
     */
    enum States {
        PrepareInvestment,
        Investment,
        Finalizing,
        Finalized
    }

    struct InvestmentPhase {
        bytes32 label;
        bool allowManualSwitch;
        uint discountBPS;
        uint capAmount;
        uint tokensSoldAmount;
    }

    struct TokenAllocation {
        bytes32 label;
        AllocationActionType actionType;
        AllocationValueType valueType;
        uint valueAmount;
        address beneficiary;
        bool isAllocated;
    }

    struct TokenStatement {
        uint requestedBase;
        uint requestedCHF;
        uint feesCHF;
        uint currentPhaseDiscount;
        uint earlyBirdCreditTokenAmount;
        uint voucherCreditTokenAmount;
        uint currentPhaseTokenAmount;
        uint nextPhaseBaseAmount;
        TokenStatementValidation validationCode;
    }

    enum Currency {
        ETH,
        CHF,
        EUR
    }

    enum ExecutionType {
        SinglePayment,
        SplitPayment
    }

    enum AllocationActionType {
        POST_ALLOCATE
    }

    enum AllocationValueType {
        FIXED_TOKEN_AMOUNT,
        BPS_OF_TOKENS_SOLD
    }

    enum TokenStatementValidation {
        OK,
        BELOW_MIN_LIMIT,
        ABOVE_MAX_LIMIT,
        EXCEEDS_HARD_CAP
    }

    /**
     * This event is fired when a ether payment is confirmed by payment confirmer
     */
    event LogPaymentConfirmation(address indexed beneficiary, uint indexed investment, uint[] paymentDetails, uint id, Currency currency, ExecutionType executionType);
    /**
     * This event is fired when a new investment sub-phase is registered during the PrepareInvestment phase
     */
    event LogRegisterInvestmentPhase(address indexed sender, bool allowManualSwitch, bytes32 indexed label, uint indexed discountBPS, uint cap);

    /**
     * This event is fired when the start date is updated
     */
    event LogSaleStartUpdated(address indexed sender, uint indexed saleStartDate);

    /**
     * This event is fired whenever the CrowdliKYCProvider used for the STO is updated
     */
    event LogKYCProviderUpdated(address indexed sender, address indexed crowdliKycProvider);

    /**
     * This event is fired when the STO has started
     */
    event LogStarted(address indexed sender);

    /**
     * This event is fired when a new investment phase starts
     */
    event LogInvestmentPhaseSwitched(uint phaseIndex);

    /**
     * This event is fired when the STO closes
     */
    event LogEndDateExtended(address indexed sender, uint endDate);

    /**
     * This event is fired when the STO closes
     */
    event LogClosed(address indexed sender, bool stoSucessfull);

    /**
     * This event will be fired when the customer finalizes the STO
     */
    event LogFinalized(address indexed sender);

    /**
     * Whenever the state of the contract changes, this event will be fired.
     */
    event LogStateChanged(States _states);
    
    /**
     * Whenever the investor gets pending voucher.
     */
    event LogPendingVoucherAdded(address _investor);

    /**
     * State variable: Defines the state of the STO
     */
    States public state;

    /**
     * Only the foundation board is able to finalize the STO.
     * Two of four members have to confirm the finalization. Therefore a multisig contract is used.
     */
    address public directorsBoard;

    /**
     * This account is authorized to confirm payments
     */
    address public paymentConfirmer;

    /**
     * This the wallet where for an external agent all tokens tokens are minted for the incoming payments
     */
    address public tokenAgentWallet;

    /**
     * The token we are giving the investors in return for their investments
     */
    CrowdliToken public token;

    /**
     * The exchange vault used to exchange ether payments in a restricted an safe manner with the authorized bank into fiat money
     */
    CrowdliExchangeVault public crowdliExchangeVault;

    /**
     * The kyc provider used to whitelist the investors for verification tiers
     */
    CrowdliKYCProvider public crowdliKycProvider;

    /**
     * STO settings & statistics: Pre- and post allocated tokens
     */
    TokenAllocation[] public tokenAllocations;

    /**
     * STO settings & statistics: Defines the phases for an STO
     */
    InvestmentPhase[] public investmentPhases;

    /**
     * STO Setting:  The total amount of tokens sold during the STO(includes all phases)
     */
    uint public hardCapAmount = 0;

    /**
     * The lower hardcap threshold allows a bandwith in which the hard cap is regarded as reached
     */
    uint public hardCapThresholdAmount;

    /**
     * STO Setting: The min. token amount that have to be sold so that the STO successful
     */
    uint public softCapAmount;

    /**
     * STO Setting: Minimum amount of tokens a investor is able to buy
     */
    uint public minChfAmountPerInvestment;
    /**
     * STO Setting: The UNIX timestamp (in seconds) defining when 1the STO will start
     */
    uint public saleStartDate;

    /**
     * The date the STO Organizer can extend the STO at latest for the defined offset
     */
    uint public endDateExtensionDecissionDate;

    /**
     * The endDate can be extended with this offset
     */
    uint public endDateExtensionOffset;

    /**
     * STO Setting: 
     */
    uint public endDate;

    /**
     * STO settings: Video Verification cost
     */
    uint public videoVerificationCostAmount ;

    /**
     * STO settings: gas fees used for further processing of payments
     */
    uint internal gasCostAmount;

    /**
     * STO state: Defines the index of the current phase
     */
    uint public investmentPhaseIndex;

    /**
     * The board of directors can comment the finalization
     * Crowdli change: change to bytes32 to reduce gas costs
     */
    bytes32 public boardComment;

    /**
     * Threshold to define if the investor should get 'earlyBird' status.
     */
    uint public earlyBirdTokensThresholdAmount;

    /**
     * Token to be added to the purchased tokens amount.
     */
    uint public earlyBirdAdditionalTokensAmount;

    /**
     * Maximum number of the 'earlyBird' investors.
     */
    uint public earlyBirdInvestorsCount;

    /**
     * First available investment phase for 'earlyBird' investor.
     */
    uint public earlyBirdInvestmentPhase = 0;

    /**
     * Current number of the 'earlyBird' investor.
     */
    uint public currentEarlyBirdInvestorsCount = 0;

    /**
     * The token amount an investor receives for redeeming a voucher
     */
    uint public voucherTokensAmount;

    /**
     * Investors that have a pending vouchers to be redeemed
     */
    mapping(address => bool) public investorsWithEarlyBird;

    /**
     * Investors that have pending vouchers.
     */
    mapping(address => bool) public investorsWithPendingVouchers;

    /**
     * Investors that have paid for the video verification
     */
    mapping(address => bool) public paidForVideoVerification;

    /**
     * STO Statistic: The total amount of tokens sold
     */
    uint public tokensSoldAmount;

    /**
     * STO Statistic: The total amount of WEI invested by this STO
     */
    uint public weiInvested ;

    /**
     * STO Statistic: The number of investors that have invested in this STO
     */
    uint public numberOfInvestors;

    /**
     * STO Statistic: The total amount of investments (FIAT and ETH) in CHF
     */
    mapping(address => uint) public allInvestmentsInChf;

    /**
     * STO Statistic: The total amount of WEI's per investor
     */
    mapping(address => uint) public weiPerInvestor;

    /**
     * STO Statistic: The total amount of CHF's per investor
     */
    mapping(address => uint) public chfPerInvestor;

    /**
     * STO Statistic: The total amount of CHF's investments
     */
    uint public chfOverallInvested;

    /**
     * STO Statistic: The total amount of EUR's per investor
     */
    mapping(address => uint) public eurPerInvestor;

    /**
     * STO Statistic: The total amount of EUR's investments
     */
    uint public eurOverallInvested;

    /**
     * The exchangeRate that was last used 
     */
    uint public exchangeRate;

    uint public exchangeRateDecimals;

    /**
     * Limit the size of arrays to avoid gas limit deadlocks 
     */
	uint constant public arrayMaxEntryLimit = 10;
	
    // ============================================================================================================================================================================================================================   
    // All modifiers come here
    // ============================================================================================================================================================================================================================
    /**
     * @dev Throws if called by any account other than the foundation board
     */
    modifier onlyDirectorsBoard() {
        require(msg.sender == directorsBoard, "not directorsBoard");
        _;
    }

    /**
     * @dev Throws if sender is not payment confirmer
     */
    modifier onlyFiatPaymentConfirmer() {
        require((msg.sender == paymentConfirmer), "not paymentConfirmer");
        _;
    }

    /**
     * @dev Throws if sender is not payment confirmer
     */
    modifier onlyEtherPaymentProvider() {
        require(msg.sender == address(crowdliExchangeVault), "not crowdliExchangeVault");
        _;
    }

    /**
     * @dev Throws if sender is not token agent payment confirmer
     */
    modifier onlyTokenAgentPaymentConfirmer() {
        require((msg.sender == paymentConfirmer), "not tokenAgentPaymentConfirmer");
        _;
    }

    /**
     * @dev Throws if sender is not in state
     */
    modifier inState(States _state) {
        require(hasState(_state), "not in required state");
        _;
    }


    constructor (CrowdliToken _token, CrowdliKYCProvider _crowdliKycProvider, CrowdliExchangeVault _crowdliExchangeVault, address _directorsBoard, address _paymentConfirmer, address _tokenAgentWallet) public {
        token = _token;
        crowdliKycProvider = _crowdliKycProvider;
        crowdliExchangeVault = _crowdliExchangeVault;
        directorsBoard = _directorsBoard;
        paymentConfirmer = _paymentConfirmer;
        tokenAgentWallet = _tokenAgentWallet;
    }

    // ============================================================================================================================================================================================================================   
    // External functions
    // ============================================================================================================================================================================================================================v
    function initSTO(uint _saleStartDate, uint _earlyBirdTokensThreshold,
        uint _earlyBirdAdditionalTokens,
        uint _earlyBirdInvestorsCount,
        uint _earlyBirdInvestmentPhase,
        uint _voucherTokensAmount,
        uint _videoVerificationCost,
        uint _softCap,
        uint _endDate,
        uint _endDateExtensionDecissionDate,
        uint _endDateExtensionOffset,
        uint _gasCost,
        uint _hardCapThresholdAmount,
        uint _minChfAmountPerInvestment) external onlyOwner {

        // we must disallow any transfers until the end of the STO
        token.pause();

        saleStartDate = _saleStartDate;
        state = States.PrepareInvestment;
        earlyBirdTokensThresholdAmount = _earlyBirdTokensThreshold;
        earlyBirdInvestorsCount = _earlyBirdInvestorsCount;
        earlyBirdAdditionalTokensAmount = _earlyBirdAdditionalTokens;
        earlyBirdInvestmentPhase = _earlyBirdInvestmentPhase;
        voucherTokensAmount = _voucherTokensAmount;
        videoVerificationCostAmount = _videoVerificationCost;
        gasCostAmount = _gasCost;
        softCapAmount = _softCap;
        endDate = _endDate;
        endDateExtensionDecissionDate = _endDateExtensionDecissionDate;
        endDateExtensionOffset = _endDateExtensionOffset;
        hardCapThresholdAmount = _hardCapThresholdAmount;
        minChfAmountPerInvestment = _minChfAmountPerInvestment;

    }

    function registerPostAllocation(bytes32 _label, AllocationValueType _valueType, address _beneficiary, uint _value) external onlyOwner inState(States.PrepareInvestment) {
        require(_label != 0, "_label not set");
        require(_beneficiary != address(0), "_beneficiary not set");
        require(_value > 0, "_value not set");
        require(tokenAllocations.length < arrayMaxEntryLimit, "tokenAllocations.length is too high");
        tokenAllocations.push(TokenAllocation(_label, AllocationActionType.POST_ALLOCATE, _valueType, _value, _beneficiary, false));
    }

    function updateStartDate(uint _saleStartDate) external onlyOwner inState(States.PrepareInvestment) {
        require(_saleStartDate >= now, "saleStartDate not in future");
        saleStartDate = _saleStartDate;
        emit LogSaleStartUpdated(msg.sender, _saleStartDate);
    }

    function updateCrowdliKYCProvider(CrowdliKYCProvider _crowdliKycProvider) external onlyOwner inState(States.PrepareInvestment) {
        crowdliKycProvider = _crowdliKycProvider;
        emit LogKYCProviderUpdated(msg.sender, address(_crowdliKycProvider));
    }

    function updateExchangeRate(uint _exchangeRate, uint _exchangeRateDecimals) external onlyOwner {
        exchangeRate = _exchangeRate;
        exchangeRateDecimals = _exchangeRateDecimals;
    }

    function registerInvestmentPhase(bytes32 _label, bool allowManualSwitch, uint _discountBPS, uint _cap) external onlyOwner inState(States.PrepareInvestment) {
        require(_label != 0, "label should not be empty");
        require(investmentPhases.length <= arrayMaxEntryLimit, "investmentPhases.length is too high");
        investmentPhases.push(InvestmentPhase(_label, allowManualSwitch, _discountBPS, _cap, 0));
        emit LogRegisterInvestmentPhase(msg.sender, allowManualSwitch, _label, _discountBPS, _cap);
        //the hardcap is the sum of all phases caps
        hardCapAmount = hardCapAmount.add(_cap);
    }

    function processEtherPayment(address _beneficiary, uint _weiAmount, uint _paymentId) external whenNotPaused onlyEtherPaymentProvider inState(States.Investment) {
        processPayment(_beneficiary, _paymentId, _weiAmount, Currency.ETH, exchangeRate, exchangeRateDecimals, false, true);
    }

    function processBankPaymentCHF(address _beneficiary, uint _chfAmount, bool _hasRequestedPayments, uint _paymentId) external whenNotPaused onlyFiatPaymentConfirmer inState(States.Investment) {
        processPayment(_beneficiary, _paymentId, _chfAmount, Currency.CHF, 1, 1, _hasRequestedPayments, true);
    }

    function processBankPaymentEUR(address _beneficiary, uint _eurAmount, uint _exchangeRate, uint _exchangeRateDecimals, bool _hasRequestedPayments, uint _paymentId) external whenNotPaused onlyFiatPaymentConfirmer inState(States.Investment) {
        processPayment(_beneficiary, _paymentId, _eurAmount, Currency.EUR, _exchangeRate, _exchangeRateDecimals, _hasRequestedPayments, true);
    }

    function processTokenAgentPaymentCHF(uint _chfAmount, uint _paymentId) external whenNotPaused onlyTokenAgentPaymentConfirmer inState(States.Investment) {
        processPayment(tokenAgentWallet, _paymentId, _chfAmount, Currency.CHF, 1, 1, false, true);
    }

    function addPendingVoucher(address _investor) external onlyOwner whenNotPaused {
        investorsWithPendingVouchers[_investor] = true;
        emit LogPendingVoucherAdded(_investor);
    }

    function switchCurrentPhaseManually() external onlyDirectorsBoard inState(States.Investment) {
        require(isCurrentPhaseManuallySwitchable(), "manual switch disallowed");

        // calculate the gap between current phase and cap amount
        InvestmentPhase memory currentInvestmentPhase = investmentPhases[investmentPhaseIndex];
        uint phaseDeltaTokenAmount = currentInvestmentPhase.capAmount.sub(currentInvestmentPhase.tokensSoldAmount);

        // all tokens which were not sold after manual close will be made available in the last investment phase
        uint lastIndex = investmentPhases.length.sub(1);
        investmentPhases[lastIndex].capAmount = investmentPhases[lastIndex].capAmount.add(phaseDeltaTokenAmount);
        nextInvestmentPhase();
    }

    function start() external onlyDirectorsBoard inState(States.PrepareInvestment) {
        startInternal();
    }
    
    function calculateTokenStatementFiat(address _investor, uint _currencyAmount, Currency _currency, uint256 _exchangeRate, uint256 _exchangeRateDecimals, bool _hasRequestedBankPayments, uint investmentPhaseOffset) external view returns(uint[] memory) {
        TokenStatement memory tokenStatement = calculateTokenStatementStruct(_investor, _currencyAmount, _currency, _exchangeRate, _exchangeRateDecimals, _hasRequestedBankPayments, (investmentPhaseOffset == 0), investmentPhaseOffset);
        return convertTokenStatementToArray(tokenStatement);
    }
    
    function calculateTokenStatementEther(address _investor, uint _currencyAmount, Currency _currency, bool _hasRequestedBankPayments, uint investmentPhaseOffset) external view returns(uint[] memory) {
        //exchangeRate and exchangeRateDecimals will be used from internal parameters
        TokenStatement memory tokenStatement = calculateTokenStatementStruct(_investor, _currencyAmount, _currency, exchangeRate, exchangeRateDecimals, _hasRequestedBankPayments, (investmentPhaseOffset == 0), investmentPhaseOffset);
        return convertTokenStatementToArray(tokenStatement);
    }

    function evalTimedStates() external view returns (bool) {
        return ((isEndDateReached() && state == States.Investment) || isStartRequired());
    }

    function extendEndDate() external inState(States.Investment) onlyDirectorsBoard {
        require(isEndDateExtendable(), "isEndDateExtendable() is false");
        endDate = endDate.add(endDateExtensionOffset);
        endDateExtensionOffset = 0;
        emit LogEndDateExtended(msg.sender, endDate);
    }

    function updateTimedStates() external {
        if (isEndDateReached()) {
            if (isSoftCapReached()) {
                close(true);
            } else {
                close(false);
            }
        }
        if(isStartRequired()){
        	startInternal();
        }
    }

    function closeManually() external onlyDirectorsBoard inState(States.Investment) {
        require(isHardCapWithinCapThresholdReached(), "Cap is not reached.");
        close(true);
    }

    /**
     * Once the STO is in state Finalizing the directors board account has to finalize in order to make the tokens transferable
     * @param _message An official statement why the STO is considered as successful
     * 
     * Visibility: OK
     */
    function finalize(bytes32 _message) external onlyDirectorsBoard inState(States.Finalizing) {
        // the directors board has to give an statement why the STO is successful
        setBoardComment(_message);

        // Make token transferable otherwise the transfer call used when granting vesting to teams will be rejected.
        allocateTokens(AllocationActionType.POST_ALLOCATE);

        // release the token so can be transfered or 
        token.unpause();

        // finally the state of the STO is set to the final state 'Finalized' 
        updateState(States.Finalized);

        emit LogFinalized(msg.sender);
    }

    // ============================================================================================================================================================================================================================   
    // Public functions
    // ============================================================================================================================================================================================================================v
    function getInvestmentPhaseCount() public view returns(uint) {
        return investmentPhases.length;
    }

    function  getTokenAllocationsCount() public view returns(uint) {
        return tokenAllocations.length;
    }

    function validate() public view returns (uint) {
        uint statusCode = 0;
        if (address(token) == address(0)) {
            statusCode = 1;
        } else if (address(crowdliKycProvider) == address(0)) {
            statusCode = 2;
        } else if (softCapAmount == 0) {
            statusCode = 3;
        } else if (hardCapAmount == 0) {
            statusCode = 4;
        } else if (hardCapAmount < softCapAmount) {
            statusCode = 5;
        } else if (minChfAmountPerInvestment == 0) {
            statusCode = 6;
        } else if (investmentPhases.length == 0) {
            statusCode = 9;
        }
        return statusCode;
    }

    /**
     * @dev there is no direct way to convert an enum to string
     */
    function resolvePaymentError(TokenStatementValidation validationCode) public pure returns(string memory) {
        if (validationCode == TokenStatementValidation.BELOW_MIN_LIMIT) {
            return "BELOW_MIN_LIMIT";
        } else if (validationCode == TokenStatementValidation.ABOVE_MAX_LIMIT) {
            return "ABOVE_MAX_LIMIT";
        } else if (validationCode == TokenStatementValidation.EXCEEDS_HARD_CAP) {
            return "EXCEEDS_HARD_CAP";
        }
    }

    /**
     * @dev access permissions (onlyPauser) is checked in super function
     */
    function pause() public {
        super.pause();
        crowdliExchangeVault.pause();
        crowdliKycProvider.pause();
    }

    /**
     * @dev access permissions (onlyPauser) is checked in super function
     */
    function unpause () public {
        super.unpause();
        crowdliExchangeVault.unpause();
        crowdliKycProvider.unpause();
    }

    function setBoardComment(bytes32 _boardComment) public onlyDirectorsBoard {
        boardComment = _boardComment;
    }

    function hasPendingVideoVerificationFees(address _investor, bool _hasRequestedBankPayments) private view returns (bool) {
        return (crowdliKycProvider.hasVerificationLevel(_investor, CrowdliKYCProvider.VerificationTier.VideoVerified) && (!paidForVideoVerification[_investor]) && !hasUnconfirmedPayments(_investor, _hasRequestedBankPayments));
    }

    function isEntitledForEarlyBird(address _investor, uint tokenAmount, uint _investmentPhaseIndex) private view returns (bool) {
        return ((tokenAmount >= earlyBirdTokensThresholdAmount) && (currentEarlyBirdInvestorsCount < earlyBirdInvestorsCount) && !investorsWithEarlyBird[_investor] && _investmentPhaseIndex >= earlyBirdInvestmentPhase);
    }

    function hasPendingVouchers(address _investor, bool _hasRequestedBankPayments) private view returns (bool) {
        return (investorsWithPendingVouchers[_investor] && !hasUnconfirmedPayments(_investor, _hasRequestedBankPayments));
    }

    function hasUnconfirmedPayments(address _investor, bool _hasRequestedBankPayments) private view returns (bool) {
        return (_hasRequestedBankPayments || crowdliExchangeVault.hasRequestedPayments(_investor));
    }

    function isEndDateExtendable() public view returns (bool) {
        return ((endDateExtensionDecissionDate >= now) && (endDateExtensionOffset > 0));
    }

    function isCurrentPhaseManuallySwitchable() public view returns(bool) {
        return investmentPhases[investmentPhaseIndex].allowManualSwitch;
    }

    function isLastPhase() public view returns (bool) {
        return (investmentPhaseIndex.add(1) >= investmentPhases.length);
    }

    function isCurrentPhaseCapReached() public view returns(bool) {
        InvestmentPhase memory investmentPhase = investmentPhases[investmentPhaseIndex];
        return (investmentPhase.tokensSoldAmount >= investmentPhase.capAmount);
    }

    function isHardCapWithinCapThresholdReached() public view returns (bool) {
        return (isLastPhase() && (investmentPhases[investmentPhaseIndex].tokensSoldAmount >= investmentPhases[investmentPhaseIndex].capAmount.sub(hardCapThresholdAmount)));
    }

 	function isHardCapReached() public view returns (bool) {
        return (isLastPhase() && (investmentPhases[investmentPhaseIndex].tokensSoldAmount >= investmentPhases[investmentPhaseIndex].capAmount));
    }
    
    function isSoftCapReached() public view returns (bool) {
        return (tokensSoldAmount >= softCapAmount);
    }

    function isManuallyClosable() public view returns(bool) {
        return(hasState(States.Investment) && isHardCapWithinCapThresholdReached());
    }

    function isEndDateReached() public view returns (bool) {
        return (now > endDate);
    }

    function hasState(States _state) public view returns (bool) {
        return (state == _state);
    }

    /**
     * Used by the STO user interface to retrieve the STO statistics with a single call
     */
    function getStatisticsData() public view returns(uint[] memory) {
        uint[] memory result= new uint[](7);
        result[0] = softCapAmount;
        result[1] = hardCapAmount;
        result[2] = weiInvested;
        result[3] = chfOverallInvested;
        result[4] = eurOverallInvested;
        result[5] = tokensSoldAmount;
        result[6] = numberOfInvestors;
        return result;
    }

    // ============================================================================================================================================================================================================================   
    // Private functions
    // ============================================================================================================================================================================================================================v
    function nextInvestmentPhase() private returns (bool) {
        if (!isLastPhase()) {
            // there is a next phase, so we can switch
            investmentPhaseIndex = investmentPhaseIndex.add(1);
            emit LogInvestmentPhaseSwitched(investmentPhaseIndex);
            return false;

        } else {
            revert("payment exceeds hard cap");
        }
    }

    function confirmMintedTokensForPayment(uint _paymentId, uint tokenAmountToBuy, Currency _currency) private {
        if (Currency.ETH == _currency) {
            crowdliExchangeVault.confirmMintedTokensForPayment(_paymentId, tokenAmountToBuy);
        }
    }

    function updateState(States _state) private {
        require (_state > state, "the state can never transit backwards");
        state = _state;
        emit LogStateChanged(state);
    }

    function close(bool stoSucessfull) private inState(States.Investment) {
        require(hasState(States.Investment), "Requires state Investment");
        updateState(States.Finalizing);
        emit LogClosed(msg.sender, stoSucessfull);
    }

    function allocateTokens(AllocationActionType _actionType) private {
        for (uint i = 0; i < tokenAllocations.length;i++) {
            if (tokenAllocations[i].actionType == _actionType) {
                uint tokensToAllocate = 0;
                if (tokenAllocations[i].valueType == AllocationValueType.BPS_OF_TOKENS_SOLD) {
                    tokensToAllocate = tokensSoldAmount.mul(tokenAllocations[i].valueAmount).div(10000);
                } else if (tokenAllocations[i].valueType == AllocationValueType.FIXED_TOKEN_AMOUNT) {
                    tokensToAllocate = tokenAllocations[i].valueAmount;
                }
                token.mint(tokenAllocations[i].beneficiary, tokensToAllocate);
                tokenAllocations[i].isAllocated = true;
            }
        }
    }

    function processPayment(address _investor, uint _paymentId, uint _currencyAmount, Currency _currency, uint _exchangeRate, uint _exchangeRateDecimals, bool _hasRequestedBankPayments, bool _isFirstPayment) private {
        require(crowdliKycProvider.verificationTiers(_investor) > CrowdliKYCProvider.VerificationTier.None, "Verification tier not > 0");

        InvestmentPhase storage investmentPhase = investmentPhases[investmentPhaseIndex];
        // ============================================================================================
        // Step 1: Calculate token statement
        // ============================================================================================
        TokenStatement memory tokenStatement = calculateTokenStatementStruct(_investor, _currencyAmount, _currency, _exchangeRate, _exchangeRateDecimals, _hasRequestedBankPayments, _isFirstPayment, 0);

        // only process if validation code == OK
        require(tokenStatement.validationCode == TokenStatementValidation.OK, resolvePaymentError(tokenStatement.validationCode));

        // ============================================================================================
        // Update the STO states and statistics
        // ============================================================================================ 
        // sum up the tokens sold for the current investment phase
        investmentPhase.tokensSoldAmount = investmentPhase.tokensSoldAmount.add(tokenStatement.currentPhaseTokenAmount);

        // sum up the amount of tokens sold during the STO
        tokensSoldAmount = tokensSoldAmount.add(tokenStatement.currentPhaseTokenAmount);

        if (_isFirstPayment) {
            allInvestmentsInChf[_investor] = allInvestmentsInChf[_investor].add(tokenStatement.requestedCHF);

            if (tokenStatement.feesCHF > gasCostAmount)
	        	paidForVideoVerification[_investor] = true;

            if (Currency.CHF == _currency) {
                chfPerInvestor[_investor] = chfPerInvestor[_investor].add(_currencyAmount);
                chfOverallInvested = chfOverallInvested.add(_currencyAmount);
            } else if (Currency.EUR == _currency) {
                eurPerInvestor[_investor] = eurPerInvestor[_investor].add(_currencyAmount);
                eurOverallInvested = eurOverallInvested.add(_currencyAmount);
            } else if (Currency.ETH == _currency) {
                weiPerInvestor[_investor] = weiPerInvestor[_investor].add(_currencyAmount);
                weiInvested = weiInvested.add(_currencyAmount);
            }

            // update the statistic counting the number of investors involved in a token purchase
            if (token.balanceOf(_investor) == 0) {
                numberOfInvestors = numberOfInvestors.add(1);
            }
        }

        if (tokenStatement.earlyBirdCreditTokenAmount > 0) { // earlyBird         
        // update early bird investor statistics
            currentEarlyBirdInvestorsCount = currentEarlyBirdInvestorsCount.add(1);

            // store flag that the investor has received early bird tokens
            investorsWithEarlyBird[_investor] = true;
        }

        if (tokenStatement.voucherCreditTokenAmount > 0) {
            // mark voucher as redeemed for investor
            investorsWithPendingVouchers[_investor] = false;
        }


        // ============================================================================================
        // Mint the STO tokens
        // ============================================================================================        
        token.mint(_investor, tokenStatement.currentPhaseTokenAmount);

        if (tokenStatement.nextPhaseBaseAmount > 0) {
            ExecutionType executionType;

            executionType = ExecutionType.SplitPayment;

            emit LogPaymentConfirmation(_investor, tokenStatement.requestedBase, convertTokenStatementToArray(tokenStatement), _paymentId, _currency, executionType);
            confirmMintedTokensForPayment(_paymentId, tokenStatement.currentPhaseTokenAmount, _currency);

            // switch to next phase
            nextInvestmentPhase();

            // process payment in the new phase
            processPayment(_investor, _paymentId, tokenStatement.nextPhaseBaseAmount, _currency, _exchangeRate, _exchangeRateDecimals, _hasRequestedBankPayments, false);
        } else {

            // no further payments to process
            emit LogPaymentConfirmation(_investor, tokenStatement.requestedBase, convertTokenStatementToArray(tokenStatement), _paymentId, _currency, ExecutionType.SinglePayment);
            confirmMintedTokensForPayment(_paymentId, tokenStatement.currentPhaseTokenAmount, _currency);
        }
    }

    function convertTokenStatementToArray(TokenStatement memory tokenStatement) private pure returns(uint[] memory) {
        uint[] memory tokenStatementArray = new uint[](9);
        tokenStatementArray[0] = tokenStatement.requestedBase;
        tokenStatementArray[1] = tokenStatement.requestedCHF;
        tokenStatementArray[2] = tokenStatement.feesCHF;
        tokenStatementArray[3] = tokenStatement.currentPhaseDiscount;
        tokenStatementArray[4] = tokenStatement.earlyBirdCreditTokenAmount;
        tokenStatementArray[5] = tokenStatement.voucherCreditTokenAmount;
        tokenStatementArray[6] = tokenStatement.currentPhaseTokenAmount;
        tokenStatementArray[7] = tokenStatement.nextPhaseBaseAmount;
        tokenStatementArray[8] = uint(tokenStatement.validationCode);
        return tokenStatementArray;
    }

    function calculateDiscountUptick(uint _amount, InvestmentPhase memory investmentPhase) private pure returns (uint) {
        uint currentRate = uint(10000).sub(investmentPhase.discountBPS);
        return _amount.mul(investmentPhase.discountBPS).div(currentRate);
    }

    function calculateDiscount(uint _amount, InvestmentPhase memory investmentPhase) private pure returns (uint) {
        return _amount.mul(investmentPhase.discountBPS).div(10000);
    }

    function calculateConversionFromBase(uint _currencyAmount, uint _exchangeRate, uint _exchangeRateDecimals) private pure returns (uint) {
        return _currencyAmount.mul(_exchangeRate).div(_exchangeRateDecimals);
    }

    function calculateConversionToBase(uint _currencyAmount, uint _exchangeRate, uint _exchangeRateDecimals) private pure returns (uint) {
        return _currencyAmount.mul(_exchangeRateDecimals).div(_exchangeRate);
    }

    function calculateTokenStatementStruct(address _investor, uint _currencyAmount, Currency _currency, uint256 _exchangeRate, uint256 _exchangeRateDecimals, bool _hasRequestedBankPayments, bool _isFirstPayment, uint _investmentPhaseOffset) private view returns(TokenStatement memory) {
        TokenStatement memory tokenStatement;

        // the struct containing the data for the current investment phase
        uint investmentPhaseWithOffset = investmentPhaseIndex.add(_investmentPhaseOffset);
        InvestmentPhase memory investmentPhase = investmentPhases[investmentPhaseWithOffset];

        // the requested amount in the currency provided
        tokenStatement.requestedBase = _currencyAmount;

        // ============================================================================================
        // Step 1: Convert requested payment to CHF
        // ============================================================================================
        if (Currency.CHF == _currency) {
            tokenStatement.requestedCHF = tokenStatement.requestedBase;
        } else if (Currency.EUR == _currency) {
            tokenStatement.requestedCHF = calculateConversionFromBase(tokenStatement.requestedBase, _exchangeRate, _exchangeRateDecimals);
        } else if (Currency.ETH == _currency) {
            tokenStatement.requestedCHF = calculateConversionFromBase(tokenStatement.requestedBase, _exchangeRate, _exchangeRateDecimals);
        } else revert("Currency not supported");

        // the requested amount in the currency provided
        tokenStatement.requestedCHF = roundUp(tokenStatement.requestedCHF);

        uint investmentNetCHF = tokenStatement.requestedCHF;

        // calculate the fees (gas cost always, video verification once, if previously processed)
        // we have to make sure that the credits are not recognized twice in case of a split payment
        if (_isFirstPayment) {
            // ============================================================================================
	        // Verify/validate investment thresholds
	        // ============================================================================================
	        tokenStatement.validationCode = validatePayment(_investor, tokenStatement);
 
            tokenStatement.feesCHF = gasCostAmount;
            if (hasPendingVideoVerificationFees(_investor, _hasRequestedBankPayments)) {
                tokenStatement.feesCHF = tokenStatement.feesCHF.add(videoVerificationCostAmount);
            }
            investmentNetCHF = tokenStatement.requestedCHF.sub(tokenStatement.feesCHF);
        }

        // check whether the payment can be handled in the current phase OR we have to create a second payment to be executed in the next phase
        uint phaseDeltaTokenAmount = investmentPhase.capAmount.sub(investmentPhase.tokensSoldAmount);
        tokenStatement.currentPhaseDiscount = roundUp(calculateDiscountUptick(investmentNetCHF, investmentPhase));
        uint tokenAmountWithCurrentPhaseDiscount = investmentNetCHF.add(tokenStatement.currentPhaseDiscount);



        // create second payment (split) if tokens exceed current phase cap
        if (tokenAmountWithCurrentPhaseDiscount > phaseDeltaTokenAmount) {
        	if (isLastPhase())
            	tokenStatement.validationCode = TokenStatementValidation.EXCEEDS_HARD_CAP;
        
            tokenStatement.currentPhaseTokenAmount = roundUp(phaseDeltaTokenAmount);
            tokenStatement.currentPhaseDiscount = roundUp(calculateDiscount(phaseDeltaTokenAmount, investmentPhase));
            uint currentPhaseNetTokenAmount = phaseDeltaTokenAmount.sub(tokenStatement.currentPhaseDiscount);
            tokenStatement.nextPhaseBaseAmount = calculateConversionToBase(investmentNetCHF.sub(currentPhaseNetTokenAmount), _exchangeRate, _exchangeRateDecimals);
        } else {
            tokenStatement.currentPhaseDiscount = tokenStatement.currentPhaseDiscount;
            tokenStatement.currentPhaseTokenAmount = tokenAmountWithCurrentPhaseDiscount;
            tokenStatement.nextPhaseBaseAmount = 0;

            // we have to make sure that the credits are not recognized twice in case of a split payment
            // the first x investors starting from phase y will receive some bonus tokens
            if (isEntitledForEarlyBird(_investor, tokenStatement.currentPhaseTokenAmount, investmentPhaseWithOffset)) {
                tokenStatement.earlyBirdCreditTokenAmount = earlyBirdAdditionalTokensAmount;
                tokenStatement.currentPhaseTokenAmount = tokenStatement.currentPhaseTokenAmount.add(tokenStatement.earlyBirdCreditTokenAmount);
            }
            // investor receives some bonus tokens if he has previously redeemed a valid STO voucher
            if (hasPendingVouchers(_investor, _hasRequestedBankPayments)) {
                tokenStatement.voucherCreditTokenAmount = voucherTokensAmount;
                tokenStatement.currentPhaseTokenAmount = tokenStatement.currentPhaseTokenAmount.add(tokenStatement.voucherCreditTokenAmount);
            }
        }
        
        // the STO requires to round up the decimals
        tokenStatement.currentPhaseTokenAmount = roundUp(tokenStatement.currentPhaseTokenAmount);
        return tokenStatement;
    }

    function validatePayment(address _investor, TokenStatement memory tokenStatement) private view returns(TokenStatementValidation) {
        if (tokenStatement.requestedCHF < minChfAmountPerInvestment) {
            // a single investment (token purchase) musn't be below the defined min. token amount threshold
            return TokenStatementValidation.BELOW_MIN_LIMIT; // a single investment (token purchase) musn't exceed the max token amount per KYC Verification Tier
        } else if (allInvestmentsInChf[_investor].add(tokenStatement.requestedCHF) > crowdliKycProvider.getMaxChfAmountForInvestor(_investor)) {
            // a single investment (token purchase) musn't exceed the max token amount per KYC Verification Tier 
            return TokenStatementValidation.ABOVE_MAX_LIMIT;
        } else return TokenStatementValidation.OK;

    }
    
    function isStartRequired() private view returns(bool) {
    	return ((now > saleStartDate) && state == States.PrepareInvestment);
    }
    
    function startInternal() private {
    	require(validate() == 0, "Start validation failed");
        saleStartDate = now;
        updateState(States.Investment);
        emit LogStarted(msg.sender);
    }

    function roundUp(uint amount) private pure returns(uint) {
        uint decimals = 10 ** 18;
        uint result = amount;
        uint remainder = amount % decimals;
        if (remainder > 0) {
            result = amount - remainder + decimals;
        }
        return result;
    }
}

File 6 of 22: CrowdliToken.sol
pragma solidity 0.5.0;

import "./Ownable.sol";
import "./ERC20Detailed.sol";
import "./ERC20Mintable.sol";
import "./ERC20Pausable.sol";

/**
* @title CrowdliToken
*/
contract CrowdliToken is ERC20Detailed, ERC20Mintable, ERC20Pausable, Ownable {
	/**
	 * Holds the addresses of the investors
	 */
    address[] public investors;

    constructor (string memory _name, string memory _symbol, uint8 _decimals) ERC20Detailed(_name,_symbol,_decimals) public {
    }
    
    function mint(address account, uint256 amount) public onlyMinter returns (bool) {
         if (balanceOf(account) == 0) {
            investors.push(account);
         }
         return super.mint(account, amount);
    }
    
    
    function initToken(address _directorsBoard,address _crowdliSTO) external onlyOwner{
    	addMinter(_directorsBoard);
    	addMinter(_crowdliSTO);
    	addPauser(_directorsBoard);
    	addPauser(_crowdliSTO);
    }
    
}


File 7 of 22: ERC20.sol
pragma solidity ^0.5.0;

import "./IERC20.sol";
import "./SafeMath.sol";

/**
 * @dev Implementation of the `IERC20` interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using `_mint`.
 * For a generic mechanism see `ERC20Mintable`.
 *
 * *For a detailed writeup see our guide [How to implement supply
 * mechanisms](https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226).*
 *
 * We have followed general OpenZeppelin guidelines: functions revert instead
 * of returning `false` on failure. This behavior is nonetheless conventional
 * and does not conflict with the expectations of ERC20 applications.
 *
 * Additionally, an `Approval` event is emitted on calls to `transferFrom`.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard `decreaseAllowance` and `increaseAllowance`
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See `IERC20.approve`.
 */
contract ERC20 is IERC20 {
    using SafeMath for uint256;

    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowances;

    uint256 private _totalSupply;

    /**
     * @dev See `IERC20.totalSupply`.
     */
    function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See `IERC20.balanceOf`.
     */
    function balanceOf(address account) public view returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See `IERC20.transfer`.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public returns (bool) {
        _transfer(msg.sender, recipient, amount);
        return true;
    }

    /**
     * @dev See `IERC20.allowance`.
     */
    function allowance(address owner, address spender) public view returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See `IERC20.approve`.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 value) public returns (bool) {
        _approve(msg.sender, spender, value);
        return true;
    }

    /**
     * @dev See `IERC20.transferFrom`.
     *
     * Emits an `Approval` event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of `ERC20`;
     *
     * Requirements:
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `value`.
     * - the caller must have allowance for `sender`'s tokens of at least
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, msg.sender, _allowances[sender][msg.sender].sub(amount));
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to `approve` that can be used as a mitigation for
     * problems described in `IERC20.approve`.
     *
     * Emits an `Approval` event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
        _approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue));
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to `approve` that can be used as a mitigation for
     * problems described in `IERC20.approve`.
     *
     * Emits an `Approval` event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
        _approve(msg.sender, spender, _allowances[msg.sender][spender].sub(subtractedValue));
        return true;
    }

    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is internal function is equivalent to `transfer`, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a `Transfer` event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(address sender, address recipient, uint256 amount) internal {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _balances[sender] = _balances[sender].sub(amount);
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a `Transfer` event with `from` set to the zero address.
     *
     * Requirements
     *
     * - `to` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal {
        require(account != address(0), "ERC20: mint to the zero address");

        _totalSupply = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);
        emit Transfer(address(0), account, amount);
    }

     /**
     * @dev Destoys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a `Transfer` event with `to` set to the zero address.
     *
     * Requirements
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 value) internal {
        require(account != address(0), "ERC20: burn from the zero address");

        _totalSupply = _totalSupply.sub(value);
        _balances[account] = _balances[account].sub(value);
        emit Transfer(account, address(0), value);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
     *
     * This is internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an `Approval` event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 value) internal {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = value;
        emit Approval(owner, spender, value);
    }

    /**
     * @dev Destoys `amount` tokens from `account`.`amount` is then deducted
     * from the caller's allowance.
     *
     * See `_burn` and `_approve`.
     */
    function _burnFrom(address account, uint256 amount) internal {
        _burn(account, amount);
        _approve(account, msg.sender, _allowances[account][msg.sender].sub(amount));
    }
}

File 8 of 22: ERC20Capped.sol
pragma solidity ^0.5.0;

import "./ERC20Mintable.sol";

/**
 * @dev Extension of `ERC20Mintable` that adds a cap to the supply of tokens.
 */
contract ERC20Capped is ERC20Mintable {
    uint256 private _cap;

    /**
     * @dev Sets the value of the `cap`. This value is immutable, it can only be
     * set once during construction.
     */
    constructor (uint256 cap) public {
        require(cap > 0, "ERC20Capped: cap is 0");
        _cap = cap;
    }

    /**
     * @dev Returns the cap on the token's total supply.
     */
    function cap() public view returns (uint256) {
        return _cap;
    }

    /**
     * @dev See `ERC20Mintable.mint`.
     *
     * Requirements:
     *
     * - `value` must not cause the total supply to go over the cap.
     */
    function _mint(address account, uint256 value) internal {
        require(totalSupply().add(value) <= _cap, "ERC20Capped: cap exceeded");
        super._mint(account, value);
    }
}

File 9 of 22: ERC20Detailed.sol
pragma solidity ^0.5.0;

import "./IERC20.sol";

/**
 * @dev Optional functions from the ERC20 standard.
 */
contract ERC20Detailed is IERC20 {
    string private _name;
    string private _symbol;
    uint8 private _decimals;

    /**
     * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of
     * these values are immutable: they can only be set once during
     * construction.
     */
    constructor (string memory name, string memory symbol, uint8 decimals) public {
        _name = name;
        _symbol = symbol;
        _decimals = decimals;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei.
     *
     * > Note that this information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * `IERC20.balanceOf` and `IERC20.transfer`.
     */
    function decimals() public view returns (uint8) {
        return _decimals;
    }
}

File 10 of 22: ERC20Mintable.sol
pragma solidity ^0.5.0;

import "./ERC20.sol";
import "./MinterRole.sol";

/**
 * @dev Extension of `ERC20` that adds a set of accounts with the `MinterRole`,
 * which have permission to mint (create) new tokens as they see fit.
 *
 * At construction, the deployer of the contract is the only minter.
 */
contract ERC20Mintable is ERC20, MinterRole {
    /**
     * @dev See `ERC20._mint`.
     *
     * Requirements:
     *
     * - the caller must have the `MinterRole`.
     */
    function mint(address account, uint256 amount) public onlyMinter returns (bool) {
        _mint(account, amount);
        return true;
    }
}

File 11 of 22: ERC20Pausable.sol
pragma solidity ^0.5.0;

import "./ERC20.sol";
import "./Pausable.sol";

/**
 * @title Pausable token
 * @dev ERC20 modified with pausable transfers.
 */
contract ERC20Pausable is ERC20, Pausable {
    function transfer(address to, uint256 value) public whenNotPaused returns (bool) {
        return super.transfer(to, value);
    }

    function transferFrom(address from, address to, uint256 value) public whenNotPaused returns (bool) {
        return super.transferFrom(from, to, value);
    }

    function approve(address spender, uint256 value) public whenNotPaused returns (bool) {
        return super.approve(spender, value);
    }

    function increaseAllowance(address spender, uint addedValue) public whenNotPaused returns (bool) {
        return super.increaseAllowance(spender, addedValue);
    }

    function decreaseAllowance(address spender, uint subtractedValue) public whenNotPaused returns (bool) {
        return super.decreaseAllowance(spender, subtractedValue);
    }
}

File 12 of 22: IERC20.sol
pragma solidity ^0.5.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see `ERC20Detailed`.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a `Transfer` event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through `transferFrom`. This is
     * zero by default.
     *
     * This value changes when `approve` or `transferFrom` are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * > 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
     *
     * Emits an `Approval` event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a `Transfer` event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to `approve`. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

File 13 of 22: MinterRole.sol
pragma solidity ^0.5.0;

import "./Roles.sol";

contract MinterRole {
    using Roles for Roles.Role;

    event MinterAdded(address indexed account);
    event MinterRemoved(address indexed account);

    Roles.Role private _minters;

    constructor () internal {
        _addMinter(msg.sender);
    }

    modifier onlyMinter() {
        require(isMinter(msg.sender), "MinterRole: caller does not have the Minter role");
        _;
    }

    function isMinter(address account) public view returns (bool) {
        return _minters.has(account);
    }

    function addMinter(address account) public onlyMinter {
        _addMinter(account);
    }

    function renounceMinter() public {
        _removeMinter(msg.sender);
    }

    function _addMinter(address account) internal {
        _minters.add(account);
        emit MinterAdded(account);
    }

    function _removeMinter(address account) internal {
        _minters.remove(account);
        emit MinterRemoved(account);
    }
}

File 14 of 22: Ownable.sol
pragma solidity ^0.5.0;

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be aplied to your functions to restrict their use to
 * the owner.
 */
contract Ownable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        _owner = msg.sender;
        emit OwnershipTransferred(address(0), _owner);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(isOwner(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Returns true if the caller is the current owner.
     */
    function isOwner() public view returns (bool) {
        return msg.sender == _owner;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * > Note: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public onlyOwner {
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     */
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

File 15 of 22: Pausable.sol
pragma solidity ^0.5.0;

import "./PauserRole.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
contract Pausable is PauserRole {
    /**
     * @dev Emitted when the pause is triggered by a pauser (`account`).
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by a pauser (`account`).
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state. Assigns the Pauser role
     * to the deployer.
     */
    constructor () internal {
        _paused = false;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view returns (bool) {
        return _paused;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     */
    modifier whenNotPaused() {
        require(!_paused, "Pausable: paused");
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     */
    modifier whenPaused() {
        require(_paused, "Pausable: not paused");
        _;
    }

    /**
     * @dev Called by a pauser to pause, triggers stopped state.
     */
    function pause() public onlyPauser whenNotPaused {
        _paused = true;
        emit Paused(msg.sender);
    }

    /**
     * @dev Called by a pauser to unpause, returns to normal state.
     */
    function unpause() public onlyPauser whenPaused {
        _paused = false;
        emit Unpaused(msg.sender);
    }
}

File 16 of 22: PauserRole.sol
pragma solidity ^0.5.0;

import "./Roles.sol";

contract PauserRole {
    using Roles for Roles.Role;

    event PauserAdded(address indexed account);
    event PauserRemoved(address indexed account);

    Roles.Role private _pausers;

    constructor () internal {
        _addPauser(msg.sender);
    }

    modifier onlyPauser() {
        require(isPauser(msg.sender), "PauserRole: caller does not have the Pauser role");
        _;
    }

    function isPauser(address account) public view returns (bool) {
        return _pausers.has(account);
    }

    function addPauser(address account) public onlyPauser {
        _addPauser(account);
    }

    function renouncePauser() public {
        _removePauser(msg.sender);
    }

    function _addPauser(address account) internal {
        _pausers.add(account);
        emit PauserAdded(account);
    }

    function _removePauser(address account) internal {
        _pausers.remove(account);
        emit PauserRemoved(account);
    }
}

File 17 of 22: Roles.sol
pragma solidity ^0.5.0;

/**
 * @title Roles
 * @dev Library for managing addresses assigned to a Role.
 */
library Roles {
    struct Role {
        mapping (address => bool) bearer;
    }

    /**
     * @dev Give an account access to this role.
     */
    function add(Role storage role, address account) internal {
        require(!has(role, account), "Roles: account already has role");
        role.bearer[account] = true;
    }

    /**
     * @dev Remove an account's access to this role.
     */
    function remove(Role storage role, address account) internal {
        require(has(role, account), "Roles: account does not have role");
        role.bearer[account] = false;
    }

    /**
     * @dev Check if an account has this role.
     * @return bool
     */
    function has(Role storage role, address account) internal view returns (bool) {
        require(account != address(0), "Roles: account is the zero address");
        return role.bearer[account];
    }
}

File 18 of 22: SafeERC20.sol
pragma solidity ^0.5.0;

import "./IERC20.sol";
import "./SafeMath.sol";
import "./Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * 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 {
    using SafeMath for uint256;
    using Address for address;

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value);
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves.

        // A Solidity high level call has three parts:
        //  1. The target address is checked to verify it contains contract code
        //  2. The call itself is made, and success asserted
        //  3. The return value is decoded, which in turn checks the size of the returned data.
        // solhint-disable-next-line max-line-length
        require(address(token).isContract(), "SafeERC20: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = address(token).call(data);
        require(success, "SafeERC20: low-level call failed");

        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 19 of 22: SafeMath.sol
pragma solidity ^0.5.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring '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;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, "SafeMath: division by zero");
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, "SafeMath: modulo by zero");
        return a % b;
    }
}

File 20 of 22: SignerRole.sol
pragma solidity ^0.5.0;

import "./Roles.sol";

contract SignerRole {
    using Roles for Roles.Role;

    event SignerAdded(address indexed account);
    event SignerRemoved(address indexed account);

    Roles.Role private _signers;

    constructor () internal {
        _addSigner(msg.sender);
    }

    modifier onlySigner() {
        require(isSigner(msg.sender), "SignerRole: caller does not have the Signer role");
        _;
    }

    function isSigner(address account) public view returns (bool) {
        return _signers.has(account);
    }

    function addSigner(address account) public onlySigner {
        _addSigner(account);
    }

    function renounceSigner() public {
        _removeSigner(msg.sender);
    }

    function _addSigner(address account) internal {
        _signers.add(account);
        emit SignerAdded(account);
    }

    function _removeSigner(address account) internal {
        _signers.remove(account);
        emit SignerRemoved(account);
    }
}

File 21 of 22: WhitelistAdminRole.sol
pragma solidity ^0.5.0;

import "./Roles.sol";

/**
 * @title WhitelistAdminRole
 * @dev WhitelistAdmins are responsible for assigning and removing Whitelisted accounts.
 */
contract WhitelistAdminRole {
    using Roles for Roles.Role;

    event WhitelistAdminAdded(address indexed account);
    event WhitelistAdminRemoved(address indexed account);

    Roles.Role private _whitelistAdmins;

    constructor () internal {
        _addWhitelistAdmin(msg.sender);
    }

    modifier onlyWhitelistAdmin() {
        require(isWhitelistAdmin(msg.sender), "WhitelistAdminRole: caller does not have the WhitelistAdmin role");
        _;
    }

    function isWhitelistAdmin(address account) public view returns (bool) {
        return _whitelistAdmins.has(account);
    }

    function addWhitelistAdmin(address account) public onlyWhitelistAdmin {
        _addWhitelistAdmin(account);
    }

    function renounceWhitelistAdmin() public {
        _removeWhitelistAdmin(msg.sender);
    }

    function _addWhitelistAdmin(address account) internal {
        _whitelistAdmins.add(account);
        emit WhitelistAdminAdded(account);
    }

    function _removeWhitelistAdmin(address account) internal {
        _whitelistAdmins.remove(account);
        emit WhitelistAdminRemoved(account);
    }
}

File 22 of 22: WhitelistedRole.sol
pragma solidity ^0.5.0;

import "./Roles.sol";
import "./WhitelistAdminRole.sol";

/**
 * @title WhitelistedRole
 * @dev Whitelisted accounts have been approved by a WhitelistAdmin to perform certain actions (e.g. participate in a
 * crowdsale). This role is special in that the only accounts that can add it are WhitelistAdmins (who can also remove
 * it), and not Whitelisteds themselves.
 */
contract WhitelistedRole is WhitelistAdminRole {
    using Roles for Roles.Role;

    event WhitelistedAdded(address indexed account);
    event WhitelistedRemoved(address indexed account);

    Roles.Role private _whitelisteds;

    modifier onlyWhitelisted() {
        require(isWhitelisted(msg.sender), "WhitelistedRole: caller does not have the Whitelisted role");
        _;
    }

    function isWhitelisted(address account) public view returns (bool) {
        return _whitelisteds.has(account);
    }

    function addWhitelisted(address account) public onlyWhitelistAdmin {
        _addWhitelisted(account);
    }

    function removeWhitelisted(address account) public onlyWhitelistAdmin {
        _removeWhitelisted(account);
    }

    function renounceWhitelisted() public {
        _removeWhitelisted(msg.sender);
    }

    function _addWhitelisted(address account) internal {
        _whitelisteds.add(account);
        emit WhitelistedAdded(account);
    }

    function _removeWhitelisted(address account) internal {
        _whitelisteds.remove(account);
        emit WhitelistedRemoved(account);
    }
}

Contract Security Audit

Contract ABI

API
[{"constant":true,"inputs":[],"name":"getExchangeOrdersCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_beneficiary","type":"address"}],"name":"hasRequestedPayments","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"isPauser","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_crowdliSTO","type":"address"}],"name":"setCrowdliSTO","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"paymentId","type":"uint256"},{"name":"_mintedTokens","type":"uint256"}],"name":"confirmMintedTokensForPayment","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"requestPayment","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"renouncePauser","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"nrRequestedPayments","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_orderIndex","type":"uint64"},{"name":"_exchangeRate","type":"uint256"}],"name":"confirmOrder","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_paymentIds","type":"uint256[]"}],"name":"rejectPayment","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"}],"name":"addPauser","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"payments","outputs":[{"name":"from","type":"address"},{"name":"date","type":"uint64"},{"name":"status","type":"uint8"},{"name":"weiAmount","type":"uint256"},{"name":"pendingTokens","type":"uint256"},{"name":"mintedTokens","type":"uint256"},{"name":"exchangeRate","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getEtherPaymentsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"orderId","type":"uint256"}],"name":"getExchangeOrdersToPayments","outputs":[{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_exchangeWallet","type":"address"},{"name":"_paymentsToAccept","type":"uint256[]"}],"name":"createOrder","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_directorsBoard","type":"address"},{"name":"_crowdliSTO","type":"address"}],"name":"initExchangeVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"exchangeOrders","outputs":[{"name":"exchangeRate","type":"uint256"},{"name":"date","type":"uint64"},{"name":"exchangeWallet","type":"address"},{"name":"status","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"paymentConfirmer","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"index","type":"uint256"}],"name":"refundPayment","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_paymentConfirmer","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"}],"name":"PaymentsEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"}],"name":"PaymentsDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"beneficiary","type":"address"},{"indexed":false,"name":"weiAmount","type":"uint256"}],"name":"EtherPaymentRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"beneficiary","type":"address"},{"indexed":false,"name":"weiAmount","type":"uint256"},{"indexed":false,"name":"paymentIndex","type":"uint256"}],"name":"EtherPaymentRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"etherPaymentIndex","type":"uint256"}],"name":"EtherPaymentRejected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"value","type":"uint256"}],"name":"LogGasUsed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"etherPaymentIndex","type":"uint256"}],"name":"EtherPaymentPurchaseFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"payments","type":"uint256[]"}],"name":"OrderCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"etherPaymentIndex","type":"uint256"}],"name":"OrderConfirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"PauserAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"PauserRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}]

60806040523480156200001157600080fd5b5060405160208062002922833981018060405260208110156200003357600080fd5b505160008054600160a060020a0319163317808255604051600160a060020a039190911691907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a36200009233640100000000620000c2810204565b6002805460ff1916905560078054600160a060020a031916600160a060020a03929092169190911790556200027b565b620000dd600182640100000000620025826200011482021704565b604051600160a060020a038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b620001298282640100000000620001bb810204565b156200019657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c6500604482015290519081900360640190fd5b600160a060020a0316600090815260209190915260409020805460ff19166001179055565b6000600160a060020a03821615156200025b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f526f6c65733a206163636f756e7420697320746865207a65726f20616464726560448201527f7373000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b50600160a060020a03166000908152602091909152604090205460ff1690565b612697806200028b6000396000f3fe60806040526004361061013a5763ffffffff60e060020a600035041663241b6ae6811461013f57806330748be0146101665780633f4ba83a146101ad57806346fbf68e146101c45780634fb7eed3146101f757806358ccf6b61461022a5780635c975abb1461025a57806363bdb94b1461026f5780636ef8d66d14610277578063715018a61461028c578063796be41a146102a15780637ace5778146102d45780637c48522f1461030e57806382dc1ec41461038b5780638456cb59146103be57806387d81789146103d35780638da5cb5b1461045e5780638f32d59b1461048f578063982cc3c9146104a4578063bdba5d4e146104b9578063bef9045914610533578063c89288e5146105c0578063d2485f26146105fb578063f2fde38b14610684578063f3612cb3146106b7578063f63813f4146106cc575b600080fd5b34801561014b57600080fd5b506101546106f6565b60408051918252519081900360200190f35b34801561017257600080fd5b506101996004803603602081101561018957600080fd5b5035600160a060020a03166106fc565b604080519115158252519081900360200190f35b3480156101b957600080fd5b506101c2610719565b005b3480156101d057600080fd5b50610199600480360360208110156101e757600080fd5b5035600160a060020a0316610839565b34801561020357600080fd5b506101c26004803603602081101561021a57600080fd5b5035600160a060020a0316610852565b34801561023657600080fd5b506101c26004803603604081101561024d57600080fd5b50803590602001356108cd565b34801561026657600080fd5b50610199610973565b6101c261097c565b34801561028357600080fd5b506101c2610e68565b34801561029857600080fd5b506101c2610e73565b3480156102ad57600080fd5b50610154600480360360208110156102c457600080fd5b5035600160a060020a0316610f16565b3480156102e057600080fd5b506101c2600480360360408110156102f757600080fd5b5067ffffffffffffffff8135169060200135610f28565b34801561031a57600080fd5b506101c26004803603602081101561033157600080fd5b81019060208101813564010000000081111561034c57600080fd5b82018360208201111561035e57600080fd5b8035906020019184602083028401116401000000008311171561038057600080fd5b50909250905061113d565b34801561039757600080fd5b506101c2600480360360208110156103ae57600080fd5b5035600160a060020a03166113d4565b3480156103ca57600080fd5b506101c2611465565b3480156103df57600080fd5b506103fd600480360360208110156103f657600080fd5b5035611575565b60408051600160a060020a038916815267ffffffffffffffff8816602082015290810186600681111561042c57fe5b60ff16815260200185815260200184815260200183815260200182815260200197505050505050505060405180910390f35b34801561046a57600080fd5b506104736115e9565b60408051600160a060020a039092168252519081900360200190f35b34801561049b57600080fd5b506101996115f8565b3480156104b057600080fd5b50610154611609565b3480156104c557600080fd5b506104e3600480360360208110156104dc57600080fd5b503561160f565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561051f578181015183820152602001610507565b505050509050019250505060405180910390f35b34801561053f57600080fd5b506101c26004803603604081101561055657600080fd5b600160a060020a03823516919081019060408101602082013564010000000081111561058157600080fd5b82018360208201111561059357600080fd5b803590602001918460208302840111640100000000831117156105b557600080fd5b509092509050611671565b3480156105cc57600080fd5b506101c2600480360360408110156105e357600080fd5b50600160a060020a0381358116916020013516611c82565b34801561060757600080fd5b506106256004803603602081101561061e57600080fd5b5035611d15565b604051808581526020018467ffffffffffffffff1667ffffffffffffffff16815260200183600160a060020a0316600160a060020a0316815260200182600181111561066d57fe5b60ff16815260200194505050505060405180910390f35b34801561069057600080fd5b506101c2600480360360208110156106a757600080fd5b5035600160a060020a0316611d6d565b3480156106c357600080fd5b50610473611dc2565b3480156106d857600080fd5b506101c2600480360360208110156106ef57600080fd5b5035611dd1565b60035490565b600160a060020a0316600090815260056020526040902054151590565b61072233610839565b151561079e576040805160e560020a62461bcd02815260206004820152603060248201527f506175736572526f6c653a2063616c6c657220646f6573206e6f74206861766560448201527f207468652050617573657220726f6c6500000000000000000000000000000000606482015290519081900360840190fd5b60025460ff1615156107fa576040805160e560020a62461bcd02815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015290519081900360640190fd5b6002805460ff191690556040805133815290517f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa9181900360200190a1565b600061084c60018363ffffffff61204316565b92915050565b61085a6115f8565b151561089e576040805160e560020a62461bcd028152602060048201819052602482015260008051602061262c833981519152604482015290519081900360640190fd5b6008805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b6108d56115f8565b1515610919576040805160e560020a62461bcd028152602060048201819052602482015260008051602061262c833981519152604482015290519081900360640190fd5b61094c8160048481548110151561092c57fe5b9060005260206000209060050201600301546120eb90919063ffffffff16565b600480548490811061095a57fe5b9060005260206000209060050201600301819055505050565b60025460ff1690565b60025460ff16156109c5576040805160e560020a62461bcd028152602060048201526010602482015260008051602061264c833981519152604482015290519081900360640190fd5b600854604080517ff291fe9f00000000000000000000000000000000000000000000000000000000815233600482015234602482015260006044820181905260648201819052608482018190529151606093600160a060020a03169263f291fe9f9260a48082019391829003018186803b158015610a4257600080fd5b505afa158015610a56573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015610a7f57600080fd5b810190808051640100000000811115610a9757600080fd5b82016020810184811115610aaa57600080fd5b8151856020820283011164010000000082111715610ac757600080fd5b5090945060009350610ad892505050565b816008815181101515610ae757fe5b906020019060200201516003811115610afc57fe5b6003811115610b0757fe5b6008805484519290931492600160a060020a031691633fbf509c9185918110610b2c57fe5b906020019060200201516003811115610b4157fe5b6040518263ffffffff1660e060020a02815260040180826003811115610b6357fe5b60ff16815260200191505060006040518083038186803b158015610b8657600080fd5b505afa158015610b9a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015610bc357600080fd5b810190808051640100000000811115610bdb57600080fd5b82016020810184811115610bee57600080fd5b8151640100000000811182820187101715610c0857600080fd5b5050929190505050901515610c9e5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610c63578181015183820152602001610c4b565b50505050905090810190601f168015610c905780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506040805160e08101825233815267ffffffffffffffff42811660208301908152600193830184815234606085015260006080850181905260a0850181905260c0850181905260048054968701808255915284517f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b6005909702969096018054935190941674010000000000000000000000000000000000000000027fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff600160a060020a0390971673ffffffffffffffffffffffffffffffffffffffff19909416939093179590951691909117808355905190829060e060020a60ff02191660e060020a836006811115610dae57fe5b021790555060608201516001808301919091556080830151600283015560a0830151600383015560c09092015160049091015533600090815260056020526040902054610e0292509063ffffffff6120eb16565b336000818152600560205260409020919091556004547f27d02633599e682f984c85c4f8d2036761dae6638a56360aaa1fb6050daf7a19903490610e4d90600163ffffffff61214f16565b6040805192835260208301919091528051918290030190a250565b610e71336121af565b565b610e7b6115f8565b1515610ebf576040805160e560020a62461bcd028152602060048201819052602482015260008051602061262c833981519152604482015290519081900360640190fd5b60008054604051600160a060020a03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a36000805473ffffffffffffffffffffffffffffffffffffffff19169055565b60056020526000908152604090205481565b60025460ff1615610f71576040805160e560020a62461bcd028152602060048201526010602482015260008051602061264c833981519152604482015290519081900360640190fd5b600754600160a060020a03163314610ff9576040805160e560020a62461bcd02815260206004820152602660248201527f53656e6465722073686f756c642062652045746865725061796d656e74436f6e60448201527f6669726d65720000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b60035467ffffffffffffffff83161061105c576040805160e560020a62461bcd02815260206004820152601760248201527f5f6f72646572496e64657820697320746f6f2068696768000000000000000000604482015290519081900360640190fd5b600060038367ffffffffffffffff1681548110151561107757fe5b6000918252602090912060029091020190506001808281015460e060020a900460ff16908111156110a457fe5b1415611120576040805160e560020a62461bcd02815260206004820152602160248201527f65786368616e67654f726465722e73746174757320697320636f6e6669726d6560448201527f6400000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b908155600101805460e060020a60ff02191660e060020a17905550565b600754600160a060020a031633146111c5576040805160e560020a62461bcd02815260206004820152602660248201527f53656e6465722073686f756c642062652045746865725061796d656e74436f6e60448201527f6669726d65720000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b60005b818110156113cf5760008383838181106111de57fe5b602002919091013591506001905060048054839081106111fa57fe5b600091825260209091206005909102015460e060020a900460ff16600681111561122057fe5b1461129b576040805160e560020a62461bcd02815260206004820152602260248201527f5061796d656e74206d75737420626520696e207374617465205265717565737460448201527f6564000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b600480828154811015156112ab57fe5b60009182526020909120600590910201805460e060020a60ff02191660e060020a8360068111156112d857fe5b021790555061132b6001600560006004858154811015156112f557fe5b60009182526020808320600590920290910154600160a060020a031683528201929092526040019020549063ffffffff61214f16565b6005600060048481548110151561133e57fe5b60009182526020808320600590920290910154600160a060020a03168352820192909252604001902055600480548290811061137657fe5b600091825260209182902060059091020154604080518481529051600160a060020a03909216927fea11d4eb5784e0cc5db25bae5f508815b9a230763736bb69b767af12175329e192918290030190a2506001016111c8565b505050565b6113dd33610839565b1515611459576040805160e560020a62461bcd02815260206004820152603060248201527f506175736572526f6c653a2063616c6c657220646f6573206e6f74206861766560448201527f207468652050617573657220726f6c6500000000000000000000000000000000606482015290519081900360840190fd5b611462816121f7565b50565b61146e33610839565b15156114ea576040805160e560020a62461bcd02815260206004820152603060248201527f506175736572526f6c653a2063616c6c657220646f6573206e6f74206861766560448201527f207468652050617573657220726f6c6500000000000000000000000000000000606482015290519081900360840190fd5b60025460ff1615611533576040805160e560020a62461bcd028152602060048201526010602482015260008051602061264c833981519152604482015290519081900360640190fd5b6002805460ff191660011790556040805133815290517f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589181900360200190a1565b600480548290811061158357fe5b600091825260209091206005909102018054600182015460028301546003840154600490940154600160a060020a038416955074010000000000000000000000000000000000000000840467ffffffffffffffff169460e060020a90940460ff16939087565b600054600160a060020a031690565b600054600160a060020a0316331490565b60045490565b60008181526006602090815260409182902080548351818402810184019094528084526060939283018282801561166557602002820191906000526020600020905b815481526020019060010190808311611651575b50505050509050919050565b60025460ff16156116ba576040805160e560020a62461bcd028152602060048201526010602482015260008051602061264c833981519152604482015290519081900360640190fd5b600754600160a060020a03163314611742576040805160e560020a62461bcd02815260206004820152602660248201527f53656e6465722073686f756c642062652045746865725061796d656e74436f6e60448201527f6669726d65720000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b6008546040517fd438edb9000000000000000000000000000000000000000000000000000000008152600160a060020a039091169063d438edb990600190600401808260ff16815260200191505060206040518083038186803b1580156117a857600080fd5b505afa1580156117bc573d6000803e3d6000fd5b505050506040513d60208110156117d257600080fd5b5051806118595750600860009054906101000a9004600160a060020a0316600160a060020a0316635c975abb6040518163ffffffff1660e060020a02815260040160206040518083038186803b15801561182b57600080fd5b505afa15801561183f573d6000803e3d6000fd5b505050506040513d602081101561185557600080fd5b5051155b15156118af576040805160e560020a62461bcd02815260206004820152601760248201527f626f7420696e20737461746520696e766573746d656e74000000000000000000604482015290519081900360640190fd5b60045460001061192f576040805160e560020a62461bcd02815260206004820152602c60248201527f4174206c65617374206f6e65207061796d656e7420697320726571756972656460448201527f20746f2065786368616e67650000000000000000000000000000000000000000606482015290519081900360840190fd5b611937612606565b608060405190810160405280600081526020014267ffffffffffffffff16815260200185600160a060020a031681526020016000600181111561197657fe5b9052600380546001818101808455600093909352835160029092027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b810192835560208501517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c90910180546040870151600160a060020a031668010000000000000000027fffffffff0000000000000000000000000000000000000000ffffffffffffffff67ffffffffffffffff90941667ffffffffffffffff19909216919091179290921691909117808255606086015195965093948694909260e060020a60ff02199091169060e060020a908490811115611a7057fe5b0217905550506003546000190160009081526006602052604081209092509050815b67ffffffffffffffff8116851115611bc3576000868667ffffffffffffffff8416818110611abc57fe5b9050602002013590506000600482815481101515611ad657fe5b6000918252602090912060059091020190506001815460e060020a900460ff166006811115611b0157fe5b14611b56576040805160e560020a62461bcd02815260206004820152601d60248201527f73686f756c6420626520696e2073746174757320726571756573746564000000604482015290519081900360640190fd5b805460e060020a60ff0219167c0200000000000000000000000000000000000000000000000000000000178155835460018101855560008581526020902001829055611ba18261223f565b6001810154611bb790869063ffffffff6120eb16565b94505050600101611a92565b5033600160a060020a03167f867bc23ca6c178085d8b0d3346dd80b94773ac4f234da4ddc6ffe6d3a9fdad5f8260405180806020018281038252838181548152602001915080548015611c3557602002820191906000526020600020905b815481526020019060010190808311611c21575b50509250505060405180910390a2604051600160a060020a0387169083156108fc029084906000818181858888f19350505050158015611c79573d6000803e3d6000fd5b50505050505050565b611c8a6115f8565b1515611cce576040805160e560020a62461bcd028152602060048201819052602482015260008051602061262c833981519152604482015290519081900360640190fd5b6008805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a038316179055611cff81611d6d565b611d08826113d4565b611d11816113d4565b5050565b6003805482908110611d2357fe5b60009182526020909120600290910201805460019091015490915067ffffffffffffffff811690680100000000000000008104600160a060020a03169060e060020a900460ff1684565b611d756115f8565b1515611db9576040805160e560020a62461bcd028152602060048201819052602482015260008051602061262c833981519152604482015290519081900360640190fd5b611462816123ec565b600754600160a060020a031681565b6000600482815481101515611de257fe5b60009182526020909120600160059092020190810154815491925090600160a060020a0316331480611e1e5750600754600160a060020a031633145b1515611e9a576040805160e560020a62461bcd02815260206004820152602160248201527f526566756e6420617265206e6f7420656e61626c656420666f722073656e646560448201527f7200000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b6004825460e060020a900460ff166006811115611eb357fe5b14611f2e576040805160e560020a62461bcd02815260206004820152603460248201527f65746865725061796d656e742e7374617475732073686f756c6420626520506160448201527f796d656e745374617475732e52656a6563746564000000000000000000000000606482015290519081900360840190fd5b3031811115611fad576040805160e560020a62461bcd02815260206004820152603160248201527f45786368616e6765205661756c742062616c616e636520646f65736e2774206860448201527f61766520656e6f7567682066756e64732e000000000000000000000000000000606482015290519081900360840190fd5b815460e060020a60ff0219167c0500000000000000000000000000000000000000000000000000000000178255604051339082156108fc029083906000818181858888f19350505050158015612007573d6000803e3d6000fd5b5060408051828152905133917f87939864e1fcd7919e055b4a6f27fd99527425bbecee1458e06ab461914bf32d919081900360200190a2505050565b6000600160a060020a03821615156120cb576040805160e560020a62461bcd02815260206004820152602260248201527f526f6c65733a206163636f756e7420697320746865207a65726f20616464726560448201527f7373000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b50600160a060020a03166000908152602091909152604090205460ff1690565b600082820183811015612148576040805160e560020a62461bcd02815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6000828211156121a9576040805160e560020a62461bcd02815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6121c060018263ffffffff6124da16565b604051600160a060020a038216907fcd265ebaf09df2871cc7bd4133404a235ba12eff2041bb89d9c714a2621c7c7e90600090a250565b61220860018263ffffffff61258216565b604051600160a060020a038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b600060048281548110151561225057fe5b600091825260208083206005928302018054600160a060020a0316845291905260409091205490915061228a90600163ffffffff61214f16565b8154600160a060020a03908116600090815260056020526040808220939093556008548454600186015485517fbf6bffe20000000000000000000000000000000000000000000000000000000081529185166004830152602482015260448101879052935192169263bf6bffe2926064808301939282900301818387803b15801561231457600080fd5b505af1158015612328573d6000803e3d6000fd5b5050825460e060020a60ff0219167c03000000000000000000000000000000000000000000000000000000001783555050600854604080517f3ba0b9a90000000000000000000000000000000000000000000000000000000081529051600160a060020a0390921691633ba0b9a991600480820192602092909190829003018186803b1580156123b757600080fd5b505afa1580156123cb573d6000803e3d6000fd5b505050506040513d60208110156123e157600080fd5b505160049091015550565b600160a060020a0381161515612472576040805160e560020a62461bcd02815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b60008054604051600160a060020a03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a36000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b6124e48282612043565b1515612560576040805160e560020a62461bcd02815260206004820152602160248201527f526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c60448201527f6500000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b600160a060020a0316600090815260209190915260409020805460ff19169055565b61258c8282612043565b156125e1576040805160e560020a62461bcd02815260206004820152601f60248201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c6500604482015290519081900360640190fd5b600160a060020a0316600090815260209190915260409020805460ff19166001179055565b604080516080810182526000808252602082018190529181018290529060608201529056fe4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65725061757361626c653a2070617573656400000000000000000000000000000000a165627a7a7230582001e2c5fc2252eb52e1c397afe1936aece7ffc4b43d0acfa71b87ba959a0f23ab0029000000000000000000000000aa39d13816885c7e8d6d2446e2dced8cbab3c065

Deployed Bytecode

0x60806040526004361061013a5763ffffffff60e060020a600035041663241b6ae6811461013f57806330748be0146101665780633f4ba83a146101ad57806346fbf68e146101c45780634fb7eed3146101f757806358ccf6b61461022a5780635c975abb1461025a57806363bdb94b1461026f5780636ef8d66d14610277578063715018a61461028c578063796be41a146102a15780637ace5778146102d45780637c48522f1461030e57806382dc1ec41461038b5780638456cb59146103be57806387d81789146103d35780638da5cb5b1461045e5780638f32d59b1461048f578063982cc3c9146104a4578063bdba5d4e146104b9578063bef9045914610533578063c89288e5146105c0578063d2485f26146105fb578063f2fde38b14610684578063f3612cb3146106b7578063f63813f4146106cc575b600080fd5b34801561014b57600080fd5b506101546106f6565b60408051918252519081900360200190f35b34801561017257600080fd5b506101996004803603602081101561018957600080fd5b5035600160a060020a03166106fc565b604080519115158252519081900360200190f35b3480156101b957600080fd5b506101c2610719565b005b3480156101d057600080fd5b50610199600480360360208110156101e757600080fd5b5035600160a060020a0316610839565b34801561020357600080fd5b506101c26004803603602081101561021a57600080fd5b5035600160a060020a0316610852565b34801561023657600080fd5b506101c26004803603604081101561024d57600080fd5b50803590602001356108cd565b34801561026657600080fd5b50610199610973565b6101c261097c565b34801561028357600080fd5b506101c2610e68565b34801561029857600080fd5b506101c2610e73565b3480156102ad57600080fd5b50610154600480360360208110156102c457600080fd5b5035600160a060020a0316610f16565b3480156102e057600080fd5b506101c2600480360360408110156102f757600080fd5b5067ffffffffffffffff8135169060200135610f28565b34801561031a57600080fd5b506101c26004803603602081101561033157600080fd5b81019060208101813564010000000081111561034c57600080fd5b82018360208201111561035e57600080fd5b8035906020019184602083028401116401000000008311171561038057600080fd5b50909250905061113d565b34801561039757600080fd5b506101c2600480360360208110156103ae57600080fd5b5035600160a060020a03166113d4565b3480156103ca57600080fd5b506101c2611465565b3480156103df57600080fd5b506103fd600480360360208110156103f657600080fd5b5035611575565b60408051600160a060020a038916815267ffffffffffffffff8816602082015290810186600681111561042c57fe5b60ff16815260200185815260200184815260200183815260200182815260200197505050505050505060405180910390f35b34801561046a57600080fd5b506104736115e9565b60408051600160a060020a039092168252519081900360200190f35b34801561049b57600080fd5b506101996115f8565b3480156104b057600080fd5b50610154611609565b3480156104c557600080fd5b506104e3600480360360208110156104dc57600080fd5b503561160f565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561051f578181015183820152602001610507565b505050509050019250505060405180910390f35b34801561053f57600080fd5b506101c26004803603604081101561055657600080fd5b600160a060020a03823516919081019060408101602082013564010000000081111561058157600080fd5b82018360208201111561059357600080fd5b803590602001918460208302840111640100000000831117156105b557600080fd5b509092509050611671565b3480156105cc57600080fd5b506101c2600480360360408110156105e357600080fd5b50600160a060020a0381358116916020013516611c82565b34801561060757600080fd5b506106256004803603602081101561061e57600080fd5b5035611d15565b604051808581526020018467ffffffffffffffff1667ffffffffffffffff16815260200183600160a060020a0316600160a060020a0316815260200182600181111561066d57fe5b60ff16815260200194505050505060405180910390f35b34801561069057600080fd5b506101c2600480360360208110156106a757600080fd5b5035600160a060020a0316611d6d565b3480156106c357600080fd5b50610473611dc2565b3480156106d857600080fd5b506101c2600480360360208110156106ef57600080fd5b5035611dd1565b60035490565b600160a060020a0316600090815260056020526040902054151590565b61072233610839565b151561079e576040805160e560020a62461bcd02815260206004820152603060248201527f506175736572526f6c653a2063616c6c657220646f6573206e6f74206861766560448201527f207468652050617573657220726f6c6500000000000000000000000000000000606482015290519081900360840190fd5b60025460ff1615156107fa576040805160e560020a62461bcd02815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015290519081900360640190fd5b6002805460ff191690556040805133815290517f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa9181900360200190a1565b600061084c60018363ffffffff61204316565b92915050565b61085a6115f8565b151561089e576040805160e560020a62461bcd028152602060048201819052602482015260008051602061262c833981519152604482015290519081900360640190fd5b6008805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b6108d56115f8565b1515610919576040805160e560020a62461bcd028152602060048201819052602482015260008051602061262c833981519152604482015290519081900360640190fd5b61094c8160048481548110151561092c57fe5b9060005260206000209060050201600301546120eb90919063ffffffff16565b600480548490811061095a57fe5b9060005260206000209060050201600301819055505050565b60025460ff1690565b60025460ff16156109c5576040805160e560020a62461bcd028152602060048201526010602482015260008051602061264c833981519152604482015290519081900360640190fd5b600854604080517ff291fe9f00000000000000000000000000000000000000000000000000000000815233600482015234602482015260006044820181905260648201819052608482018190529151606093600160a060020a03169263f291fe9f9260a48082019391829003018186803b158015610a4257600080fd5b505afa158015610a56573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015610a7f57600080fd5b810190808051640100000000811115610a9757600080fd5b82016020810184811115610aaa57600080fd5b8151856020820283011164010000000082111715610ac757600080fd5b5090945060009350610ad892505050565b816008815181101515610ae757fe5b906020019060200201516003811115610afc57fe5b6003811115610b0757fe5b6008805484519290931492600160a060020a031691633fbf509c9185918110610b2c57fe5b906020019060200201516003811115610b4157fe5b6040518263ffffffff1660e060020a02815260040180826003811115610b6357fe5b60ff16815260200191505060006040518083038186803b158015610b8657600080fd5b505afa158015610b9a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015610bc357600080fd5b810190808051640100000000811115610bdb57600080fd5b82016020810184811115610bee57600080fd5b8151640100000000811182820187101715610c0857600080fd5b5050929190505050901515610c9e5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610c63578181015183820152602001610c4b565b50505050905090810190601f168015610c905780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506040805160e08101825233815267ffffffffffffffff42811660208301908152600193830184815234606085015260006080850181905260a0850181905260c0850181905260048054968701808255915284517f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b6005909702969096018054935190941674010000000000000000000000000000000000000000027fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff600160a060020a0390971673ffffffffffffffffffffffffffffffffffffffff19909416939093179590951691909117808355905190829060e060020a60ff02191660e060020a836006811115610dae57fe5b021790555060608201516001808301919091556080830151600283015560a0830151600383015560c09092015160049091015533600090815260056020526040902054610e0292509063ffffffff6120eb16565b336000818152600560205260409020919091556004547f27d02633599e682f984c85c4f8d2036761dae6638a56360aaa1fb6050daf7a19903490610e4d90600163ffffffff61214f16565b6040805192835260208301919091528051918290030190a250565b610e71336121af565b565b610e7b6115f8565b1515610ebf576040805160e560020a62461bcd028152602060048201819052602482015260008051602061262c833981519152604482015290519081900360640190fd5b60008054604051600160a060020a03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a36000805473ffffffffffffffffffffffffffffffffffffffff19169055565b60056020526000908152604090205481565b60025460ff1615610f71576040805160e560020a62461bcd028152602060048201526010602482015260008051602061264c833981519152604482015290519081900360640190fd5b600754600160a060020a03163314610ff9576040805160e560020a62461bcd02815260206004820152602660248201527f53656e6465722073686f756c642062652045746865725061796d656e74436f6e60448201527f6669726d65720000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b60035467ffffffffffffffff83161061105c576040805160e560020a62461bcd02815260206004820152601760248201527f5f6f72646572496e64657820697320746f6f2068696768000000000000000000604482015290519081900360640190fd5b600060038367ffffffffffffffff1681548110151561107757fe5b6000918252602090912060029091020190506001808281015460e060020a900460ff16908111156110a457fe5b1415611120576040805160e560020a62461bcd02815260206004820152602160248201527f65786368616e67654f726465722e73746174757320697320636f6e6669726d6560448201527f6400000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b908155600101805460e060020a60ff02191660e060020a17905550565b600754600160a060020a031633146111c5576040805160e560020a62461bcd02815260206004820152602660248201527f53656e6465722073686f756c642062652045746865725061796d656e74436f6e60448201527f6669726d65720000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b60005b818110156113cf5760008383838181106111de57fe5b602002919091013591506001905060048054839081106111fa57fe5b600091825260209091206005909102015460e060020a900460ff16600681111561122057fe5b1461129b576040805160e560020a62461bcd02815260206004820152602260248201527f5061796d656e74206d75737420626520696e207374617465205265717565737460448201527f6564000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b600480828154811015156112ab57fe5b60009182526020909120600590910201805460e060020a60ff02191660e060020a8360068111156112d857fe5b021790555061132b6001600560006004858154811015156112f557fe5b60009182526020808320600590920290910154600160a060020a031683528201929092526040019020549063ffffffff61214f16565b6005600060048481548110151561133e57fe5b60009182526020808320600590920290910154600160a060020a03168352820192909252604001902055600480548290811061137657fe5b600091825260209182902060059091020154604080518481529051600160a060020a03909216927fea11d4eb5784e0cc5db25bae5f508815b9a230763736bb69b767af12175329e192918290030190a2506001016111c8565b505050565b6113dd33610839565b1515611459576040805160e560020a62461bcd02815260206004820152603060248201527f506175736572526f6c653a2063616c6c657220646f6573206e6f74206861766560448201527f207468652050617573657220726f6c6500000000000000000000000000000000606482015290519081900360840190fd5b611462816121f7565b50565b61146e33610839565b15156114ea576040805160e560020a62461bcd02815260206004820152603060248201527f506175736572526f6c653a2063616c6c657220646f6573206e6f74206861766560448201527f207468652050617573657220726f6c6500000000000000000000000000000000606482015290519081900360840190fd5b60025460ff1615611533576040805160e560020a62461bcd028152602060048201526010602482015260008051602061264c833981519152604482015290519081900360640190fd5b6002805460ff191660011790556040805133815290517f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589181900360200190a1565b600480548290811061158357fe5b600091825260209091206005909102018054600182015460028301546003840154600490940154600160a060020a038416955074010000000000000000000000000000000000000000840467ffffffffffffffff169460e060020a90940460ff16939087565b600054600160a060020a031690565b600054600160a060020a0316331490565b60045490565b60008181526006602090815260409182902080548351818402810184019094528084526060939283018282801561166557602002820191906000526020600020905b815481526020019060010190808311611651575b50505050509050919050565b60025460ff16156116ba576040805160e560020a62461bcd028152602060048201526010602482015260008051602061264c833981519152604482015290519081900360640190fd5b600754600160a060020a03163314611742576040805160e560020a62461bcd02815260206004820152602660248201527f53656e6465722073686f756c642062652045746865725061796d656e74436f6e60448201527f6669726d65720000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b6008546040517fd438edb9000000000000000000000000000000000000000000000000000000008152600160a060020a039091169063d438edb990600190600401808260ff16815260200191505060206040518083038186803b1580156117a857600080fd5b505afa1580156117bc573d6000803e3d6000fd5b505050506040513d60208110156117d257600080fd5b5051806118595750600860009054906101000a9004600160a060020a0316600160a060020a0316635c975abb6040518163ffffffff1660e060020a02815260040160206040518083038186803b15801561182b57600080fd5b505afa15801561183f573d6000803e3d6000fd5b505050506040513d602081101561185557600080fd5b5051155b15156118af576040805160e560020a62461bcd02815260206004820152601760248201527f626f7420696e20737461746520696e766573746d656e74000000000000000000604482015290519081900360640190fd5b60045460001061192f576040805160e560020a62461bcd02815260206004820152602c60248201527f4174206c65617374206f6e65207061796d656e7420697320726571756972656460448201527f20746f2065786368616e67650000000000000000000000000000000000000000606482015290519081900360840190fd5b611937612606565b608060405190810160405280600081526020014267ffffffffffffffff16815260200185600160a060020a031681526020016000600181111561197657fe5b9052600380546001818101808455600093909352835160029092027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b810192835560208501517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c90910180546040870151600160a060020a031668010000000000000000027fffffffff0000000000000000000000000000000000000000ffffffffffffffff67ffffffffffffffff90941667ffffffffffffffff19909216919091179290921691909117808255606086015195965093948694909260e060020a60ff02199091169060e060020a908490811115611a7057fe5b0217905550506003546000190160009081526006602052604081209092509050815b67ffffffffffffffff8116851115611bc3576000868667ffffffffffffffff8416818110611abc57fe5b9050602002013590506000600482815481101515611ad657fe5b6000918252602090912060059091020190506001815460e060020a900460ff166006811115611b0157fe5b14611b56576040805160e560020a62461bcd02815260206004820152601d60248201527f73686f756c6420626520696e2073746174757320726571756573746564000000604482015290519081900360640190fd5b805460e060020a60ff0219167c0200000000000000000000000000000000000000000000000000000000178155835460018101855560008581526020902001829055611ba18261223f565b6001810154611bb790869063ffffffff6120eb16565b94505050600101611a92565b5033600160a060020a03167f867bc23ca6c178085d8b0d3346dd80b94773ac4f234da4ddc6ffe6d3a9fdad5f8260405180806020018281038252838181548152602001915080548015611c3557602002820191906000526020600020905b815481526020019060010190808311611c21575b50509250505060405180910390a2604051600160a060020a0387169083156108fc029084906000818181858888f19350505050158015611c79573d6000803e3d6000fd5b50505050505050565b611c8a6115f8565b1515611cce576040805160e560020a62461bcd028152602060048201819052602482015260008051602061262c833981519152604482015290519081900360640190fd5b6008805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a038316179055611cff81611d6d565b611d08826113d4565b611d11816113d4565b5050565b6003805482908110611d2357fe5b60009182526020909120600290910201805460019091015490915067ffffffffffffffff811690680100000000000000008104600160a060020a03169060e060020a900460ff1684565b611d756115f8565b1515611db9576040805160e560020a62461bcd028152602060048201819052602482015260008051602061262c833981519152604482015290519081900360640190fd5b611462816123ec565b600754600160a060020a031681565b6000600482815481101515611de257fe5b60009182526020909120600160059092020190810154815491925090600160a060020a0316331480611e1e5750600754600160a060020a031633145b1515611e9a576040805160e560020a62461bcd02815260206004820152602160248201527f526566756e6420617265206e6f7420656e61626c656420666f722073656e646560448201527f7200000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b6004825460e060020a900460ff166006811115611eb357fe5b14611f2e576040805160e560020a62461bcd02815260206004820152603460248201527f65746865725061796d656e742e7374617475732073686f756c6420626520506160448201527f796d656e745374617475732e52656a6563746564000000000000000000000000606482015290519081900360840190fd5b3031811115611fad576040805160e560020a62461bcd02815260206004820152603160248201527f45786368616e6765205661756c742062616c616e636520646f65736e2774206860448201527f61766520656e6f7567682066756e64732e000000000000000000000000000000606482015290519081900360840190fd5b815460e060020a60ff0219167c0500000000000000000000000000000000000000000000000000000000178255604051339082156108fc029083906000818181858888f19350505050158015612007573d6000803e3d6000fd5b5060408051828152905133917f87939864e1fcd7919e055b4a6f27fd99527425bbecee1458e06ab461914bf32d919081900360200190a2505050565b6000600160a060020a03821615156120cb576040805160e560020a62461bcd02815260206004820152602260248201527f526f6c65733a206163636f756e7420697320746865207a65726f20616464726560448201527f7373000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b50600160a060020a03166000908152602091909152604090205460ff1690565b600082820183811015612148576040805160e560020a62461bcd02815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6000828211156121a9576040805160e560020a62461bcd02815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6121c060018263ffffffff6124da16565b604051600160a060020a038216907fcd265ebaf09df2871cc7bd4133404a235ba12eff2041bb89d9c714a2621c7c7e90600090a250565b61220860018263ffffffff61258216565b604051600160a060020a038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b600060048281548110151561225057fe5b600091825260208083206005928302018054600160a060020a0316845291905260409091205490915061228a90600163ffffffff61214f16565b8154600160a060020a03908116600090815260056020526040808220939093556008548454600186015485517fbf6bffe20000000000000000000000000000000000000000000000000000000081529185166004830152602482015260448101879052935192169263bf6bffe2926064808301939282900301818387803b15801561231457600080fd5b505af1158015612328573d6000803e3d6000fd5b5050825460e060020a60ff0219167c03000000000000000000000000000000000000000000000000000000001783555050600854604080517f3ba0b9a90000000000000000000000000000000000000000000000000000000081529051600160a060020a0390921691633ba0b9a991600480820192602092909190829003018186803b1580156123b757600080fd5b505afa1580156123cb573d6000803e3d6000fd5b505050506040513d60208110156123e157600080fd5b505160049091015550565b600160a060020a0381161515612472576040805160e560020a62461bcd02815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b60008054604051600160a060020a03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a36000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b6124e48282612043565b1515612560576040805160e560020a62461bcd02815260206004820152602160248201527f526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c60448201527f6500000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b600160a060020a0316600090815260209190915260409020805460ff19169055565b61258c8282612043565b156125e1576040805160e560020a62461bcd02815260206004820152601f60248201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c6500604482015290519081900360640190fd5b600160a060020a0316600090815260209190915260409020805460ff19166001179055565b604080516080810182526000808252602082018190529181018290529060608201529056fe4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65725061757361626c653a2070617573656400000000000000000000000000000000a165627a7a7230582001e2c5fc2252eb52e1c397afe1936aece7ffc4b43d0acfa71b87ba959a0f23ab0029

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

000000000000000000000000aa39d13816885c7e8d6d2446e2dced8cbab3c065

-----Decoded View---------------
Arg [0] : _paymentConfirmer (address): 0xAa39D13816885c7e8d6D2446E2dced8cbab3c065

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000aa39d13816885c7e8d6d2446e2dced8cbab3c065


Deployed Bytecode Sourcemap

402:9704:2:-;;;;;;;;;-1:-1:-1;;;402:9704:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9828:110;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9828:110:2;;;;;;;;;;;;;;;;;;;;9555:142;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9555:142:2;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;9555:142:2;-1:-1:-1;;;;;9555:142:2;;;;;;;;;;;;;;;;;;;;;1838:115:14;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1838:115:14;;;;;;446:107:15;;8:9:-1;5:2;;;30:1;27;20:12;5:2;446:107:15;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;446:107:15;-1:-1:-1;;;;;446:107:15;;;3625:104:2;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3625:104:2;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;3625:104:2;-1:-1:-1;;;;;3625:104:2;;;3982:197;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3982:197:2;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;3982:197:2;;;;;;;;1078:76:14;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1078:76:14;;;;4479:737:2;;;;655:75:15;;8:9:-1;5:2;;;30:1;27;20:12;5:2;655:75:15;;;;1599:137:13;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1599:137:13;;;;1586:51:2;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1586:51:2;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1586:51:2;-1:-1:-1;;;;;1586:51:2;;;9055:490;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9055:490:2;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;9055:490:2;;;;;;;;;;5333:870;;8:9:-1;5:2;;;30:1;27;20:12;5:2;5333:870:2;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;5333:870:2;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;5333:870:2;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;5333:870:2;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;39:11;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;-1:-1;5333:870:2;;-1:-1:-1;5333:870:2;-1:-1:-1;5333:870:2;;559:90:15;;8:9:-1;5:2;;;30:1;27;20:12;5:2;559:90:15;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;559:90:15;-1:-1:-1;;;;;559:90:15;;;1635:113:14;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1635:113:14;;;;1457:30:2;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1457:30:2;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1457:30:2;;;;;;;-1:-1:-1;;;;;1457:30:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;814:77:13;;8:9:-1;5:2;;;30:1;27;20:12;5:2;814:77:13;;;;;;;;-1:-1:-1;;;;;814:77:13;;;;;;;;;;;;;;1165:90;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1165:90:13;;;;9715:103:2;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9715:103:2;;;;9948:146;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9948:146:2;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;9948:146:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;9948:146:2;;;;;;;;;;;;;;;;;7289:1284;;8:9:-1;5:2;;;30:1;27;20:12;5:2;7289:1284:2;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;7289:1284:2;;;;;;;;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;7289:1284:2;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;7289:1284:2;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;39:11;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;-1:-1;7289:1284:2;;-1:-1:-1;7289:1284:2;-1:-1:-1;7289:1284:2;;3732:240;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3732:240:2;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;3732:240:2;;;;;;;;;;;1330:37;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1330:37:2;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1330:37:2;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1330:37:2;-1:-1:-1;;;;;1330:37:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1885:107:13;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1885:107:13;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1885:107:13;-1:-1:-1;;;;;1885:107:13;;;1903:31:2;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1903:31:2;;;;6294:860;;8:9:-1;5:2;;;30:1;27;20:12;5:2;6294:860:2;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;6294:860:2;;;9828:110;9910:14;:21;9828:110;:::o;9555:142::-;-1:-1:-1;;;;;9651:33:2;9627:4;9651:33;;;:19;:33;;;;;;:38;;;9555:142::o;1838:115:14:-;349:20:15;358:10;349:8;:20::i;:::-;341:81;;;;;;;-1:-1:-1;;;;;341:81:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1498:7:14;;;;1490:40;;;;;;;-1:-1:-1;;;;;1490:40:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;1896:7;:15;;-1:-1:-1;;1896:15:14;;;1926:20;;;1935:10;1926:20;;;;;;;;;;;;;1838:115::o;446:107:15:-;502:4;525:21;:8;538:7;525:21;:12;:21;:::i;:::-;518:28;446:107;-1:-1:-1;;446:107:15:o;3625:104:2:-;1018:9:13;:7;:9::i;:::-;1010:54;;;;;;;-1:-1:-1;;;;;1010:54:13;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;1010:54:13;;;;;;;;;;;;;;;3698:10:2;:24;;-1:-1:-1;;3698:24:2;-1:-1:-1;;;;;3698:24:2;;;;;;;;;;3625:104::o;3982:197::-;1018:9:13;:7;:9::i;:::-;1010:54;;;;;;;-1:-1:-1;;;;;1010:54:13;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;1010:54:13;;;;;;;;;;;;;;;4121:51:2;4158:13;4121:8;4130:9;4121:19;;;;;;;;;;;;;;;;;;;;:32;;;:36;;:51;;;;:::i;:::-;4086:8;:19;;4095:9;;4086:19;;;;;;;;;;;;;;;;:32;;:86;;;;3982:197;;:::o;1078:76:14:-;1140:7;;;;1078:76;:::o;4479:737:2:-;1307:7:14;;;;1306:8;1298:37;;;;;-1:-1:-1;;;;;1298:37:14;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;1298:37:14;;;;;;;;;;;;;;;4578:10:2;;:97;;;;;;4618:10;4578:97;;;;4630:9;4578:97;;;;-1:-1:-1;4578:97:2;;;;;;;;;;;;;;;;;;;;4547:28;;-1:-1:-1;;;;;4578:10:2;;:39;;:97;;;;;;;;;;;:10;:97;;;5:2:-1;;;;30:1;27;20:12;5:2;4578:97:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;4578:97:2;;;;;;39:16:-1;36:1;17:17;2:54;101:4;4578:97:2;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:2;5:11;;2:2;;;29:1;26;19:12;2:2;4578:97:2;;;;;;19:11:-1;14:3;11:20;8:2;;;44:1;41;34:12;8:2;62:21;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;219:3;213:10;331:9;325:2;311:12;307:21;289:16;285:44;282:59;261:11;247:12;244:29;233:116;230:2;;;362:1;359;352:12;230:2;-1:-1;4578:97:2;;-1:-1:-1;4801:38:2;;-1:-1:-1;4743:96:2;;-1:-1:-1;;;4743:96:2;;4779:14;4794:1;4779:17;;;;;;;;;;;;;;;;;;4743:54;;;;;;;;:96;;;;;;;;4841:10;;;4908:17;;4743:96;;;;;-1:-1:-1;;;;;4841:10:2;;:30;;4908:17;;;;;;;;;;;;;;;;4872:54;;;;;;;;4841:86;;;;;-1:-1:-1;;;4841:86:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4841:86:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;4841:86:2;;;;;;39:16:-1;36:1;17:17;2:54;101:4;4841:86:2;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:2;5:11;;2:2;;;29:1;26;19:12;2:2;4841:86:2;;;;;;19:11:-1;14:3;11:20;8:2;;;44:1;41;34:12;8:2;62:21;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;213:10;;261:11;244:29;;285:43;;;282:58;-1:-1;233:115;230:2;;;361:1;358;351:12;230:2;0:372;;4841:86:2;;;;;;4735:193;;;;;;;-1:-1:-1;;;;;4735:193:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;4735:193:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;4961:82:2;;;;;;;;4974:10;4961:82;;;4993:3;4961:82;;;;;;;;4999:23;4961:82;;;;;;5024:9;4961:82;;;;-1:-1:-1;4961:82:2;;;;;;;;;;;;;;;;;;4947:8;27:10:-1;;23:18;;;45:23;;;4947:97:2;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;4947:97:2;;;-1:-1:-1;;4947:97:2;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;4947:97:2;-1:-1:-1;;;4947:97:2;;;;;;;;;;;;;-1:-1:-1;4947:97:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5108:10;-1:-1:-1;5088:31:2;;;:19;:31;;;;;;:38;;-1:-1:-1;5088:31:2;:38;:35;:38;:::i;:::-;5074:10;5054:31;;;;:19;:31;;;;;:72;;;;5186:8;:15;5141:68;;5175:9;;5186:22;;5206:1;5186:22;:19;:22;:::i;:::-;5141:68;;;;;;;;;;;;;;;;;;;;;;1345:1:14;4479:737:2:o;655:75:15:-;698:25;712:10;698:13;:25::i;:::-;655:75::o;1599:137:13:-;1018:9;:7;:9::i;:::-;1010:54;;;;;;;-1:-1:-1;;;;;1010:54:13;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;1010:54:13;;;;;;;;;;;;;;;1697:1;1681:6;;1660:40;;-1:-1:-1;;;;;1681:6:13;;;;1660:40;;1697:1;;1660:40;1727:1;1710:19;;-1:-1:-1;;1710:19:13;;;1599:137::o;1586:51:2:-;;;;;;;;;;;;;:::o;9055:490::-;1307:7:14;;;;1306:8;1298:37;;;;;-1:-1:-1;;;;;1298:37:14;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;1298:37:14;;;;;;;;;;;;;;;3430:16:2;;-1:-1:-1;;;;;3430:16:2;3416:10;:30;3407:83;;;;;-1:-1:-1;;;;;3407:83:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9201:14;:21;9187:35;;;;9179:71;;;;;-1:-1:-1;;;;;9179:71:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;9260:35;9298:14;9313:11;9298:27;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;9367:24:2;9343:20;;;;;-1:-1:-1;;;9343:20:2;;;;;:48;;;;;;;;;9335:94;;;;;-1:-1:-1;;;;;9335:94:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9439:42;;;9514:24;9491:20;:47;;-1:-1:-1;;;;;;9491:47:2;-1:-1:-1;;;9491:47:2;;;-1:-1:-1;9055:490:2:o;5333:870::-;3430:16;;-1:-1:-1;;;;;3430:16:2;3416:10;:30;3407:83;;;;;-1:-1:-1;;;;;3407:83:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5434:7;5430:767;5447:23;;;5430:767;;;5488:14;5505:11;;5517:2;5505:15;;;;;;;;;;;;;;;-1:-1:-1;5665:23:2;;-1:-1:-1;5635:8:2;:19;;5644:9;;5635:19;;;;;;;;;;;;;;;;;;;:26;-1:-1:-1;;;5635:26:2;;;;:53;;;;;;;;;5627:100;;;;;-1:-1:-1;;;;;5627:100:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5870:22;5841:8;5850:9;5841:19;;;;;;;;;;;;;;;;;;;;;;;:51;;-1:-1:-1;;;;;;5841:51:2;-1:-1:-1;;;5841:51:2;;;;;;;;;;;;;;5967:52;6017:1;5967:19;:45;5987:8;5996:9;5987:19;;;;;;;;;;;;;;;;;;;;;;;;;:24;-1:-1:-1;;;;;5987:24:2;5967:45;;;;;;;;;;;;;;:52;:49;:52;:::i;:::-;5919:19;:45;5939:8;5948:9;5939:19;;;;;;;;;;;;;;;;;;;;;;;;;:24;-1:-1:-1;;;;;5939:24:2;5919:45;;;;;;;;;;;;:100;6150:8;:19;;6159:9;;6150:19;;;;;;;;;;;;;;;;;;;;:24;6129:57;;;;;;;;-1:-1:-1;;;;;6150:24:2;;;;6129:57;;;;;;;;;-1:-1:-1;5472:4:2;;5430:767;;;;5333:870;;:::o;559:90:15:-;349:20;358:10;349:8;:20::i;:::-;341:81;;;;;;;-1:-1:-1;;;;;341:81:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;623:19;634:7;623:10;:19::i;:::-;559:90;:::o;1635:113:14:-;349:20:15;358:10;349:8;:20::i;:::-;341:81;;;;;;;-1:-1:-1;;;;;341:81:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1307:7:14;;;;1306:8;1298:37;;;;;-1:-1:-1;;;;;1298:37:14;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;1298:37:14;;;;;;;;;;;;;;;1694:7;:14;;-1:-1:-1;;1694:14:14;1704:4;1694:14;;;1723:18;;;1730:10;1723:18;;;;;;;;;;;;;1635:113::o;1457:30:2:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1457:30:2;;;-1:-1:-1;1457:30:2;;;;;;-1:-1:-1;;;1457:30:2;;;;;;;;:::o;814:77:13:-;852:7;878:6;-1:-1:-1;;;;;878:6:13;814:77;:::o;1165:90::-;1205:4;1242:6;-1:-1:-1;;;;;1242:6:13;1228:10;:20;;1165:90::o;9715:103:2:-;9796:8;:15;9715:103;:::o;9948:146::-;10054:33;;;;:24;:33;;;;;;;;;10047:40;;;;;;;;;;;;;;;;;10022:13;;10047:40;;;10054:33;10047:40;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9948:146;;;:::o;7289:1284::-;1307:7:14;;;;1306:8;1298:37;;;;;-1:-1:-1;;;;;1298:37:14;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;1298:37:14;;;;;;;;;;;;;;;3430:16:2;;-1:-1:-1;;;;;3430:16:2;3416:10;:30;3407:83;;;;;-1:-1:-1;;;;;3407:83:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3096:10;;:49;;;;;-1:-1:-1;;;;;3096:10:2;;;;:19;;:10;;:49;;;:10;:49;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3096:49:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;3096:49:2;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;3096:49:2;;:73;;;3150:10;;;;;;;;;-1:-1:-1;;;;;3150:10:2;-1:-1:-1;;;;;3150:17:2;;:19;;;;;-1:-1:-1;;;3150:19:2;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3150:19:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;3150:19:2;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;3150:19:2;3149:20;3096:73;3088:109;;;;;;;-1:-1:-1;;;;;3088:109:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;7465:8;:15;7483:1;-1:-1:-1;7457:76:2;;;;;-1:-1:-1;;;;;7457:76:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7543:34;;:::i;:::-;7580:70;;;;;;;;;7594:1;7580:70;;;;7604:3;7580:70;;;;;;7610:15;-1:-1:-1;;;;;7580:70:2;;;;;7627:22;7580:70;;;;;;;;;;7660:14;27:10:-1;;39:1;23:18;;;45:23;;;-1:-1;7660:34:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;7660:34:2;;;;;;;;-1:-1:-1;;7660:34:2;;;;;;;;;;;;;;;;;;;;;;7543:107;;-1:-1:-1;23:18;;7543:107:2;;7660:34;;-1:-1:-1;;;;;;7660:34:2;;;;-1:-1:-1;;;7660:34:2;;;;;;;;;;;;;;-1:-1:-1;;7891:14:2;:21;-1:-1:-1;;7891:23:2;7704:28;7866:49;;;:24;:49;;;;;7704:28;;-1:-1:-1;7866:49:2;-1:-1:-1;7704:28:2;7925:524;7944:28;;;;-1:-1:-1;7925:524:2;;;7993:14;8010:17;;:20;;;;;;;;;;;;;;;;7993:37;;8044:33;8080:8;8089:9;8080:19;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;8144:23:2;8121:19;;-1:-1:-1;;;8121:19:2;;;;:46;;;;;;;;;8113:88;;;;;-1:-1:-1;;;;;8113:88:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;8216:44;;-1:-1:-1;;;;;;8216:44:2;;;;;27:10:-1;;-1:-1;23:18;;45:23;;-1:-1;8274:34:2;;;;;;;;;;8322:25;8274:34;8322:14;:25::i;:::-;8415:22;;;;8387:51;;:23;;:51;:27;:51;:::i;:::-;8361:77;-1:-1:-1;;;7974:3:2;;7925:524;;;;8476:10;-1:-1:-1;;;;;8463:44:2;;8488:18;8463:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8517:49;;-1:-1:-1;;;;;8517:24:2;;;:49;;;;;8542:23;;8517:49;;;;8542:23;8517:24;:49;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;8517:49:2;3207:1;;;7289:1284;;;:::o;3732:240::-;1018:9:13;:7;:9::i;:::-;1010:54;;;;;;;-1:-1:-1;;;;;1010:54:13;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;1010:54:13;;;;;;;;;;;;;;;3830:10:2;:36;;-1:-1:-1;;3830:36:2;-1:-1:-1;;;;;3830:36:2;;;;;3873:30;3830:36;3873:17;:30::i;:::-;3910:26;3920:15;3910:9;:26::i;:::-;3943:22;3953:11;3943:9;:22::i;:::-;3732:240;;:::o;1330:37::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1330:37:2;;;;;;;-1:-1:-1;;;;;1330:37:2;;-1:-1:-1;;;1330:37:2;;;;;:::o;1885:107:13:-;1018:9;:7;:9::i;:::-;1010:54;;;;;;;-1:-1:-1;;;;;1010:54:13;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;1010:54:13;;;;;;;;;;;;;;;1957:28;1976:8;1957:18;:28::i;1903:31:2:-;;;-1:-1:-1;;;;;1903:31:2;;:::o;6294:860::-;6353:33;6389:8;6398:5;6389:15;;;;;;;;;;;;;;;;;;6439:22;6389:15;;;;;6439:22;;;;6549:17;;6389:15;;-1:-1:-1;6439:22:2;-1:-1:-1;;;;;6549:17:2;6570:10;6549:31;;6548:69;;-1:-1:-1;6600:16:2;;-1:-1:-1;;;;;6600:16:2;6586:10;:30;6548:69;6540:115;;;;;;;-1:-1:-1;;;;;6540:115:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6696:22;6673:19;;-1:-1:-1;;;6673:19:2;;;;:45;;;;;;;;;6665:111;;;;;-1:-1:-1;;;;;6665:111:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6796:4;6788:21;:39;-1:-1:-1;6788:39:2;6780:102;;;;;-1:-1:-1;;;;;6780:102:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6941:44;;-1:-1:-1;;;;;;6941:44:2;;;;;7048:35;;:10;;:35;;;;;;;-1:-1:-1;7048:35:2;-1:-1:-1;7048:35:2;;:10;:35;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;7099:48:2;;;;;;;;7120:10;;7099:48;;;;;;;;;;6294:860;;;:::o;779:200:16:-;851:4;-1:-1:-1;;;;;875:21:16;;;;867:68;;;;;-1:-1:-1;;;;;867:68:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;952:20:16;:11;:20;;;;;;;;;;;;;;;779:200::o;834:176:18:-;892:7;923:5;;;946:6;;;;938:46;;;;;-1:-1:-1;;;;;938:46:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;1002:1;834:176;-1:-1:-1;;;834:176:18:o;1274:179::-;1332:7;1359:6;;;;1351:49;;;;;-1:-1:-1;;;;;1351:49:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1422:5:18;;;1274:179::o;861:127:15:-;920:24;:8;936:7;920:24;:15;:24;:::i;:::-;959:22;;-1:-1:-1;;;;;959:22:15;;;;;;;;861:127;:::o;736:119::-;792:21;:8;805:7;792:21;:12;:21;:::i;:::-;828:20;;-1:-1:-1;;;;;828:20:15;;;;;;;;736:119;:::o;8625:420:2:-;8679:33;8715:8;8724:10;8715:20;;;;;;;;;;;;;;;;;;;;;;;8803:17;;-1:-1:-1;;;;;8803:17:2;8783:38;;;;;;;;;;8715:20;;-1:-1:-1;8783:45:2;;8826:1;8783:45;:42;:45;:::i;:::-;8762:17;;-1:-1:-1;;;;;8762:17:2;;;8742:38;;;;:19;:38;;;;;;:86;;;;8835:10;;8866:17;;8762;8885:22;;;8835:85;;;;;8866:17;;;8835:85;;;;;;;;;;;;;;;;:10;;;:30;;:85;;;;;8742:38;8835:85;;;;;8742:38;8835:10;:85;;;5:2:-1;;;;30:1;27;20:12;5:2;8835:85:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;8927:51:2;;-1:-1:-1;;;;;;8927:51:2;;;;;-1:-1:-1;;9013:10:2;;:25;;;;;;;;-1:-1:-1;;;;;9013:10:2;;;;:23;;:25;;;;;;;;;;;;;;;:10;:25;;;5:2:-1;;;;30:1;27;20:12;5:2;9013:25:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;9013:25:2;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;9013:25:2;8985;;;;:53;-1:-1:-1;8625:420:2:o;2093:225:13:-;-1:-1:-1;;;;;2166:22:13;;;;2158:73;;;;;-1:-1:-1;;;;;2158:73:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2267:6;;;2246:38;;-1:-1:-1;;;;;2246:38:13;;;;2267:6;;;2246:38;;;2294:6;:17;;-1:-1:-1;;2294:17:13;-1:-1:-1;;;;;2294:17:13;;;;;;;;;;2093:225::o;510:180:16:-;589:18;593:4;599:7;589:3;:18::i;:::-;581:64;;;;;;;-1:-1:-1;;;;;581:64:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;655:20:16;678:5;655:20;;;;;;;;;;;:28;;-1:-1:-1;;655:28:16;;;510:180::o;260:175::-;337:18;341:4;347:7;337:3;:18::i;:::-;336:19;328:63;;;;;-1:-1:-1;;;;;328:63:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;401:20:16;:11;:20;;;;;;;;;;;:27;;-1:-1:-1;;401:27:16;424:4;401:27;;;260:175::o;402:9704:2:-;;;;;;;;;-1:-1:-1;402:9704:2;;;;;;;;;;;;;;;;;;;;;:::o

Swarm Source

bzzr://01e2c5fc2252eb52e1c397afe1936aece7ffc4b43d0acfa71b87ba959a0f23ab

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ 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.