ETH Price: $3,413.69 (-1.71%)
Gas: 6 Gwei

Contract

0xACEf7A6384e03544971F3a7df9CfD82e8bb80b1b
 

Overview

ETH Balance

0.02266231326842469 ETH

Eth Value

$77.36 (@ $3,413.69/ETH)

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Transfer Ownersh...194601832024-03-18 7:25:23123 days ago1710746723IN
0xACEf7A63...e8bb80b1b
0 ETH0.0006471219.83273838
Update Minimum B...194600762024-03-18 7:03:47123 days ago1710745427IN
0xACEf7A63...e8bb80b1b
0 ETH0.000675220.54807558
Update Maximum A...194600742024-03-18 7:03:23123 days ago1710745403IN
0xACEf7A63...e8bb80b1b
0 ETH0.000700121.38910742
0x60806040194600662024-03-18 7:01:47123 days ago1710745307IN
 Create: Distributor
0 ETH0.0605441321.25822809

Latest 11 internal transactions

Advanced mode:
Parent Transaction Hash Block From To
196637132024-04-15 21:53:3594 days ago1713218015
0xACEf7A63...e8bb80b1b
0.00090552 ETH
196193982024-04-09 16:53:23100 days ago1712681603
0xACEf7A63...e8bb80b1b
0.00136028 ETH
195993002024-04-06 21:16:23103 days ago1712438183
0xACEf7A63...e8bb80b1b
0.00115317 ETH
195968002024-04-06 12:51:11104 days ago1712407871
0xACEf7A63...e8bb80b1b
0.00120534 ETH
195913832024-04-05 18:41:11104 days ago1712342471
0xACEf7A63...e8bb80b1b
0.00252533 ETH
195777702024-04-03 20:56:23106 days ago1712177783
0xACEf7A63...e8bb80b1b
0.00034728 ETH
195764292024-04-03 16:26:59106 days ago1712161619
0xACEf7A63...e8bb80b1b
0.00248089 ETH
195760472024-04-03 15:10:11106 days ago1712157011
0xACEf7A63...e8bb80b1b
0.00060259 ETH
195759842024-04-03 14:57:35106 days ago1712156255
0xACEf7A63...e8bb80b1b
0.00157141 ETH
195759182024-04-03 14:44:11106 days ago1712155451
0xACEf7A63...e8bb80b1b
0.00638628 ETH
195759172024-04-03 14:43:59106 days ago1712155439
0xACEf7A63...e8bb80b1b
0.00412418 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Distributor

Compiler Version
v0.8.18+commit.87f61d96

Optimization Enabled:
Yes with 10 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2024-03-18
*/

/**
 * ██████  ███████ ██    ██  ██████  ██      ██    ██ ███████ ██  ██████  ███    ██
 * ██   ██ ██      ██    ██ ██    ██ ██      ██    ██     ██  ██ ██    ██ ████   ██
 * ██████  █████   ██    ██ ██    ██ ██      ██    ██   ██    ██ ██    ██ ██ ██  ██
 * ██   ██ ██       ██  ██  ██    ██ ██      ██    ██  ██     ██ ██    ██ ██  ██ ██
 * ██   ██ ███████   ████    ██████  ███████  ██████  ███████ ██  ██████  ██   ████
 * 
 * @title BRO Revenue Share
 * 
 * @notice This is a smart contract developed by Revoluzion for BRO Revenue Share.
 * 
 * @dev This smart contract was developed based on the general
 * OpenZeppelin Contracts guidelines where functions revert instead of
 * returning `false` on failure. 
 * 
 * @author Revoluzion Ecosystem
 * @custom:email [email protected]
 * @custom:telegram https://t.me/RevoluzionEcosystem
 * @custom:website https://revoluzion.io
 * @custom:dapp https://revoluzion.app
 */
 
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

/********************************************************************************************
  LIBRARY
********************************************************************************************/

/**
 * @title Address Library
 *
 * @notice Collection of functions providing utility for interacting with addresses.
 */
library Address {

    // ERROR

    /**
     * @notice Error indicating insufficient balance while performing an operation.
     *
     * @param account Address where the balance is insufficient.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @notice Error indicating an attempt to interact with a contract having empty code.
     *
     * @param target Address of the contract with empty code.
     */
    error AddressEmptyCode(address target);

    /**
     * @notice Error indicating a failed internal call.
     */
    error FailedInnerCall();

    // FUNCTION

    /**
     * @notice Calls a function on a specified address without transferring value.
     *
     * @param target Address on which the function will be called.
     * @param data Encoded data of the function call.
     *
     * @return returndata Result of the function call.
     *
     * @dev The `target` must be a contract address and this function must be calling
     * `target` with `data` not reverting.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @notice Calls a function on a specified address with a specified value.
     *
     * @param target Address on which the function will be called.
     * @param data Encoded data of the function call.
     * @param value Value to be sent in the call.
     *
     * @return returndata Result of the function call.
     *
     * @dev This function ensure that the calling contract actually have Ether balance
     * of at least `value` and that the called Solidity function is a `payable`. Should
     * throw if caller does have insufficient balance.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @notice Verifies the result of a function call and handles errors if any.
     *
     * @param target Address on which the function was called.
     * @param success Boolean indicating the success of the function call.
     * @param returndata Result data of the function call.
     *
     * @return Result of the function call or reverts with an appropriate error.
     *
     * @dev This help to verify that a low level call to smart-contract was successful
     * and will reverts if the target was not a contract. For unsuccessful call, this
     * will bubble up the revert reason (falling back to {FailedInnerCall}). Should
     * throw if both the returndata and target.code length are 0 when `success` is true.
     */
    function verifyCallResultFromTarget(address target, bool success, bytes memory returndata) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @notice Reverts with decoded revert data or FailedInnerCall if no revert
     * data is available.
     *
     * @param returndata Result data of a failed function call.
     *
     * @dev Should throw if returndata length is 0.
     */
    function _revert(bytes memory returndata) private pure {
        if (returndata.length > 0) {
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert FailedInnerCall();
        }
    }
}

/**
 * @title SafeERC20 Library
 *
 * @notice Collection of functions providing utility for safe operations with
 * ERC20 tokens.
 *
 * @dev This is mainly for the usage of token 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 where non-reverting calls are assumed
 * to be a successful transaction.
 */
library SafeERC20 {
    
    // LIBRARY

    using Address for address;

    // ERROR

    /**
     * @notice Error indicating a failed operation during an ERC-20 token transfer.
     *
     * @param token Address of the token contract.
     */
    error SafeERC20FailedOperation(address token);

    // FUNCTION

    /**
     * @notice Safely transfers tokens.
     *
     * @param token ERC20 token interface.
     * @param to Address to which the tokens will be transferred.
     * @param value Amount of tokens to be transferred.
     *
     * @dev Transfer `value` amount of `token` from the calling contract to `to` where
     * non-reverting calls are assumed to be successful if `token` returns no value.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @notice Calls a function on a token contract and reverts if the operation fails.
     *
     * @param token ERC20 token interface.
     * @param data Encoded data of the function call.
     *
     * @dev This imitates a Solidity high-level call such as a regular function call to
     * a contract while relaxing the requirement on the return value.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        bytes memory returndata = address(token).functionCall(data);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }
}

/********************************************************************************************
  INTERFACE
********************************************************************************************/

/**
 * @title ERC20 Token Standard Interface
 * 
 * @notice Interface of the ERC-20 standard token as defined in the ERC.
 * 
 * @dev See https://eips.ethereum.org/EIPS/eip-20
 */
interface IERC20 {
    
    // EVENT
    
    /**
     * @notice Emitted when `value` tokens are transferred from
     * one account (`from`) to another (`to`).
     * 
     * @param from The address tokens are transferred from.
     * @param to The address tokens are transferred to.
     * @param value The amount of tokens transferred.
     * 
     * @dev The `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @notice Emitted when the allowance of a `spender` for an `owner`
     * is set by a call to {approve}.
     * 
     * @param owner The address allowing `spender` to spend on their behalf.
     * @param spender The address allowed to spend tokens on behalf of `owner`.
     * @param value The allowance amount set for `spender`.
     * 
     * @dev The `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    // FUNCTION

    /**
     * @notice Returns the value of tokens in existence.
     * 
     * @return The value of the total supply of tokens.
     * 
     * @dev This should get the total token supply.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @notice Returns the value of tokens owned by `account`.
     * 
     * @param account The address to query the balance for.
     * 
     * @return The token balance of `account`.
     * 
     * @dev This should get the token balance of a specific account.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @notice Moves a `value` amount of tokens from the caller's account to `to`.
     * 
     * @param to The address to transfer tokens to.
     * @param value The amount of tokens to be transferred.
     * 
     * @return A boolean indicating whether the transfer was successful or not.
     * 
     * @dev This should transfer tokens to a specified address and emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @notice Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}.
     * 
     * @param owner The address allowing `spender` to spend on their behalf.
     * @param spender The address allowed to spend tokens on behalf of `owner`.
     * 
     * @return The allowance amount for `spender`.
     * 
     * @dev The return value should be zero by default and
     * changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @notice Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     * 
     * @param spender The address allowed to spend tokens on behalf of the sender.
     * @param value The allowance amount for `spender`.
     * 
     * @return A boolean indicating whether the approval was successful or not.
     * 
     * @dev This should approve `spender` to spend a specified amount of tokens
     * on behalf of the sender and emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @notice Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's allowance.
     * 
     * @param from The address to transfer tokens from.
     * @param to The address to transfer tokens to.
     * @param value The amount of tokens to be transferred.
     * 
     * @return A boolean indicating whether the transfer was successful or not.
     * 
     * @dev This should transfer tokens from one address to another after
     * spending caller's allowance and emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

/**
 * @title ERC20 Token Metadata Interface
 * 
 * @notice Interface for the optional metadata functions of the ERC-20 standard as defined in the ERC.
 * 
 * @dev It extends the IERC20 interface. See https://eips.ethereum.org/EIPS/eip-20
 */
interface IERC20Metadata is IERC20 {

    // FUNCTION
    
    /**
     * @notice Returns the name of the token.
     * 
     * @return The name of the token as a string.
     */
    function name() external view returns (string memory);

    /**
     * @notice Returns the symbol of the token.
     * 
     * @return The symbol of the token as a string.
     */
    function symbol() external view returns (string memory);

    /**
     * @notice Returns the number of decimals used to display the token.
     * 
     * @return The number of decimals as a uint8.
     */
    function decimals() external view returns (uint8);
}

/**
 * @title Common Error Interface
 * 
 * @notice Interface of the common errors not specific to ERC-20 functionalities.
 */
interface ICommonErrors {

    // ERROR

    /**
     * @notice Error indicating that cannot use all current addresses to initiate function.
     */
    error CannotUseAllCurrentAddress();

    /**
     * @notice Error indicating that cannot use all current states to initiate function.
     */
    error CannotUseAllCurrentState();

    /**
     * @notice Error indicating that cannot use all current values to initiate function.
     */
    error CannotUseAllCurrentValue();

    /**
     * @notice Error indicating that the `current` address cannot be used in this context.
     * 
     * @param current Address used in the context.
     */
    error CannotUseCurrentAddress(address current);

    /**
     * @notice Error indicating that the `current` state cannot be used in this context.
     * 
     * @param current Boolean state used in the context.
     */
    error CannotUseCurrentState(bool current);

    /**
     * @notice Error indicating that the `current` value cannot be used in this context.
     * 
     * @param current Value used in the context.
     */
    error CannotUseCurrentValue(uint256 current);

    /**
     * @notice Error indicating that the `invalid` address provided is not a valid address for this context.
     * 
     * @param invalid Address used in the context.
     */
    error InvalidAddress(address invalid);

    /**
     * @notice Error indicating that the `invalid` value provided is not a valid value for this context.
     * 
     * @param invalid Value used in the context.
     */
    error InvalidValue(uint256 invalid);
}

/**
 * @title Revenue Share Interface
 * 
 * @notice Interface of the revenue share contract utilised within the ecosystem.
 */
interface IRevenueShare {

    // FUNCTION

    /**
     * @notice Allow deposits to be made along with the creation of new reward pool.
     */
    function deposit() external payable;

    /**
     * @notice Add the share eligible for dividend after token buy transaction.
     * 
     * @param holder The address of the holder.
     * @param amount The amount being transacted.
     */
    function addShare(address holder, uint256 amount) external;

    /**
     * @notice Remove the share eligible for dividend after token transfer or sell transaction.
     * 
     * @param holder The address of the holder.
     * @param amount The amount being transacted.
     */
    function removeShare(address holder, uint256 amount) external;
}

/********************************************************************************************
  ACCESS
********************************************************************************************/

/**
 * @title Ownable Contract
 * 
 * @notice Abstract contract module implementing ownership functionality through
 * inheritance as a basic access control mechanism, where there is an owner account
 * that can be granted exclusive access to specific functions.
 * 
 * @dev The initial owner is set to the address provided by the deployer and can
 * later be changed with {transferOwnership}.
 */
abstract contract Ownable {

    // DATA

    address private _owner;

    // MODIFIER

    /**
     * @notice Modifier that allows access only to the contract owner.
     *
     * @dev Should throw if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    // ERROR

    /**
     * @notice Error indicating that the `account` is not authorized to perform an operation.
     * 
     * @param account Address used to perform the operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @notice Error indicating that the provided `owner` address is invalid.
     * 
     * @param owner Address used to perform the operation.
     * 
     * @dev Should throw if called by an invalid owner account such as address(0) as an example.
     */
    error OwnableInvalidOwner(address owner);

    // CONSTRUCTOR

    /**
     * @notice Initializes the contract setting the `initialOwner` address provided by
     * the deployer as the initial owner.
     * 
     * @param initialOwner The address to set as the initial owner.
     *
     * @dev Should throw an error if called with address(0) as the `initialOwner`.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }
    
    // EVENT
    
    /**
     * @notice Emitted when ownership of the contract is transferred.
     * 
     * @param previousOwner The address of the previous owner.
     * @param newOwner The address of the new owner.
     */
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    // FUNCTION

    /**
     * @notice Get the address of the smart contract owner.
     * 
     * @return The address of the current owner.
     *
     * @dev Should return the address of the current smart contract owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }
    
    /**
     * @notice Checks if the caller is the owner and reverts if not.
     * 
     * @dev Should throw if the sender is not the current owner of the smart contract.
     */
    function _checkOwner() internal view virtual {
        if (owner() != msg.sender) {
            revert OwnableUnauthorizedAccount(msg.sender);
        }
    }
    
    /**
     * @notice Allows the current owner to renounce ownership and make the
     * smart contract ownerless.
     * 
     * @dev This function can only be called by the current owner and will
     * render all `onlyOwner` functions inoperable.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }
    
    /**
     * @notice Allows the current owner to transfer ownership of the smart contract
     * to `newOwner` address.
     * 
     * @param newOwner The address to transfer ownership to.
     *
     * @dev This function can only be called by the current owner and will render
     * all `onlyOwner` functions inoperable to him/her. Should throw if called with
     * address(0) as the `newOwner`.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }
    
    /**
     * @notice Internal function to transfer ownership of the smart contract
     * to `newOwner` address.
     * 
     * @param newOwner The address to transfer ownership to.
     *
     * @dev This function replace current owner address stored as _owner with 
     * the address of the `newOwner`.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

/**
 * @title Auth Contract
 * 
 * @notice Abstract contract module for managing authorization.
 *
 * @dev This contract provides functionality for authorizing and unauthorizing accounts.
 */
abstract contract Auth is Ownable {
    
    // MAPPING

    mapping(address => bool) public authorization;

    // MODIFIER

    modifier authorized() {
        _checkAuthorized();
        _;
    }

    // ERROR

    /**
     * @notice Error indicating that the account is not authorized.
     * 
     * @dev Should throw if called when the account was not authorized.
     */
    error InvalidAuthorizedAccount(address account);

    /**
     * @notice Error indicating that current state is being used.
     * 
     * @dev Should throw if called when the current state is being used.
     */
    error CurrentAuthorizedState(address account, bool state);
    
    // CONSTRUCTOR

    constructor(
        address initialOwner
    ) Ownable(initialOwner) {
        authorize(initialOwner);
        if (initialOwner != msg.sender) {
            authorize(msg.sender);
        }
    }

    // EVENT
    
    /**
     * @notice Emitted when the account's authorization status was updated.
     * 
     * @param state The new state being used for the account.
     * @param authorizedAccount The address of the account being updated.
     * @param caller The address of the caller who update the account.
     * @param timestamp The timestamp when the account was updated.
     */
    event UpdateAuthorizedAccount(address authorizedAccount, address caller, bool state, uint256 timestamp);

    // FUNCTION

    /**
     * @notice Checks if the caller is authorized.
     * 
     * @dev This function checks whether the caller is authorized by verifying their
     * presence in the authorization mapping. If the caller is not authorized, the
     * function reverts with an appropriate error message.
     */
    function _checkAuthorized() internal view virtual {
        if (!authorization[msg.sender]) {
            revert OwnableUnauthorizedAccount(msg.sender);
        }
    }

    /**
     * @notice Authorizes an account.
     * 
     * @param account The address of the account to be authorized.
     * 
     * @dev This function authorizes the specified account by updating the authorization mapping.
     * It checks if the account address is valid and not equal to address(0) or address(0xdead).
     */
    function authorize(address account) public virtual onlyOwner {
        if (account == address(0) || account == address(0xdead)) {
            revert InvalidAuthorizedAccount(account);
        }
        _authorization(account, msg.sender, true);
    }

    /**
     * @notice Unauthorizes an account.
     * 
     * @param account The address of the account to be unauthorized.
     * 
     * @dev This function unauthorizes the specified account by updating the authorization mapping.
     * It checks if the account address is valid and not equal to address(0) or address(0xdead).
     */
    function unauthorize(address account) public virtual onlyOwner {
        if (account == address(0) || account == address(0xdead)) {
            revert InvalidAuthorizedAccount(account);
        }
        _authorization(account, msg.sender, false);
    }

    /**
     * @notice Internal function for managing authorization status.
     * 
     * @param account The address of the account to be authorized or unauthorized.
     * @param caller The address of the caller authorizing or unauthorizing the account.
     * @param state The desired authorization state (true for authorized, false for unauthorized).
     * 
     * @dev This function updates the authorization mapping for the specified account and emits an
     * `UpdateAuthorizedAccount` event. It checks if the current authorization state matches the
     * desired state before updating.
     */
    function _authorization(address account, address caller, bool state) internal virtual {
        if (authorization[account] == state) {
            revert CurrentAuthorizedState(account, state);
        }
        authorization[account] = state;
        emit UpdateAuthorizedAccount(account, caller, state, block.timestamp);
    }
}

/********************************************************************************************
  SECURITY
********************************************************************************************/

/**
 * @title Pausable Contract
 * 
 * @notice Abstract contract module implementing pause functionality through
 * inheritance as a basic security mechanism, where there certain functions
 * that can be paused and unpaused.
 */
abstract contract Pausable {

    // DATA

    bool private _paused;

    // ERROR

    /**
     * @notice Error thrown when an action is attempted in an enforced pause.
     */
    error EnforcedPause();

    /**
     * @notice Error thrown when an action is attempted without the expected pause.
     */
    error ExpectedPause();

    // MODIFIER

    /**
     * @notice Modifier ensure functions are called when the contract is
     * not paused.
     * 
     * @dev Should throw if called when the contract is paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @notice Modifier ensure functions are called when the contract is
     * paused.
     * 
     * @dev Should throw if called when the contract is not paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    // CONSTRUCTOR

    /**
     * @notice Initializes the contract setting the `_paused` state as false.
     */
    constructor() {
        _paused = false;
    }

    // EVENT
    
    /**
     * @notice Emitted when the contract is paused.
     * 
     * @param account The address that initiate the function.
     */
    event Paused(address account);

    /**
     * @notice Emitted when the contract is unpaused.
     * 
     * @param account The address that initiate the function.
     */
    event Unpaused(address account);

    // FUNCTION

    /**
     * @notice Returns the current paused state of the contract.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @notice Function to pause the contract.
     * 
     * @dev This function is accessible externally when not paused.
     */
    function pause() public virtual whenNotPaused {
        _pause();
    }

    /**
     * @notice Function to unpause the contract.
     * 
     * @dev This function is accessible externally when paused.
     */
    function unpause() public virtual whenPaused {
        _unpause();
    }

    /**
     * @notice Internal function to revert if the contract is not paused.
     * 
     * @dev Throws when smart contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        if (paused()) {
            revert EnforcedPause();
        }
    }

    /**
     * @notice Internal function to revert if the contract is paused.
     * 
     * @dev Throws when smart contract is not paused.
     */
    function _requirePaused() internal view virtual {
        if (!paused()) {
            revert ExpectedPause();
        }
    }

    /**
     * @notice Internal function to pause the contract.
     * 
     * @dev This function emits {Paused} event.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(msg.sender);
    }

    /**
     * @notice Internal function to unpause the contract.
     * 
     * @dev This function emits {Unpaused} event.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(msg.sender);
    }
}

/********************************************************************************************
  DISTRIBUTOR
********************************************************************************************/

/**
 * @title BRO Distributor Contract
 *
 * @notice BRO Distributor is the smart contract used for the revenue share system within
 * the BRO ecosystem.
 * 
 * @dev Implements RevenueShare and CommonError interfaces, and extends Auth contract while
 * at the same time implementing the Pausable logic.
 */
contract Distributor is Auth, Pausable, ICommonErrors, IRevenueShare {

    // LIBRARY

    using SafeERC20 for IERC20;
    using Address for address;

    // DATA

    struct PenaltyHistory {
        address holder;
        uint256 penaltyTime;
        uint256 totalReward;
        uint256 startIndex;
        uint256 lastIndex;
    }

    struct RewardHistory {
        address holder;
        uint256 distributedTime;
        uint256 totalReward;
        uint256 startIndex;
        uint256 lastIndex;
    }

    struct RewardInfo {
        uint256 createTime;
        uint256 amountAdded;
        uint256 shareEligible;
        uint256 rewardsPerShare;
        uint256 rewardsPerShareAccuracyFactor;
    }

    struct ShareInfo {
        uint256 lastTxn;
        uint256 cooldown;
        uint256 shares;
        uint256 startPoolIndex;
        uint256 eligibleTime;
    }

    address public projectOwner;
    address public tokenAddress;

    uint256 public lastTally = 0;
    uint256 public rewardHistoryIndex = 0;
    uint256 public penaltyHistoryIndex = 0;
    uint256 public totalHolders = 0;
    uint256 public totalShares = 0;
    uint256 public totalRewardPool = 0;
    uint256 public allocatedFund = 0;
    uint256 public distributedFund = 0;
    uint256 public accuracyFactor = 0;
    uint256 public lastRewardAddedTimestamp = 0;
    uint256 public maximumAmountPerEpoch = 18_000 ether;
    uint256 public minimumRewardRequired = 0.1 ether;
    uint256 public minimumForRewardPool = 10 ether;
    uint256 public minimumBalanceEligible = 3_000 ether;
    uint256 public cooldownTime = 7 hours;

    bool public justCreatePool = false;
    bool public useAddShareCooldown = false;
    bool public useRemoveShareCooldown = true;

    // MAPPING
    
    mapping(address account => ShareInfo) public userEligibility;
    mapping(address account => uint256) public remainingTransactable;
    mapping(address account => uint256) public holderIndex;
    mapping(uint256 holderId => address) public holderAtIndex;
    mapping(uint256 poolId => RewardInfo) public rewardPool;
    mapping(uint256 historyId => RewardHistory) public rewardHistory;
    mapping(address account => uint256) public userRewardHistoryIndex;
    mapping(address account => mapping(uint256 index => uint256)) public userRewardHistory;
    mapping(uint256 penaltyId => PenaltyHistory) public penaltyHistory;
    mapping(address account => uint256) public userPenaltyHistoryIndex;
    mapping(address account => mapping(uint256 index => uint256)) public userPenaltyHistory;

    // ERROR

    /**
     * @notice Error indicating that the native cannot be withdrawn from the smart contract.
     */
    error CannotWithdrawNative();

    /**
     * @notice Error indicating that the native fund in the smart contract is insufficient.
     */
    error InsufficientFund();

    /**
     * @notice Error indicating that the receiver cannot initiate transfer of Ether.
     * 
     * @dev Should throw if called by the receiver address.
     */
    error ReceiverCannotInitiateTransferEther();

    /**
     * @notice Error indicating cooldown has not end.
     */
    error WaitForCooldown(uint256 currentTime, uint256 endTime, uint256 timeLeft);

    /**
     * @notice Error indicating that the function not initiated by token contract.
     * 
     * @dev Should throw if called by address other than token.
     */
    error NotInitiatedByToken(address caller);

    /**
     * @notice Error indicating that the `sender` has insufficient `balance` for the operation.
     * 
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     *
     * @dev The `needed` value is required to inform user on the needed amount.
     */
    error InsufficientBalance(address sender, uint256 balance, uint256 needed);

    // MODIFIER
    
    /**
     * @notice Modifier to only allow token to initiate the function.
     */
    modifier onlyToken() {
        if (tokenAddress != msg.sender) {
            revert NotInitiatedByToken(msg.sender);
        }
        _;
    }

    // CONSTRUCTOR

    /**
     * @notice Constructs the distributor contract and initializes all important settings.
     */
    constructor(
        address initialOwner,
        address token
    ) Auth (
        msg.sender
    ) payable {
        if (initialOwner == address(0) || initialOwner == address(0xdead)) {
            revert InvalidAddress(initialOwner);
        }
        if (initialOwner != msg.sender) {
            authorize(initialOwner);
        }
        tokenAddress = token;
        projectOwner = initialOwner;
        accuracyFactor = (1 ether) * (1 ether);
    }

    // EVENT

    /**
     * @notice Emitted when the value of a feature is updated.
     * 
     * @param valueType The type of value being updated.
     * @param oldValue The previous status before the update.
     * @param newValue The new status after the update.
     * @param caller The address of the caller who updated the value.
     * @param timestamp The timestamp when the update occurred.
     */
    event UpdateValue(string valueType, uint256 oldValue, uint256 newValue, address caller, uint256 timestamp);

    /**
     * @notice Emitted when the state of a feature is updated.
     * 
     * @param stateType The type of state being updated.
     * @param oldState The previous status before the update.
     * @param newState The new status after the update.
     * @param caller The address of the caller who updated the state.
     * @param timestamp The timestamp when the update occurred.
     */
    event UpdateState(string stateType, bool oldState, bool newState, address caller, uint256 timestamp);

    /**
     * @notice Emitted when the claiming reward.
     * 
     * @param holder The address of the holder who claimed the reward.
     * @param rewardClaimed The total amount of reward claimed.
     * @param startIndex The reward pool index where claim start occuring.
     * @param lastIndex The reward pool index where claim stop occuring.
     * @param timestamp The timestamp when the claim occurred.
     */
    event RewardClaimed(address holder, uint256 rewardClaimed, uint256 startIndex, uint256 lastIndex, uint256 timestamp);

    /**
     * @notice Emitted when taking penalty.
     * 
     * @param holder The address of the holder who received the penalty.
     * @param penaltyTaken The total amount of penalty taken.
     * @param startIndex The reward pool index where penalty start occuring.
     * @param lastIndex The reward pool index where penalty stop occuring.
     * @param timestamp The timestamp when the penalty occurred.
     */
    event PenaltyTaken(address holder, uint256 penaltyTaken, uint256 startIndex, uint256 lastIndex, uint256 timestamp);

    /**
     * @notice Emitted when deposit for reward pool was created on the contract.
     * 
     * @param poolId The id of the reward pool created.
     * @param rewardAdded The amount of reward added for the pool.
     * @param caller The address that triggered the reward pool creation.
     * @param timestamp The timestamp when reward pool was created.
     */
    event RewardDeposited(uint256 poolId, uint256 rewardAdded, address caller, uint256 timestamp);

    /**
     * @notice Emitted when share was added after a user buy token.
     * 
     * @param holder The address of the user whose share is being updated.
     * @param amount The amount of share being added for the user.
     * @param caller The address that triggered the share update.
     * @param timestamp The timestamp when share was updated.
     */
    event AddShare(address holder, uint256 amount, address caller, uint256 timestamp);

    /**
     * @notice Emitted when share was removed after a user sell or transfer token.
     * 
     * @param holder The address of the user whose share is being updated.
     * @param amount The amount of share being removed for the user.
     * @param caller The address that triggered the share update.
     * @param timestamp The timestamp when share was updated.
     */
    event RemoveShare(address holder, uint256 amount, address caller, uint256 timestamp);

    /**
     * @notice Emitted when reward distribution was updated to balance out the difference.
     * 
     * @param desiredAmount The amount to be expected.
     * @param oldAmount The amount currently in use.
     * @param newAmount The amount after the update.
     * @param caller The address that triggered the update.
     * @param timestamp The timestamp for the update.
     */
    event TallyDistribution(uint256 desiredAmount, uint256 oldAmount, uint256 newAmount, address caller, uint256 timestamp);

    // FUNCTION

    /* General */
    
    /**
     * @notice Allows the contract to receive Ether.
     * 
     * @dev This is a required feature to have in order to allow the smart contract
     * to be able to receive ether from the swap.
     */
    receive() external payable {}

    /**
     * @notice Withdraws tokens or Ether from the contract to a specified address.
     * 
     * @param token The address of the token to withdraw.
     * @param amount The amount of tokens or Ether to withdraw.
     * 
     * @dev You need to use address(0) as `tokenAddress` to withdraw Ether and
     * use 0 as `amount` to withdraw the whole balance amount in the smart contract.
     * Anyone can trigger this function to send the fund to the `feeReceiver`.
     * Only `feeReceiver` address will not be able to trigger this function to
     * withdraw Ether from the smart contract by himself/herself. Should throw if try
     * to withdraw any amount of native token from the smart contract. Distribution
     * of native token can only be done through autoRedeem function.
     */
    function wTokens(address token, uint256 amount) external {
        uint256 locked = allocatedFund > distributedFund ? allocatedFund - distributedFund : 0;
        uint256 toTransfer = amount;
        address receiver = projectOwner;
        
        if (token == address(0)) {
            if (locked >= address(this).balance) {
                revert CannotWithdrawNative();
            }
            if (amount > address(this).balance - locked) {
                revert InsufficientFund();
            }
            if (msg.sender == receiver) {
                revert ReceiverCannotInitiateTransferEther();
            }
            if (amount == 0) {
                toTransfer = address(this).balance - locked;
            }
            payable(receiver).transfer(toTransfer);
        } else {
            if (amount == 0) {
                toTransfer = IERC20(token).balanceOf(address(this));
            }
            IERC20(token).safeTransfer(receiver, toTransfer);
        }
    }

    /**
     * @notice A function to adjust and tally the difference between amount of reward
     * distributed to amount of reward allocated as the result from the nature of how
     * calculation was carried out in Solidity.
     * 
     * @dev Should throw if using an invalid value.
     */
    function tallyDistribution(uint256 amount) external onlyOwner {
        if (amount < 1 && amount > 5) {
            revert InvalidValue(amount);
        }
        if (lastTally + 1 hours > block.timestamp) {
            revert WaitForCooldown(block.timestamp, lastTally + 1 hours, (lastTally + 1 hours) - block.timestamp);
        }
        uint256 oldAmount = distributedFund;
        distributedFund += amount;
        lastTally = block.timestamp;
        emit TallyDistribution(allocatedFund, oldAmount, distributedFund + amount, msg.sender, block.timestamp);
    }

    /* Check */

    /**
     * @notice Checks if using current state.
     * 
     * @dev Should throw if using current state.
     */
    function checkCurrentState(bool newState, bool current) internal pure {
        if (newState == current) {
            revert CannotUseCurrentState(newState);
        }
    }

    /**
     * @notice Checks if using current value.
     * 
     * @dev Should throw if using current value.
     */
    function checkCurrentValue(uint256 newValue, uint256 current) internal pure {
        if (newValue == current) {
            revert CannotUseCurrentValue(newValue);
        }
    }
    
    /**
     * @notice Checks if using invalid value.
     * 
     * @dev Should throw if using invalid value.
     */
    function checkInvalidValue(uint256 newValue, uint256 invalid) internal pure {
        if (newValue == invalid) {
            revert InvalidValue(newValue);
        }
    }

    /**
     * @notice Checks if using current address.
     * 
     * @dev Should throw if using current address.
     */
    function checkCurrentAddress(address newAddress, address current) internal pure {
        if (newAddress == current) {
            revert CannotUseCurrentAddress(newAddress);
        }
    }
    
    /**
     * @notice Checks if using invalid address.
     * 
     * @dev Should throw if using invalid address.
     */
    function checkInvalidAddress(address newAddress, address invalid) internal pure {
        if (newAddress == invalid) {
            revert InvalidAddress(newAddress);
        }
    }

    /**
     * @notice Checks the transaction involve cooldown and penalty.
     * 
     * @param holder The address that will be doing the transaction.
     * @param amount The amount that will be used for the transaction.
     * 
     * @return The state to show if the transaction will exceed amount allowed per reward epoch.
     * @return The duration left for cooldown.
     * @return The amount left that was allowed to be transacted per reward epoch.
     */
    function checkCooldownPenalty(address holder, uint256 amount) public view returns (bool, uint256, uint256) {
        uint256 lastTxn = userEligibility[holder].lastTxn;
        uint256 cooldown = userEligibility[holder].cooldown;
        bool exceed = false;

        if (
            (
                cooldown < 1 ||
                block.timestamp - lastTxn > cooldownTime ||
                block.timestamp - lastTxn >= cooldown
            ) && (
                amount <= maximumAmountPerEpoch &&
                amount <= remainingTransactable[holder]
            )
        ) {
            return (
                exceed, 
                block.timestamp - lastTxn > cooldownTime ||
                block.timestamp - lastTxn >= cooldown ? 
                    cooldownTime
                :
                    cooldown - (block.timestamp - lastTxn), 
                remainingTransactable[holder] > amount ? 
                    remainingTransactable[holder] - amount 
                :
                    0
            );
        } else {
            exceed = remainingTransactable[holder] < amount;
            return (
                exceed, 
                cooldown - (block.timestamp - lastTxn), 
            remainingTransactable[holder] > amount ? 
                remainingTransactable[holder] - amount 
            :
                0
            );
        }
    }

    /* Update */

    /**
     * @notice Updates the value of maximumAmountPerEpoch.
     * 
     * @param newValue The new value of maximumAmountPerEpoch to be set.
     * 
     * @dev This function will emits the UpdateValue event.
     */
    function updateMaximumAmountPerEpoch(uint256 newValue) external authorized {
        if (newValue < 50 ether) {
            revert InvalidValue(newValue);
        }
        checkCurrentValue(newValue, maximumAmountPerEpoch);
        uint256 oldValue = maximumAmountPerEpoch;
        maximumAmountPerEpoch = newValue;
        emit UpdateValue("maximumAmountPerEpoch", oldValue, newValue, msg.sender, block.timestamp);
    }

    /**
     * @notice Updates the value of minimumRewardRequired.
     * 
     * @param newValue The new value of minimumRewardRequired to be set.
     * 
     * @dev This function will emits the UpdateValue event.
     */
    function updateMinimumRewardRequired(uint256 newValue) external authorized {
        if (newValue > 1 ether) {
            revert InvalidValue(newValue);
        }
        checkCurrentValue(newValue, minimumRewardRequired);
        uint256 oldValue = minimumRewardRequired;
        minimumRewardRequired = newValue;
        emit UpdateValue("minimumRewardRequired", oldValue, newValue, msg.sender, block.timestamp);
    }

    /**
     * @notice Updates the value of minimumForRewardPool.
     * 
     * @param newValue The new value of minimumForRewardPool to be set.
     * 
     * @dev This function will emits the UpdateValue event.
     */
    function updateMinimumForRewardPool(uint256 newValue) external authorized {
        if (newValue < 1 ether) {
            revert InvalidValue(newValue);
        }
        checkCurrentValue(newValue, minimumForRewardPool);
        uint256 oldValue = minimumForRewardPool;
        minimumForRewardPool = newValue;
        emit UpdateValue("minimumForRewardPool", oldValue, newValue, msg.sender, block.timestamp);
    }

    /**
     * @notice Updates the value of minimumBalanceEligible.
     * 
     * @param newValue The new value of minimumBalanceEligible to be set.
     * 
     * @dev This function will emits the UpdateValue event.
     */
    function updateMinimumBalanceEligible(uint256 newValue) external authorized {
        if (newValue < 0) {
            revert InvalidValue(newValue);
        }
        checkCurrentValue(newValue, minimumBalanceEligible);
        uint256 oldValue = minimumBalanceEligible;
        minimumBalanceEligible = newValue;
        emit UpdateValue("minimumBalanceEligible", oldValue, newValue, msg.sender, block.timestamp);
    }

    /**
     * @notice Updates the value of cooldownTime.
     * 
     * @param newValue The new value of cooldownTime to be set.
     * 
     * @dev This function will emits the UpdateValue event.
     */
    function updateCooldownTime(uint256 newValue) external authorized {
        if (newValue < 30 minutes || newValue > 7 days) {
            revert InvalidValue(newValue);
        }
        checkCurrentValue(newValue, cooldownTime);
        uint256 oldValue = cooldownTime;
        cooldownTime = newValue;
        emit UpdateValue("cooldownTime", oldValue, newValue, msg.sender, block.timestamp);
    }

    /**
     * @notice Updates the state of useAddShareCooldown.
     * 
     * @param newState The new state of useAddShareCooldown to be set.
     * 
     * @dev This function will emits the UpdateState event.
     */
    function updateUseAddShareCooldown(bool newState) external authorized {
        checkCurrentState(newState, useAddShareCooldown);
        bool oldState = useAddShareCooldown;
        useAddShareCooldown = newState;
        emit UpdateState("useAddShareCooldown", oldState, newState, msg.sender, block.timestamp);
    }

    /**
     * @notice Updates the state of useRemoveShareCooldown.
     * 
     * @param newState The new state of useRemoveShareCooldown to be set.
     * 
     * @dev This function will emits the UpdateState event.
     */
    function updateUseRemoveShareCooldown(bool newState) external authorized {
        checkCurrentState(newState, useRemoveShareCooldown);
        bool oldState = useRemoveShareCooldown;
        useRemoveShareCooldown = newState;
        emit UpdateState("useRemoveShareCooldown", oldState, newState, msg.sender, block.timestamp);
    }

    /* Reward */

    /**
     * @notice Allow deposits to be made along with the creation of new reward pool.
     * 
     * @dev This function will allow new reward pool to be created if the conditions were met.
     */
    function deposit() external payable override whenNotPaused {
        if (allocatedFund < distributedFund) {
            uint256 diff = distributedFund - allocatedFund;
            distributedFund -= diff;
        }

        uint256 rewardBalance = allocatedFund > distributedFund ? allocatedFund - distributedFund : 0;
        uint256 current = address(this).balance - rewardBalance;

        if (
            totalHolders > 0 &&
            totalShares > 0 &&
            current >= minimumForRewardPool &&
            lastRewardAddedTimestamp + cooldownTime <= block.timestamp
        ) {
            justCreatePool = true;
            totalRewardPool = totalRewardPool + 1;
            allocatedFund = allocatedFund + current;
            lastRewardAddedTimestamp = block.timestamp;
            rewardPool[totalRewardPool].createTime = block.timestamp;
            rewardPool[totalRewardPool].amountAdded = current;
            rewardPool[totalRewardPool].shareEligible = totalShares;
            rewardPool[totalRewardPool].rewardsPerShare = current * accuracyFactor / totalShares;
            rewardPool[totalRewardPool].rewardsPerShareAccuracyFactor = accuracyFactor;
            emit RewardDeposited(totalRewardPool, current, msg.sender, block.timestamp);
        }
    }

    /**
     * @notice Checks all pending rewards for a specific users.
     * 
     * @param holder The address of the user being check.
     * 
     * @dev This function will loop the check from the user's current start pool index.
     */
    function checkAllPendingRewards(address holder) public view returns (uint256) {
        if (holderIndex[holder] < 1 || userEligibility[holder].startPoolIndex > totalRewardPool) {
            return 0;
        }
        return checkPendingRewards(holder, totalRewardPool);
    }

    /**
     * @notice Checks all pending rewards for a specific users from account start index to specific end index.
     * 
     * @param holder The address of the user being check.
     * @param endIndex The last index to check.
     * 
     * @dev This function will loop the check from the given reward pool index range.
     */
    function checkPendingRewards(address holder, uint256 endIndex) public view returns (uint256) {
        uint256 pending = 0;
        uint256 startIndex = userEligibility[holder].startPoolIndex;
        if (endIndex > totalRewardPool) {
            endIndex = totalRewardPool;
        }
        for (uint256 i = startIndex; i < endIndex + 1; i++) {
            uint256 reward = (userEligibility[holder].shares * rewardPool[i].rewardsPerShare) / rewardPool[i].rewardsPerShareAccuracyFactor;
            pending += reward;
        }
        return pending;
    }

    /**
     * @notice Allow users to manually initiate the reward claim functionality.
     * 
     * @dev This function will check the pending rewards from eligible pool and distribute the amount.
     */
    function manualClaimRewards() external {
        claimRewards(msg.sender);
    }

    /**
     * @notice Initiate the reward claim functionality internally.
     * 
     * @dev This function will check the pending rewards from eligible pool and distribute the amount.
     */
    function claimRewards(address holder) public {
        uint256 startIndex = userEligibility[holder].startPoolIndex;
        uint256 lastIndex = startIndex;
        if (lastIndex > totalRewardPool) {
            return;
        }
        if (startIndex < 1) {
            return;
        }
        while (
            rewardPool[lastIndex].createTime + cooldownTime < block.timestamp &&
            lastIndex < totalRewardPool + 1
        ) {
            lastIndex++;
        }

        uint256 pending = checkPendingRewards(holder, lastIndex - 1);
        if (minimumRewardRequired <= pending) {
            userEligibility[holder].startPoolIndex = lastIndex;
            distributedFund += pending;
            rewardHistoryIndex++;
            rewardHistory[rewardHistoryIndex].holder = holder;
            rewardHistory[rewardHistoryIndex].distributedTime = block.timestamp;
            rewardHistory[rewardHistoryIndex].totalReward = pending;
            rewardHistory[rewardHistoryIndex].startIndex = startIndex;
            rewardHistory[rewardHistoryIndex].lastIndex = lastIndex - 1;
            userRewardHistoryIndex[holder] += 1;
            userRewardHistory[holder][userRewardHistoryIndex[holder]] = rewardHistoryIndex;
            payable(holder).transfer(pending);
            emit RewardClaimed(holder, pending, startIndex, lastIndex, block.timestamp);
        }
    }
    
    /* Distributor */

    /**
     * @notice Add the share eligible for dividend after token buy transaction.
     * 
     * @param holder The address of the holder.
     * @param amount The amount being transacted.
     */
    function addShare(address holder, uint256 amount) external override onlyToken whenNotPaused {
        uint256 oldShare = userEligibility[holder].shares;
        uint256 newShare = IERC20(tokenAddress).balanceOf(holder) + amount;
        bool alreadyEligible = oldShare >= minimumBalanceEligible;
        bool isEligible = IERC20(tokenAddress).balanceOf(holder) + amount >= minimumBalanceEligible;
        if (isEligible) {
            if (oldShare < 1) {
                addHolder(holder);
            }
            if (oldShare > 0) {
                if (totalRewardPool > 0 && userEligibility[holder].startPoolIndex > 0 && userEligibility[holder].startPoolIndex < totalRewardPool + 1) {
                    claimRewards(holder);
                }
            }
            userEligibility[holder].shares = newShare;
            totalShares = totalShares - oldShare + newShare;
            emit AddShare(holder, amount, msg.sender, block.timestamp);
        }
        if (alreadyEligible && useAddShareCooldown) {
            checkPenalty(holder, amount, false, false);
        }
    }

    /**
     * @notice Remove the share eligible for dividend after token transfer or sell transaction.
     * 
     * @param holder The address of the holder.
     * @param amount The amount being transacted.
     */
    function removeShare(address holder, uint256 amount) external override onlyToken whenNotPaused {
        uint256 oldShare = userEligibility[holder].shares;
        uint256 newShare = IERC20(tokenAddress).balanceOf(holder) - amount;
        bool alreadyEligible = oldShare >= minimumBalanceEligible;
        bool isEligible = IERC20(tokenAddress).balanceOf(holder) - amount >= minimumBalanceEligible;
        bool poolUpdated = false;
        if (justCreatePool) {
            if (rewardPool[totalRewardPool].createTime + cooldownTime >= block.timestamp) {
                uint256 newTotalShare = rewardPool[totalRewardPool].shareEligible - amount;
                rewardPool[totalRewardPool].shareEligible = newTotalShare;
                rewardPool[totalRewardPool].rewardsPerShare = rewardPool[totalRewardPool].amountAdded * accuracyFactor / newTotalShare;
                poolUpdated = true;
            }
            justCreatePool = false;
        }
        if (alreadyEligible && totalRewardPool > 0 && userEligibility[holder].startPoolIndex > 0 && userEligibility[holder].startPoolIndex < totalRewardPool + 1) {
            claimRewards(holder);
        }
        if (isEligible) {
            userEligibility[holder].shares = newShare;
            totalShares = totalShares - oldShare + newShare;
            emit RemoveShare(holder, amount, msg.sender, block.timestamp);
        }
        if (!isEligible) {
            totalShares = totalShares - oldShare;
            userEligibility[holder].shares = 0;
            removeHolder(holder);
            emit RemoveShare(holder, oldShare, msg.sender, block.timestamp);
        }
        if (alreadyEligible && useRemoveShareCooldown) {
            checkPenalty(holder, amount, true, poolUpdated);
        }
    }

    /**
     * @notice Check and take action if penalty incurred on the transaction.
     * 
     * @param holder The address of the holder.
     * @param amount The amount being transacted.
     * @param removal The status of amount transacted whether it is removed or added.
     * @param poolUpdated The status on whether latest reward pool has been updated.
     */
    function checkPenalty(address holder, uint256 amount, bool removal, bool poolUpdated) internal {
        uint256 lastTxn = userEligibility[holder].lastTxn;
        uint256 cooldown = userEligibility[holder].cooldown;
        bool exceed = false;
        
        if (
            cooldown < 1 ||
            block.timestamp - lastTxn > cooldownTime ||
            block.timestamp - lastTxn >= userEligibility[holder].cooldown
        ) {
            userEligibility[holder].cooldown = cooldownTime;
            remainingTransactable[holder] = maximumAmountPerEpoch;
        } else {
            exceed = remainingTransactable[holder] < amount;
            userEligibility[holder].cooldown -= (block.timestamp - lastTxn);
            remainingTransactable[holder] = remainingTransactable[holder] > amount ? remainingTransactable[holder] - amount : 0;
        }

        userEligibility[holder].lastTxn = block.timestamp;

        uint256 startIndex = userEligibility[holder].startPoolIndex;
        uint256 lastIndex = startIndex;

        while (
            rewardPool[lastIndex].createTime + cooldownTime > block.timestamp &&
            lastIndex < totalRewardPool + 1
        ) {
            lastIndex++;
        }

        if (removal && startIndex < lastIndex) {
            uint256 count = startIndex;
            while (count < lastIndex) {
                if (!poolUpdated) {
                    uint256 newTotalShare = rewardPool[count].shareEligible - amount;
                    rewardPool[count].shareEligible = newTotalShare;
                    rewardPool[count].rewardsPerShare = rewardPool[count].amountAdded * accuracyFactor / newTotalShare;
                } else {
                    if (count < lastIndex - 1) {
                        uint256 newTotalShare = rewardPool[count].shareEligible - amount;
                        rewardPool[count].shareEligible = newTotalShare;
                        rewardPool[count].rewardsPerShare = rewardPool[count].amountAdded * accuracyFactor / newTotalShare;
                    }
                }
                count++;
            }
        }

        if (exceed) {
            uint256 pending = checkPendingRewards(holder, lastIndex - 1);
            userEligibility[holder].startPoolIndex = lastIndex;
            distributedFund += pending;

            penaltyHistoryIndex++;
            penaltyHistory[penaltyHistoryIndex].holder = holder;
            penaltyHistory[penaltyHistoryIndex].penaltyTime = block.timestamp;
            penaltyHistory[penaltyHistoryIndex].totalReward = pending;
            penaltyHistory[penaltyHistoryIndex].startIndex = startIndex;
            penaltyHistory[penaltyHistoryIndex].lastIndex = lastIndex - 1;
            userPenaltyHistoryIndex[holder] += 1;
            userPenaltyHistory[holder][userPenaltyHistoryIndex[holder]] = penaltyHistoryIndex;
            emit PenaltyTaken(holder, pending, startIndex, lastIndex, block.timestamp);
        }
    }

    /* Holders */

    /*
     * @notice Adds a holder to the list of eligible holder.
     * 
     * @param holder The address of the holder being added.
     * 
     * @dev This function is internal and should only be called within the contract.
     */
    function addHolder(address holder) internal {
        totalHolders++;
        holderAtIndex[totalHolders] = holder;
        holderIndex[holder] = totalHolders;
        userEligibility[holder].eligibleTime = block.timestamp;
        userEligibility[holder].startPoolIndex = totalRewardPool + 1;
    }

    /**
     * @notice Removes a holder from the list of eligible holder.
     * 
     * @param holder The address of the holder being removed.
     * 
     * @dev This function is internal and should only be called within the contract.
     */
    function removeHolder(address holder) internal {
        uint256 currentIndex = holderIndex[holder];
        address lastHolder = holderAtIndex[totalHolders];
        
        holderIndex[lastHolder] = currentIndex;
        holderAtIndex[currentIndex] = lastHolder;
        holderIndex[holder] = 0;
        holderAtIndex[totalHolders] = address(0);
        userEligibility[holder].eligibleTime = 0;
        userEligibility[holder].startPoolIndex = 0;

        totalHolders--;
    }
    
    /* Override */
    
    /**
     * @notice Overrides the {transferOwnership} function to update project owner.
     * 
     * @param newOwner The address of the new owner.
     * 
     * @dev Should throw if the `newOwner` is set to the current owner address or address(0xdead).
     * This overrides function is just an extended version of the original {transferOwnership}
     * function. See {Ownable-transferOwnership} for more information.
     */
    function transferOwnership(address newOwner) public override onlyOwner {
        checkCurrentAddress(newOwner, owner());
        checkInvalidAddress(newOwner, address(0xdead));
        projectOwner = newOwner;
        super.transferOwnership(newOwner);
    }
    
    /**
     * @notice Overrides the {pause} function to pause the contract.
     * 
     * @dev This function is accessible externally when not paused only by authorized account.
     */
    function pause() public override whenNotPaused authorized {
        super.pause();
    }

    /**
     * @notice Overrides the {unpause} function to pause the contract.
     * 
     * @dev This function is accessible externally when paused only by authorized account.
     */
    function unpause() public override whenPaused authorized {
        super.unpause();
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"initialOwner","type":"address"},{"internalType":"address","name":"token","type":"address"}],"stateMutability":"payable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"CannotUseAllCurrentAddress","type":"error"},{"inputs":[],"name":"CannotUseAllCurrentState","type":"error"},{"inputs":[],"name":"CannotUseAllCurrentValue","type":"error"},{"inputs":[{"internalType":"address","name":"current","type":"address"}],"name":"CannotUseCurrentAddress","type":"error"},{"inputs":[{"internalType":"bool","name":"current","type":"bool"}],"name":"CannotUseCurrentState","type":"error"},{"inputs":[{"internalType":"uint256","name":"current","type":"uint256"}],"name":"CannotUseCurrentValue","type":"error"},{"inputs":[],"name":"CannotWithdrawNative","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"CurrentAuthorizedState","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InsufficientFund","type":"error"},{"inputs":[{"internalType":"address","name":"invalid","type":"address"}],"name":"InvalidAddress","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"InvalidAuthorizedAccount","type":"error"},{"inputs":[{"internalType":"uint256","name":"invalid","type":"uint256"}],"name":"InvalidValue","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"NotInitiatedByToken","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReceiverCannotInitiateTransferEther","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"timeLeft","type":"uint256"}],"name":"WaitForCooldown","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"holder","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"AddShare","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"holder","type":"address"},{"indexed":false,"internalType":"uint256","name":"penaltyTaken","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lastIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"PenaltyTaken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"holder","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RemoveShare","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"holder","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewardClaimed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lastIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RewardClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"poolId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardAdded","type":"uint256"},{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RewardDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"desiredAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"TallyDistribution","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"authorizedAccount","type":"address"},{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"bool","name":"state","type":"bool"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"UpdateAuthorizedAccount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"stateType","type":"string"},{"indexed":false,"internalType":"bool","name":"oldState","type":"bool"},{"indexed":false,"internalType":"bool","name":"newState","type":"bool"},{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"UpdateState","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"valueType","type":"string"},{"indexed":false,"internalType":"uint256","name":"oldValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newValue","type":"uint256"},{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"UpdateValue","type":"event"},{"inputs":[],"name":"accuracyFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addShare","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"allocatedFund","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"authorization","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"authorize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"}],"name":"checkAllPendingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"checkCooldownPenalty","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"endIndex","type":"uint256"}],"name":"checkPendingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"}],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cooldownTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"distributedFund","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"holderId","type":"uint256"}],"name":"holderAtIndex","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"holderIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"justCreatePool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastRewardAddedTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastTally","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"manualClaimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maximumAmountPerEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumBalanceEligible","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumForRewardPool","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumRewardRequired","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"penaltyId","type":"uint256"}],"name":"penaltyHistory","outputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"penaltyTime","type":"uint256"},{"internalType":"uint256","name":"totalReward","type":"uint256"},{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"lastIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"penaltyHistoryIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"projectOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"remainingTransactable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"removeShare","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"historyId","type":"uint256"}],"name":"rewardHistory","outputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"distributedTime","type":"uint256"},{"internalType":"uint256","name":"totalReward","type":"uint256"},{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"lastIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardHistoryIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolId","type":"uint256"}],"name":"rewardPool","outputs":[{"internalType":"uint256","name":"createTime","type":"uint256"},{"internalType":"uint256","name":"amountAdded","type":"uint256"},{"internalType":"uint256","name":"shareEligible","type":"uint256"},{"internalType":"uint256","name":"rewardsPerShare","type":"uint256"},{"internalType":"uint256","name":"rewardsPerShareAccuracyFactor","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"tallyDistribution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalHolders","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRewardPool","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"unauthorize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"updateCooldownTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"updateMaximumAmountPerEpoch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"updateMinimumBalanceEligible","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"updateMinimumForRewardPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"updateMinimumRewardRequired","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"newState","type":"bool"}],"name":"updateUseAddShareCooldown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"newState","type":"bool"}],"name":"updateUseRemoveShareCooldown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"useAddShareCooldown","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"useRemoveShareCooldown","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"userEligibility","outputs":[{"internalType":"uint256","name":"lastTxn","type":"uint256"},{"internalType":"uint256","name":"cooldown","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"startPoolIndex","type":"uint256"},{"internalType":"uint256","name":"eligibleTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"userPenaltyHistory","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"userPenaltyHistoryIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"userRewardHistory","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"userRewardHistoryIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"wTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

608060408190526000600481905560058190556006819055600781905560088190556009819055600a819055600b819055600c819055600d556903cfc82e37e9a7400000600e5567016345785d8a0000600f55678ac7230489e8000060105568a2a15d09519be000006011556162706012556013805462ffffff191662010000179055620030e038819003908190833981016040819052620000a191620003a3565b338080620000ca57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b620000d581620001c2565b50620000e18162000212565b6001600160a01b0381163314620000fd57620000fd3362000212565b506002805460ff191690556001600160a01b03821615806200012957506001600160a01b03821661dead145b156200015457604051634726455360e11b81526001600160a01b0383166004820152602401620000c1565b6001600160a01b03821633146200017057620001708262000212565b600380546001600160a01b0319166001600160a01b0392831617905560028054610100600160a81b03191661010093909216929092021790556ec097ce7bc90715b34b9f1000000000600c55620003db565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6200021c62000279565b6001600160a01b03811615806200023d57506001600160a01b03811661dead145b156200026857604051635077b8ed60e11b81526001600160a01b0382166004820152602401620000c1565b6200027681336001620002ba565b50565b336200028d6000546001600160a01b031690565b6001600160a01b031614620002b85760405163118cdaa760e01b8152336004820152602401620000c1565b565b6001600160a01b03831660009081526001602052604090205481151560ff9091161515036200031057604051635ce75a3b60e01b81526001600160a01b03841660048201528115156024820152604401620000c1565b6001600160a01b03838116600081815260016020908152604091829020805460ff19168615159081179091558251938452938616908301528101919091524260608201527fff1d0a27274ca0cc8403b0e8f4a70b968164366f4856d18f7569eba542e9aae49060800160405180910390a1505050565b80516001600160a01b03811681146200039e57600080fd5b919050565b60008060408385031215620003b757600080fd5b620003c28362000386565b9150620003d26020840162000386565b90509250929050565b612cf580620003eb6000396000f3fe60806040526004361061028a5760003560e01c80630203649e1461029657806309c85e24146102bf5780630da817db146102d55780630fa16dce1461033a57806316b39b07146103ac5780631ef196ea146103ef5780631f685bac1461042757806327e633f9146104495780632a7e07f9146104695780632c91e2b314610489578063350ca4241461049f5780633631d26c146104b55780633a98ef39146104df5780633ce361d2146104f55780633f4ba83a1461050b57806345c08e6e1461052057806347f441ab146105405780634a90c2101461055657806350f4f9f81461057657806353d74fdf146105965780635c975abb146105ac5780636625618d146105c457806367314b37146105f15780636e0c05bb14610607578063715018a61461062757806376d566bd1461063c5780637706c4ba1461065c5780638450ce84146106a65780638456cb59146106c55780638c1708ab146106da5780638da5cb5b146106ef5780639761535d146107045780639d76ea581461071a5780639ed5519a1461073a578063a112ddc514610767578063a4475ce41461077d578063b2d1f2d8146107a2578063b319c6b7146107f6578063b5635f741461080c578063b6a5d7de14610822578063ba553dad14610842578063bd767e3d1461087a578063c06474e0146108a7578063c2fd076b146108c7578063cbe12969146108dd578063ce4f75281461090d578063d0e30db01461092d578063d4fc3b9814610935578063d93b609814610955578063e6688a8114610975578063e9bbb04014610995578063eb5ec54f146109c2578063ef5b478d146109ff578063ef5cfb8c14610a15578063f0b37c0414610a35578063f2fde38b14610a55578063f627b48a14610a7557600080fd5b3661029157005b600080fd5b3480156102a257600080fd5b506102ac600f5481565b6040519081526020015b60405180910390f35b3480156102cb57600080fd5b506102ac60095481565b3480156102e157600080fd5b506103296102f0366004612a44565b601960205260009081526040902080546001820154600283015460038401546004909401546001600160a01b0390931693919290919085565b6040516102b6959493929190612a5d565b34801561034657600080fd5b50610384610355366004612aa7565b601460205260009081526040902080546001820154600283015460038401546004909401549293919290919085565b604080519586526020860194909452928401919091526060830152608082015260a0016102b6565b3480156103b857600080fd5b506103e26103c7366004612a44565b6017602052600090815260409020546001600160a01b031681565b6040516102b69190612ac2565b3480156103fb57600080fd5b506102ac61040a366004612ad6565b601e60209081526000928352604080842090915290825290205481565b34801561043357600080fd5b50610447610442366004612ad6565b610a95565b005b34801561045557600080fd5b50610447610464366004612a44565b610c2f565b34801561047557600080fd5b50610447610484366004612b0e565b610ce1565b34801561049557600080fd5b506102ac600c5481565b3480156104ab57600080fd5b506102ac60045481565b3480156104c157600080fd5b506013546104cf9060ff1681565b60405190151581526020016102b6565b3480156104eb57600080fd5b506102ac60085481565b34801561050157600080fd5b506102ac600d5481565b34801561051757600080fd5b50610447610d81565b34801561052c57600080fd5b5061044761053b366004612a44565b610d9b565b34801561054c57600080fd5b506102ac600e5481565b34801561056257600080fd5b506102ac610571366004612ad6565b610e3f565b34801561058257600080fd5b50610447610591366004612ad6565b610ef9565b3480156105a257600080fd5b506102ac60075481565b3480156105b857600080fd5b5060025460ff166104cf565b3480156105d057600080fd5b506102ac6105df366004612aa7565b60156020526000908152604090205481565b3480156105fd57600080fd5b506102ac60115481565b34801561061357600080fd5b506102ac610622366004612aa7565b611182565b34801561063357600080fd5b506104476111de565b34801561064857600080fd5b50610447610657366004612a44565b6111f0565b34801561066857600080fd5b50610384610677366004612a44565b601860205260009081526040902080546001820154600283015460038401546004909401549293919290919085565b3480156106b257600080fd5b506013546104cf90610100900460ff1681565b3480156106d157600080fd5b5061044761130f565b3480156106e657600080fd5b50610447611327565b3480156106fb57600080fd5b506103e2611330565b34801561071057600080fd5b506102ac60065481565b34801561072657600080fd5b506003546103e2906001600160a01b031681565b34801561074657600080fd5b506102ac610755366004612aa7565b601d6020526000908152604090205481565b34801561077357600080fd5b506102ac60105481565b34801561078957600080fd5b506002546103e29061010090046001600160a01b031681565b3480156107ae57600080fd5b506103296107bd366004612a44565b601c60205260009081526040902080546001820154600283015460038401546004909401546001600160a01b0390931693919290919085565b34801561080257600080fd5b506102ac60125481565b34801561081857600080fd5b506102ac60055481565b34801561082e57600080fd5b5061044761083d366004612aa7565b61133f565b34801561084e57600080fd5b506102ac61085d366004612ad6565b601b60209081526000928352604080842090915290825290205481565b34801561088657600080fd5b506102ac610895366004612aa7565b601a6020526000908152604090205481565b3480156108b357600080fd5b506104476108c2366004612ad6565b611396565b3480156108d357600080fd5b506102ac600b5481565b3480156108e957600080fd5b506104cf6108f8366004612aa7565b60016020526000908152604090205460ff1681565b34801561091957600080fd5b50610447610928366004612b0e565b611721565b6104476117b8565b34801561094157600080fd5b506013546104cf9062010000900460ff1681565b34801561096157600080fd5b50610447610970366004612a44565b611971565b34801561098157600080fd5b50610447610990366004612a44565b611a17565b3480156109a157600080fd5b506102ac6109b0366004612aa7565b60166020526000908152604090205481565b3480156109ce57600080fd5b506109e26109dd366004612ad6565b611abe565b6040805193151584526020840192909252908201526060016102b6565b348015610a0b57600080fd5b506102ac600a5481565b348015610a2157600080fd5b50610447610a30366004612aa7565b611c1c565b348015610a4157600080fd5b50610447610a50366004612aa7565b611e4e565b348015610a6157600080fd5b50610447610a70366004612aa7565b611ea2565b348015610a8157600080fd5b50610447610a90366004612a44565b611ef0565b6000600b54600a5411610aa9576000610ab9565b600b54600a54610ab99190612b41565b60025490915082906001600160a01b036101009091048116908516610b9c57478310610af8576040516326baa33960e11b815260040160405180910390fd5b610b028347612b41565b841115610b2257604051636a259e3160e11b815260040160405180910390fd5b6001600160a01b0381163303610b4b5760405163a5eb0da960e01b815260040160405180910390fd5b83600003610b6057610b5d8347612b41565b91505b6040516001600160a01b0382169083156108fc029084906000818181858888f19350505050158015610b96573d6000803e3d6000fd5b50610c28565b83600003610c14576040516370a0823160e01b81526001600160a01b038616906370a0823190610bd0903090600401612ac2565b602060405180830381865afa158015610bed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c119190612b54565b91505b610c286001600160a01b0386168284611f6b565b5050505050565b610c37611fc2565b670de0b6b3a7640000811015610c685760405163181c9d0b60e21b8152600481018290526024015b60405180910390fd5b610c7481601054611ff4565b60108054908290556040805160a0808252601490820152731b5a5b9a5b5d5b519bdc94995dd85c99141bdbdb60621b60c082015260208101839052908101839052336060820152426080820152600080516020612c608339815191529060e0015b60405180910390a15050565b610ce9611fc2565b601354610d0090829062010000900460ff16612017565b601380548215156201000081810262ff0000198416179093556040805160a0808252601690820152753ab9b2a932b6b7bb32a9b430b932a1b7b7b63237bbb760511b60c082015260ff9490930493909316801515602084015292820152336060820152426080820152600080516020612c808339815191529060e001610cd5565b610d8961203e565b610d91611fc2565b610d99612061565b565b610da3611fc2565b610708811080610db5575062093a8081115b15610dd65760405163181c9d0b60e21b815260048101829052602401610c5f565b610de281601254611ff4565b60128054908290556040805160a0808252600c908201526b636f6f6c646f776e54696d6560a01b60c082015260208101839052908101839052336060820152426080820152600080516020612c608339815191529060e001610cd5565b6001600160a01b038216600090815260146020526040812060030154600954829190841115610e6e5760095493505b805b610e7b856001612b6d565b811015610eed57600081815260186020908152604080832060048101546003909101546001600160a01b038b1685526014909352908320600201549091610ec191612b80565b610ecb9190612b97565b9050610ed78185612b6d565b9350508080610ee590612bb9565b915050610e70565b50909150505b92915050565b6003546001600160a01b03163314610f26573360405163f90e066960e01b8152600401610c5f9190612ac2565b610f2e612071565b6001600160a01b038083166000908152601460205260408082206002015460035491516370a0823160e01b81529093859216906370a0823190610f75908890600401612ac2565b602060405180830381865afa158015610f92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb69190612b54565b610fc09190612b6d565b6011546003546040516370a0823160e01b815292935081851015926000929187916001600160a01b03909116906370a0823190611001908b90600401612ac2565b602060405180830381865afa15801561101e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110429190612b54565b61104c9190612b6d565b10801591506111545760018410156110675761106786612095565b83156110da57600060095411801561109957506001600160a01b03861660009081526014602052604090206003015415155b80156110cc57506009546110ae906001612b6d565b6001600160a01b038716600090815260146020526040902060030154105b156110da576110da86611c1c565b6001600160a01b03861660009081526014602052604090206002018390556008548390611108908690612b41565b6111129190612b6d565b6008556040517f9c98d31460518722c29ab4ea54cc3ddb400b0c544c7cdb0ececbd99599c86a6f9061114b908890889033904290612bd2565b60405180910390a15b8180156111685750601354610100900460ff165b1561117a5761117a8686600080612124565b505050505050565b6001600160a01b038116600090815260166020526040812054600111806111c557506009546001600160a01b038316600090815260146020526040902060030154115b156111d257506000919050565b610ef382600954610e3f565b6111e6612590565b610d9960006125c2565b6111f8612590565b6001811080156112085750600581115b156112295760405163181c9d0b60e21b815260048101829052602401610c5f565b42600454610e1061123a9190612b6d565b11156112965742600454610e106112519190612b6d565b42600454610e106112629190612b6d565b61126c9190612b41565b604051637be602fd60e11b8152600481019390935260248301919091526044820152606401610c5f565b600b805490829060006112a98385612b6d565b909155505042600455600a54600b547f625b712a40968f3a9487c8af20c07bb9e812f6eb9c62c4a3f1aa79837c5d5ad0919083906112e8908690612b6d565b6040805193845260208401929092529082015233606082015242608082015260a001610cd5565b611317612071565b61131f611fc2565b610d99612612565b610d9933611c1c565b6000546001600160a01b031690565b611347612590565b6001600160a01b038116158061136757506001600160a01b03811661dead145b156113875780604051635077b8ed60e11b8152600401610c5f9190612ac2565b61139381336001612622565b50565b6003546001600160a01b031633146113c3573360405163f90e066960e01b8152600401610c5f9190612ac2565b6113cb612071565b6001600160a01b038083166000908152601460205260408082206002015460035491516370a0823160e01b81529093859216906370a0823190611412908890600401612ac2565b602060405180830381865afa15801561142f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114539190612b54565b61145d9190612b41565b6011546003546040516370a0823160e01b815292935081851015926000929187916001600160a01b03909116906370a082319061149e908b90600401612ac2565b602060405180830381865afa1580156114bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114df9190612b54565b6114e99190612b41565b601354911115915060009060ff16156115a657601254600954600090815260186020526040902054429161151c91612b6d565b1061159b57600954600090815260186020526040812060020154611541908890612b41565b60098054600090815260186020526040808220600201849055600c549254825290206001015491925082916115769190612b80565b6115809190612b97565b60095460009081526018602052604090206003015550600190505b6013805460ff191690555b8280156115b557506000600954115b80156115db57506001600160a01b03871660009081526014602052604090206003015415155b801561160e57506009546115f0906001612b6d565b6001600160a01b038816600090815260146020526040902060030154105b1561161c5761161c87611c1c565b811561168a576001600160a01b03871660009081526014602052604090206002018490556008548490611650908790612b41565b61165a9190612b6d565b600855604051600080516020612ca083398151915290611681908990899033904290612bd2565b60405180910390a15b816116f1578460085461169d9190612b41565b6008556001600160a01b0387166000908152601460205260408120600201556116c5876126ec565b600080516020612ca0833981519152878633426040516116e89493929190612bd2565b60405180910390a15b828015611706575060135462010000900460ff165b15611718576117188787600184612124565b50505050505050565b611729611fc2565b60135461173f908290610100900460ff16612017565b6013805482151561010081810261ff001984161784556040805160a0808252810195909552723ab9b2a0b23229b430b932a1b7b7b63237bbb760691b60c086015260ff919093041680151560208501529183015233606083015242608083015290600080516020612c808339815191529060e001610cd5565b6117c0612071565b600b54600a5410156117f9576000600a54600b546117de9190612b41565b905080600b60008282546117f29190612b41565b9091555050505b6000600b54600a541161180d57600061181d565b600b54600a5461181d9190612b41565b9050600061182b8247612b41565b9050600060075411801561184157506000600854115b801561184f57506010548110155b801561186a575042601254600d546118679190612b6d565b11155b1561196d576013805460ff1916600190811790915560095461188b91612b6d565b600955600a5461189c908290612b6d565b600a5542600d8190556009805460009081526018602052604080822093909355815481528281206001018490556008549154815291909120600201819055600c546118e79083612b80565b6118f19190612b97565b6009805460009081526018602052604080822060030193909355600c548254825290839020600401555490517fbca3552fe0d30d45f1d5933dfad6033dd73aa7412d2c119ad414b538e2f5b4ac91610cd59184903390429093845260208401929092526001600160a01b03166040830152606082015260800190565b5050565b611979611fc2565b670de0b6b3a76400008111156119a55760405163181c9d0b60e21b815260048101829052602401610c5f565b6119b181600f54611ff4565b600f8054908290556040805160a0808252601590820152741b5a5b9a5b5d5b54995dd85c9914995c5d5a5c9959605a1b60c082015260208101839052908101839052336060820152426080820152600080516020612c608339815191529060e001610cd5565b611a1f611fc2565b6802b5e3af16b1880000811015611a4c5760405163181c9d0b60e21b815260048101829052602401610c5f565b611a5881600e54611ff4565b600e8054908290556040805160a0808252601590820152740dac2f0d2daeada82dadeeadce8a0cae48ae0dec6d605b1b60c082015260208101839052908101839052336060820152426080820152600080516020612c608339815191529060e001610cd5565b6001600160a01b038216600090815260146020526040812080546001918201548392839291908390821080611afd5750601254611afb8442612b41565b115b80611b11575081611b0e8442612b41565b10155b8015611b425750600e548711158015611b4257506001600160a01b0388166000908152601560205260409020548711155b15611be4576012548190611b568542612b41565b1180611b6b575082611b688542612b41565b10155b611b8857611b798442612b41565b611b839084612b41565b611b8c565b6012545b6001600160a01b038a166000908152601560205260409020548910611bb2576000611bd6565b6001600160a01b038a16600090815260156020526040902054611bd6908a90612b41565b955095509550505050611c15565b506001600160a01b038716600090815260156020526040902054861180611c0b8442612b41565b611b8c9084612b41565b9250925092565b6001600160a01b0381166000908152601460205260409020600301546009548190811115611c4957505050565b6001821015611c5757505050565b6012546000828152601860205260409020544291611c7491612b6d565b108015611c8d5750600954611c8a906001612b6d565b81105b15611ca45780611c9c81612bb9565b915050611c57565b6000611cb584610571600185612b41565b905080600f5411611e48576001600160a01b0384166000908152601460205260408120600301839055600b8054839290611cf0908490612b6d565b909155505060058054906000611d0583612bb9565b90915550506005805460009081526019602052604080822080546001600160a01b0319166001600160a01b038916179055825482528082204260019182015583548352818320600201859055925482529020600301849055611d679083612b41565b6005546000908152601960209081526040808320600401939093556001600160a01b0387168252601a9052908120805460019290611da6908490612b6d565b90915550506005546001600160a01b0385166000818152601b60209081526040808320601a8352818420548452909152808220939093559151909183156108fc02918491818181858888f19350505050158015611e07573d6000803e3d6000fd5b507f9e80c048bc588b388047ffc6e8153e7c11aa34312de7ed62e1858ff3a44ddce88482858542604051611e3f959493929190612a5d565b60405180910390a15b50505050565b611e56612590565b6001600160a01b0381161580611e7657506001600160a01b03811661dead145b15611e965780604051635077b8ed60e11b8152600401610c5f9190612ac2565b61139381336000612622565b611eaa612590565b611ebb81611eb6611330565b612788565b611ec78161dead6127bc565b60028054610100600160a81b0319166101006001600160a01b03841602179055611393816127f0565b611ef8611fc2565b611f0481601154611ff4565b60118054908290556040805160a0808252601690820152756d696e696d756d42616c616e6365456c696769626c6560501b60c082015260208101839052908101839052336060820152426080820152600080516020612c608339815191529060e001610cd5565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611fbd90849061282b565b505050565b3360009081526001602052604090205460ff16610d99573360405163118cdaa760e01b8152600401610c5f9190612ac2565b80820361196d5760405163657e16cf60e01b815260048101839052602401610c5f565b8015158215150361196d5760405162a7e72d60e41b81528215156004820152602401610c5f565b60025460ff16610d9957604051638dfc202b60e01b815260040160405180910390fd5b61206961203e565b610d99612885565b60025460ff1615610d995760405163d93c066560e01b815260040160405180910390fd5b600780549060006120a583612bb9565b909155505060078054600090815260176020908152604080832080546001600160a01b0319166001600160a01b03871690811790915593549383526016825280832093909355601490522042600490910155600954612105906001612b6d565b6001600160a01b03909116600090815260146020526040902060030155565b6001600160a01b038416600090815260146020526040812080546001918201549092909182108061215f575060125461215d8442612b41565b115b8061218e57506001600160a01b03871660009081526014602052604090206001015461218b8442612b41565b10155b156121c9576012546001600160a01b038816600090815260146020908152604080832060010193909355600e54601590915291902055612283565b506001600160a01b03861660009081526015602052604090205485116121ef8342612b41565b6001600160a01b0388166000908152601460205260408120600101805490919061221a908490612b41565b90915550506001600160a01b0387166000908152601560205260409020548610612245576000612269565b6001600160a01b038716600090815260156020526040902054612269908790612b41565b6001600160a01b0388166000908152601560205260409020555b6001600160a01b038716600090815260146020526040902042815560030154805b60125460008281526018602052604090205442916122c191612b6d565b1180156122da57506009546122d7906001612b6d565b81105b156122f157806122e981612bb9565b9150506122a4565b8680156122fd57508082105b1561240b57815b81811015612409578661237d5760008181526018602052604081206002015461232e908b90612b41565b600083815260186020526040902060028101829055600c54600190910154919250829161235b9190612b80565b6123659190612b97565b600083815260186020526040902060030155506123f7565b612388600183612b41565b8110156123f7576000818152601860205260408120600201546123ac908b90612b41565b600083815260186020526040902060028101829055600c5460019091015491925082916123d99190612b80565b6123e39190612b97565b600083815260186020526040902060030155505b8061240181612bb9565b915050612304565b505b82156125855760006124228a610571600185612b41565b6001600160a01b038b166000908152601460205260408120600301849055600b80549293508392909190612457908490612b6d565b90915550506006805490600061246c83612bb9565b9091555050600680546000908152601c602052604080822080546001600160a01b0319166001600160a01b038f161790558254825280822042600191820155835483528183206002018590559254825290206003018490556124ce9083612b41565b6006546000908152601c60209081526040808320600401939093556001600160a01b038d168252601d905290812080546001929061250d908490612b6d565b90915550506006546001600160a01b038b166000908152601e60209081526040808320601d83528184205484529091529081902091909155517ff4887889290c67b03b34d3638701d36ef17b7da283ad50ba55d58c3ec2689bbd9061257b908c908490879087904290612a5d565b60405180910390a1505b505050505050505050565b33612599611330565b6001600160a01b031614610d99573360405163118cdaa760e01b8152600401610c5f9190612ac2565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61261a612071565b610d996128d1565b6001600160a01b03831660009081526001602052604090205481151560ff90911615150361267657604051635ce75a3b60e01b81526001600160a01b03841660048201528115156024820152604401610c5f565b6001600160a01b03838116600081815260016020908152604091829020805460ff19168615159081179091558251938452938616908301528101919091524260608201527fff1d0a27274ca0cc8403b0e8f4a70b968164366f4856d18f7569eba542e9aae49060800160405180910390a1505050565b6001600160a01b038181166000818152601660208181526040808420805460078054875260178086528488205490991680885295855283872082905581875297845282862080546001600160a01b031990811687179091559186905587548652828620805490921690915594845260149091528220600481018390556003018290558354929390929161277e83612bfc565b9190505550505050565b806001600160a01b0316826001600160a01b03160361196d578160405163a936636960e01b8152600401610c5f9190612ac2565b806001600160a01b0316826001600160a01b03160361196d5781604051634726455360e11b8152600401610c5f9190612ac2565b6127f8612590565b6001600160a01b038116612822576000604051631e4fbdf760e01b8152600401610c5f9190612ac2565b611393816125c2565b60006128406001600160a01b03841683612916565b905080516000141580156128655750808060200190518101906128639190612c13565b155b15611fbd5782604051635274afe760e01b8152600401610c5f9190612ac2565b61288d61203e565b6002805460ff191690556040517f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906128c7903390612ac2565b60405180910390a1565b6128d9612071565b6002805460ff191660011790556040517f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906128c7903390612ac2565b60606129248383600061292b565b9392505050565b606081471015612950573060405163cd78605960e01b8152600401610c5f9190612ac2565b600080856001600160a01b0316848660405161296c9190612c30565b60006040518083038185875af1925050503d80600081146129a9576040519150601f19603f3d011682016040523d82523d6000602084013e6129ae565b606091505b50915091506129be8683836129c8565b9695505050505050565b6060826129dd576129d882612a1b565b612924565b81511580156129f457506001600160a01b0384163b155b15612a145783604051639996b31560e01b8152600401610c5f9190612ac2565b5080612924565b805115612a2b5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b600060208284031215612a5657600080fd5b5035919050565b6001600160a01b03959095168552602085019390935260408401919091526060830152608082015260a00190565b80356001600160a01b0381168114612aa257600080fd5b919050565b600060208284031215612ab957600080fd5b61292482612a8b565b6001600160a01b0391909116815260200190565b60008060408385031215612ae957600080fd5b612af283612a8b565b946020939093013593505050565b801515811461139357600080fd5b600060208284031215612b2057600080fd5b813561292481612b00565b634e487b7160e01b600052601160045260246000fd5b81810381811115610ef357610ef3612b2b565b600060208284031215612b6657600080fd5b5051919050565b80820180821115610ef357610ef3612b2b565b8082028115828204841417610ef357610ef3612b2b565b600082612bb457634e487b7160e01b600052601260045260246000fd5b500490565b600060018201612bcb57612bcb612b2b565b5060010190565b6001600160a01b039485168152602081019390935292166040820152606081019190915260800190565b600081612c0b57612c0b612b2b565b506000190190565b600060208284031215612c2557600080fd5b815161292481612b00565b6000825160005b81811015612c515760208186018101518583015201612c37565b50600092019182525091905056fe2dc908b86b38cfca773aadc8861ff9f24d2b644be4f8a6c2024cd71e120e5ef5da986e332f97963bfa4bb220bda255b40296aa680cff592b805c2deb80b1dbf3575aefa7e6b2ff996fc72aa74d12f4a59d118c607ab9c1d95c9d55788775285ba2646970667358221220ac5ab9f1967bc1fd1fd8ac59148ddce8a16b4752d4ff534453078115384046f564736f6c6343000812003300000000000000000000000037950c488cd8f0f58aa661b7560d1ba03a608b9300000000000000000000000070726f28ec6f462cac1fc7c60cc25281c72630f9

Deployed Bytecode

0x60806040526004361061028a5760003560e01c80630203649e1461029657806309c85e24146102bf5780630da817db146102d55780630fa16dce1461033a57806316b39b07146103ac5780631ef196ea146103ef5780631f685bac1461042757806327e633f9146104495780632a7e07f9146104695780632c91e2b314610489578063350ca4241461049f5780633631d26c146104b55780633a98ef39146104df5780633ce361d2146104f55780633f4ba83a1461050b57806345c08e6e1461052057806347f441ab146105405780634a90c2101461055657806350f4f9f81461057657806353d74fdf146105965780635c975abb146105ac5780636625618d146105c457806367314b37146105f15780636e0c05bb14610607578063715018a61461062757806376d566bd1461063c5780637706c4ba1461065c5780638450ce84146106a65780638456cb59146106c55780638c1708ab146106da5780638da5cb5b146106ef5780639761535d146107045780639d76ea581461071a5780639ed5519a1461073a578063a112ddc514610767578063a4475ce41461077d578063b2d1f2d8146107a2578063b319c6b7146107f6578063b5635f741461080c578063b6a5d7de14610822578063ba553dad14610842578063bd767e3d1461087a578063c06474e0146108a7578063c2fd076b146108c7578063cbe12969146108dd578063ce4f75281461090d578063d0e30db01461092d578063d4fc3b9814610935578063d93b609814610955578063e6688a8114610975578063e9bbb04014610995578063eb5ec54f146109c2578063ef5b478d146109ff578063ef5cfb8c14610a15578063f0b37c0414610a35578063f2fde38b14610a55578063f627b48a14610a7557600080fd5b3661029157005b600080fd5b3480156102a257600080fd5b506102ac600f5481565b6040519081526020015b60405180910390f35b3480156102cb57600080fd5b506102ac60095481565b3480156102e157600080fd5b506103296102f0366004612a44565b601960205260009081526040902080546001820154600283015460038401546004909401546001600160a01b0390931693919290919085565b6040516102b6959493929190612a5d565b34801561034657600080fd5b50610384610355366004612aa7565b601460205260009081526040902080546001820154600283015460038401546004909401549293919290919085565b604080519586526020860194909452928401919091526060830152608082015260a0016102b6565b3480156103b857600080fd5b506103e26103c7366004612a44565b6017602052600090815260409020546001600160a01b031681565b6040516102b69190612ac2565b3480156103fb57600080fd5b506102ac61040a366004612ad6565b601e60209081526000928352604080842090915290825290205481565b34801561043357600080fd5b50610447610442366004612ad6565b610a95565b005b34801561045557600080fd5b50610447610464366004612a44565b610c2f565b34801561047557600080fd5b50610447610484366004612b0e565b610ce1565b34801561049557600080fd5b506102ac600c5481565b3480156104ab57600080fd5b506102ac60045481565b3480156104c157600080fd5b506013546104cf9060ff1681565b60405190151581526020016102b6565b3480156104eb57600080fd5b506102ac60085481565b34801561050157600080fd5b506102ac600d5481565b34801561051757600080fd5b50610447610d81565b34801561052c57600080fd5b5061044761053b366004612a44565b610d9b565b34801561054c57600080fd5b506102ac600e5481565b34801561056257600080fd5b506102ac610571366004612ad6565b610e3f565b34801561058257600080fd5b50610447610591366004612ad6565b610ef9565b3480156105a257600080fd5b506102ac60075481565b3480156105b857600080fd5b5060025460ff166104cf565b3480156105d057600080fd5b506102ac6105df366004612aa7565b60156020526000908152604090205481565b3480156105fd57600080fd5b506102ac60115481565b34801561061357600080fd5b506102ac610622366004612aa7565b611182565b34801561063357600080fd5b506104476111de565b34801561064857600080fd5b50610447610657366004612a44565b6111f0565b34801561066857600080fd5b50610384610677366004612a44565b601860205260009081526040902080546001820154600283015460038401546004909401549293919290919085565b3480156106b257600080fd5b506013546104cf90610100900460ff1681565b3480156106d157600080fd5b5061044761130f565b3480156106e657600080fd5b50610447611327565b3480156106fb57600080fd5b506103e2611330565b34801561071057600080fd5b506102ac60065481565b34801561072657600080fd5b506003546103e2906001600160a01b031681565b34801561074657600080fd5b506102ac610755366004612aa7565b601d6020526000908152604090205481565b34801561077357600080fd5b506102ac60105481565b34801561078957600080fd5b506002546103e29061010090046001600160a01b031681565b3480156107ae57600080fd5b506103296107bd366004612a44565b601c60205260009081526040902080546001820154600283015460038401546004909401546001600160a01b0390931693919290919085565b34801561080257600080fd5b506102ac60125481565b34801561081857600080fd5b506102ac60055481565b34801561082e57600080fd5b5061044761083d366004612aa7565b61133f565b34801561084e57600080fd5b506102ac61085d366004612ad6565b601b60209081526000928352604080842090915290825290205481565b34801561088657600080fd5b506102ac610895366004612aa7565b601a6020526000908152604090205481565b3480156108b357600080fd5b506104476108c2366004612ad6565b611396565b3480156108d357600080fd5b506102ac600b5481565b3480156108e957600080fd5b506104cf6108f8366004612aa7565b60016020526000908152604090205460ff1681565b34801561091957600080fd5b50610447610928366004612b0e565b611721565b6104476117b8565b34801561094157600080fd5b506013546104cf9062010000900460ff1681565b34801561096157600080fd5b50610447610970366004612a44565b611971565b34801561098157600080fd5b50610447610990366004612a44565b611a17565b3480156109a157600080fd5b506102ac6109b0366004612aa7565b60166020526000908152604090205481565b3480156109ce57600080fd5b506109e26109dd366004612ad6565b611abe565b6040805193151584526020840192909252908201526060016102b6565b348015610a0b57600080fd5b506102ac600a5481565b348015610a2157600080fd5b50610447610a30366004612aa7565b611c1c565b348015610a4157600080fd5b50610447610a50366004612aa7565b611e4e565b348015610a6157600080fd5b50610447610a70366004612aa7565b611ea2565b348015610a8157600080fd5b50610447610a90366004612a44565b611ef0565b6000600b54600a5411610aa9576000610ab9565b600b54600a54610ab99190612b41565b60025490915082906001600160a01b036101009091048116908516610b9c57478310610af8576040516326baa33960e11b815260040160405180910390fd5b610b028347612b41565b841115610b2257604051636a259e3160e11b815260040160405180910390fd5b6001600160a01b0381163303610b4b5760405163a5eb0da960e01b815260040160405180910390fd5b83600003610b6057610b5d8347612b41565b91505b6040516001600160a01b0382169083156108fc029084906000818181858888f19350505050158015610b96573d6000803e3d6000fd5b50610c28565b83600003610c14576040516370a0823160e01b81526001600160a01b038616906370a0823190610bd0903090600401612ac2565b602060405180830381865afa158015610bed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c119190612b54565b91505b610c286001600160a01b0386168284611f6b565b5050505050565b610c37611fc2565b670de0b6b3a7640000811015610c685760405163181c9d0b60e21b8152600481018290526024015b60405180910390fd5b610c7481601054611ff4565b60108054908290556040805160a0808252601490820152731b5a5b9a5b5d5b519bdc94995dd85c99141bdbdb60621b60c082015260208101839052908101839052336060820152426080820152600080516020612c608339815191529060e0015b60405180910390a15050565b610ce9611fc2565b601354610d0090829062010000900460ff16612017565b601380548215156201000081810262ff0000198416179093556040805160a0808252601690820152753ab9b2a932b6b7bb32a9b430b932a1b7b7b63237bbb760511b60c082015260ff9490930493909316801515602084015292820152336060820152426080820152600080516020612c808339815191529060e001610cd5565b610d8961203e565b610d91611fc2565b610d99612061565b565b610da3611fc2565b610708811080610db5575062093a8081115b15610dd65760405163181c9d0b60e21b815260048101829052602401610c5f565b610de281601254611ff4565b60128054908290556040805160a0808252600c908201526b636f6f6c646f776e54696d6560a01b60c082015260208101839052908101839052336060820152426080820152600080516020612c608339815191529060e001610cd5565b6001600160a01b038216600090815260146020526040812060030154600954829190841115610e6e5760095493505b805b610e7b856001612b6d565b811015610eed57600081815260186020908152604080832060048101546003909101546001600160a01b038b1685526014909352908320600201549091610ec191612b80565b610ecb9190612b97565b9050610ed78185612b6d565b9350508080610ee590612bb9565b915050610e70565b50909150505b92915050565b6003546001600160a01b03163314610f26573360405163f90e066960e01b8152600401610c5f9190612ac2565b610f2e612071565b6001600160a01b038083166000908152601460205260408082206002015460035491516370a0823160e01b81529093859216906370a0823190610f75908890600401612ac2565b602060405180830381865afa158015610f92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb69190612b54565b610fc09190612b6d565b6011546003546040516370a0823160e01b815292935081851015926000929187916001600160a01b03909116906370a0823190611001908b90600401612ac2565b602060405180830381865afa15801561101e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110429190612b54565b61104c9190612b6d565b10801591506111545760018410156110675761106786612095565b83156110da57600060095411801561109957506001600160a01b03861660009081526014602052604090206003015415155b80156110cc57506009546110ae906001612b6d565b6001600160a01b038716600090815260146020526040902060030154105b156110da576110da86611c1c565b6001600160a01b03861660009081526014602052604090206002018390556008548390611108908690612b41565b6111129190612b6d565b6008556040517f9c98d31460518722c29ab4ea54cc3ddb400b0c544c7cdb0ececbd99599c86a6f9061114b908890889033904290612bd2565b60405180910390a15b8180156111685750601354610100900460ff165b1561117a5761117a8686600080612124565b505050505050565b6001600160a01b038116600090815260166020526040812054600111806111c557506009546001600160a01b038316600090815260146020526040902060030154115b156111d257506000919050565b610ef382600954610e3f565b6111e6612590565b610d9960006125c2565b6111f8612590565b6001811080156112085750600581115b156112295760405163181c9d0b60e21b815260048101829052602401610c5f565b42600454610e1061123a9190612b6d565b11156112965742600454610e106112519190612b6d565b42600454610e106112629190612b6d565b61126c9190612b41565b604051637be602fd60e11b8152600481019390935260248301919091526044820152606401610c5f565b600b805490829060006112a98385612b6d565b909155505042600455600a54600b547f625b712a40968f3a9487c8af20c07bb9e812f6eb9c62c4a3f1aa79837c5d5ad0919083906112e8908690612b6d565b6040805193845260208401929092529082015233606082015242608082015260a001610cd5565b611317612071565b61131f611fc2565b610d99612612565b610d9933611c1c565b6000546001600160a01b031690565b611347612590565b6001600160a01b038116158061136757506001600160a01b03811661dead145b156113875780604051635077b8ed60e11b8152600401610c5f9190612ac2565b61139381336001612622565b50565b6003546001600160a01b031633146113c3573360405163f90e066960e01b8152600401610c5f9190612ac2565b6113cb612071565b6001600160a01b038083166000908152601460205260408082206002015460035491516370a0823160e01b81529093859216906370a0823190611412908890600401612ac2565b602060405180830381865afa15801561142f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114539190612b54565b61145d9190612b41565b6011546003546040516370a0823160e01b815292935081851015926000929187916001600160a01b03909116906370a082319061149e908b90600401612ac2565b602060405180830381865afa1580156114bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114df9190612b54565b6114e99190612b41565b601354911115915060009060ff16156115a657601254600954600090815260186020526040902054429161151c91612b6d565b1061159b57600954600090815260186020526040812060020154611541908890612b41565b60098054600090815260186020526040808220600201849055600c549254825290206001015491925082916115769190612b80565b6115809190612b97565b60095460009081526018602052604090206003015550600190505b6013805460ff191690555b8280156115b557506000600954115b80156115db57506001600160a01b03871660009081526014602052604090206003015415155b801561160e57506009546115f0906001612b6d565b6001600160a01b038816600090815260146020526040902060030154105b1561161c5761161c87611c1c565b811561168a576001600160a01b03871660009081526014602052604090206002018490556008548490611650908790612b41565b61165a9190612b6d565b600855604051600080516020612ca083398151915290611681908990899033904290612bd2565b60405180910390a15b816116f1578460085461169d9190612b41565b6008556001600160a01b0387166000908152601460205260408120600201556116c5876126ec565b600080516020612ca0833981519152878633426040516116e89493929190612bd2565b60405180910390a15b828015611706575060135462010000900460ff165b15611718576117188787600184612124565b50505050505050565b611729611fc2565b60135461173f908290610100900460ff16612017565b6013805482151561010081810261ff001984161784556040805160a0808252810195909552723ab9b2a0b23229b430b932a1b7b7b63237bbb760691b60c086015260ff919093041680151560208501529183015233606083015242608083015290600080516020612c808339815191529060e001610cd5565b6117c0612071565b600b54600a5410156117f9576000600a54600b546117de9190612b41565b905080600b60008282546117f29190612b41565b9091555050505b6000600b54600a541161180d57600061181d565b600b54600a5461181d9190612b41565b9050600061182b8247612b41565b9050600060075411801561184157506000600854115b801561184f57506010548110155b801561186a575042601254600d546118679190612b6d565b11155b1561196d576013805460ff1916600190811790915560095461188b91612b6d565b600955600a5461189c908290612b6d565b600a5542600d8190556009805460009081526018602052604080822093909355815481528281206001018490556008549154815291909120600201819055600c546118e79083612b80565b6118f19190612b97565b6009805460009081526018602052604080822060030193909355600c548254825290839020600401555490517fbca3552fe0d30d45f1d5933dfad6033dd73aa7412d2c119ad414b538e2f5b4ac91610cd59184903390429093845260208401929092526001600160a01b03166040830152606082015260800190565b5050565b611979611fc2565b670de0b6b3a76400008111156119a55760405163181c9d0b60e21b815260048101829052602401610c5f565b6119b181600f54611ff4565b600f8054908290556040805160a0808252601590820152741b5a5b9a5b5d5b54995dd85c9914995c5d5a5c9959605a1b60c082015260208101839052908101839052336060820152426080820152600080516020612c608339815191529060e001610cd5565b611a1f611fc2565b6802b5e3af16b1880000811015611a4c5760405163181c9d0b60e21b815260048101829052602401610c5f565b611a5881600e54611ff4565b600e8054908290556040805160a0808252601590820152740dac2f0d2daeada82dadeeadce8a0cae48ae0dec6d605b1b60c082015260208101839052908101839052336060820152426080820152600080516020612c608339815191529060e001610cd5565b6001600160a01b038216600090815260146020526040812080546001918201548392839291908390821080611afd5750601254611afb8442612b41565b115b80611b11575081611b0e8442612b41565b10155b8015611b425750600e548711158015611b4257506001600160a01b0388166000908152601560205260409020548711155b15611be4576012548190611b568542612b41565b1180611b6b575082611b688542612b41565b10155b611b8857611b798442612b41565b611b839084612b41565b611b8c565b6012545b6001600160a01b038a166000908152601560205260409020548910611bb2576000611bd6565b6001600160a01b038a16600090815260156020526040902054611bd6908a90612b41565b955095509550505050611c15565b506001600160a01b038716600090815260156020526040902054861180611c0b8442612b41565b611b8c9084612b41565b9250925092565b6001600160a01b0381166000908152601460205260409020600301546009548190811115611c4957505050565b6001821015611c5757505050565b6012546000828152601860205260409020544291611c7491612b6d565b108015611c8d5750600954611c8a906001612b6d565b81105b15611ca45780611c9c81612bb9565b915050611c57565b6000611cb584610571600185612b41565b905080600f5411611e48576001600160a01b0384166000908152601460205260408120600301839055600b8054839290611cf0908490612b6d565b909155505060058054906000611d0583612bb9565b90915550506005805460009081526019602052604080822080546001600160a01b0319166001600160a01b038916179055825482528082204260019182015583548352818320600201859055925482529020600301849055611d679083612b41565b6005546000908152601960209081526040808320600401939093556001600160a01b0387168252601a9052908120805460019290611da6908490612b6d565b90915550506005546001600160a01b0385166000818152601b60209081526040808320601a8352818420548452909152808220939093559151909183156108fc02918491818181858888f19350505050158015611e07573d6000803e3d6000fd5b507f9e80c048bc588b388047ffc6e8153e7c11aa34312de7ed62e1858ff3a44ddce88482858542604051611e3f959493929190612a5d565b60405180910390a15b50505050565b611e56612590565b6001600160a01b0381161580611e7657506001600160a01b03811661dead145b15611e965780604051635077b8ed60e11b8152600401610c5f9190612ac2565b61139381336000612622565b611eaa612590565b611ebb81611eb6611330565b612788565b611ec78161dead6127bc565b60028054610100600160a81b0319166101006001600160a01b03841602179055611393816127f0565b611ef8611fc2565b611f0481601154611ff4565b60118054908290556040805160a0808252601690820152756d696e696d756d42616c616e6365456c696769626c6560501b60c082015260208101839052908101839052336060820152426080820152600080516020612c608339815191529060e001610cd5565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611fbd90849061282b565b505050565b3360009081526001602052604090205460ff16610d99573360405163118cdaa760e01b8152600401610c5f9190612ac2565b80820361196d5760405163657e16cf60e01b815260048101839052602401610c5f565b8015158215150361196d5760405162a7e72d60e41b81528215156004820152602401610c5f565b60025460ff16610d9957604051638dfc202b60e01b815260040160405180910390fd5b61206961203e565b610d99612885565b60025460ff1615610d995760405163d93c066560e01b815260040160405180910390fd5b600780549060006120a583612bb9565b909155505060078054600090815260176020908152604080832080546001600160a01b0319166001600160a01b03871690811790915593549383526016825280832093909355601490522042600490910155600954612105906001612b6d565b6001600160a01b03909116600090815260146020526040902060030155565b6001600160a01b038416600090815260146020526040812080546001918201549092909182108061215f575060125461215d8442612b41565b115b8061218e57506001600160a01b03871660009081526014602052604090206001015461218b8442612b41565b10155b156121c9576012546001600160a01b038816600090815260146020908152604080832060010193909355600e54601590915291902055612283565b506001600160a01b03861660009081526015602052604090205485116121ef8342612b41565b6001600160a01b0388166000908152601460205260408120600101805490919061221a908490612b41565b90915550506001600160a01b0387166000908152601560205260409020548610612245576000612269565b6001600160a01b038716600090815260156020526040902054612269908790612b41565b6001600160a01b0388166000908152601560205260409020555b6001600160a01b038716600090815260146020526040902042815560030154805b60125460008281526018602052604090205442916122c191612b6d565b1180156122da57506009546122d7906001612b6d565b81105b156122f157806122e981612bb9565b9150506122a4565b8680156122fd57508082105b1561240b57815b81811015612409578661237d5760008181526018602052604081206002015461232e908b90612b41565b600083815260186020526040902060028101829055600c54600190910154919250829161235b9190612b80565b6123659190612b97565b600083815260186020526040902060030155506123f7565b612388600183612b41565b8110156123f7576000818152601860205260408120600201546123ac908b90612b41565b600083815260186020526040902060028101829055600c5460019091015491925082916123d99190612b80565b6123e39190612b97565b600083815260186020526040902060030155505b8061240181612bb9565b915050612304565b505b82156125855760006124228a610571600185612b41565b6001600160a01b038b166000908152601460205260408120600301849055600b80549293508392909190612457908490612b6d565b90915550506006805490600061246c83612bb9565b9091555050600680546000908152601c602052604080822080546001600160a01b0319166001600160a01b038f161790558254825280822042600191820155835483528183206002018590559254825290206003018490556124ce9083612b41565b6006546000908152601c60209081526040808320600401939093556001600160a01b038d168252601d905290812080546001929061250d908490612b6d565b90915550506006546001600160a01b038b166000908152601e60209081526040808320601d83528184205484529091529081902091909155517ff4887889290c67b03b34d3638701d36ef17b7da283ad50ba55d58c3ec2689bbd9061257b908c908490879087904290612a5d565b60405180910390a1505b505050505050505050565b33612599611330565b6001600160a01b031614610d99573360405163118cdaa760e01b8152600401610c5f9190612ac2565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61261a612071565b610d996128d1565b6001600160a01b03831660009081526001602052604090205481151560ff90911615150361267657604051635ce75a3b60e01b81526001600160a01b03841660048201528115156024820152604401610c5f565b6001600160a01b03838116600081815260016020908152604091829020805460ff19168615159081179091558251938452938616908301528101919091524260608201527fff1d0a27274ca0cc8403b0e8f4a70b968164366f4856d18f7569eba542e9aae49060800160405180910390a1505050565b6001600160a01b038181166000818152601660208181526040808420805460078054875260178086528488205490991680885295855283872082905581875297845282862080546001600160a01b031990811687179091559186905587548652828620805490921690915594845260149091528220600481018390556003018290558354929390929161277e83612bfc565b9190505550505050565b806001600160a01b0316826001600160a01b03160361196d578160405163a936636960e01b8152600401610c5f9190612ac2565b806001600160a01b0316826001600160a01b03160361196d5781604051634726455360e11b8152600401610c5f9190612ac2565b6127f8612590565b6001600160a01b038116612822576000604051631e4fbdf760e01b8152600401610c5f9190612ac2565b611393816125c2565b60006128406001600160a01b03841683612916565b905080516000141580156128655750808060200190518101906128639190612c13565b155b15611fbd5782604051635274afe760e01b8152600401610c5f9190612ac2565b61288d61203e565b6002805460ff191690556040517f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906128c7903390612ac2565b60405180910390a1565b6128d9612071565b6002805460ff191660011790556040517f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906128c7903390612ac2565b60606129248383600061292b565b9392505050565b606081471015612950573060405163cd78605960e01b8152600401610c5f9190612ac2565b600080856001600160a01b0316848660405161296c9190612c30565b60006040518083038185875af1925050503d80600081146129a9576040519150601f19603f3d011682016040523d82523d6000602084013e6129ae565b606091505b50915091506129be8683836129c8565b9695505050505050565b6060826129dd576129d882612a1b565b612924565b81511580156129f457506001600160a01b0384163b155b15612a145783604051639996b31560e01b8152600401610c5f9190612ac2565b5080612924565b805115612a2b5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b600060208284031215612a5657600080fd5b5035919050565b6001600160a01b03959095168552602085019390935260408401919091526060830152608082015260a00190565b80356001600160a01b0381168114612aa257600080fd5b919050565b600060208284031215612ab957600080fd5b61292482612a8b565b6001600160a01b0391909116815260200190565b60008060408385031215612ae957600080fd5b612af283612a8b565b946020939093013593505050565b801515811461139357600080fd5b600060208284031215612b2057600080fd5b813561292481612b00565b634e487b7160e01b600052601160045260246000fd5b81810381811115610ef357610ef3612b2b565b600060208284031215612b6657600080fd5b5051919050565b80820180821115610ef357610ef3612b2b565b8082028115828204841417610ef357610ef3612b2b565b600082612bb457634e487b7160e01b600052601260045260246000fd5b500490565b600060018201612bcb57612bcb612b2b565b5060010190565b6001600160a01b039485168152602081019390935292166040820152606081019190915260800190565b600081612c0b57612c0b612b2b565b506000190190565b600060208284031215612c2557600080fd5b815161292481612b00565b6000825160005b81811015612c515760208186018101518583015201612c37565b50600092019182525091905056fe2dc908b86b38cfca773aadc8861ff9f24d2b644be4f8a6c2024cd71e120e5ef5da986e332f97963bfa4bb220bda255b40296aa680cff592b805c2deb80b1dbf3575aefa7e6b2ff996fc72aa74d12f4a59d118c607ab9c1d95c9d55788775285ba2646970667358221220ac5ab9f1967bc1fd1fd8ac59148ddce8a16b4752d4ff534453078115384046f564736f6c63430008120033

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

00000000000000000000000037950c488cd8f0f58aa661b7560d1ba03a608b9300000000000000000000000070726f28ec6f462cac1fc7c60cc25281c72630f9

-----Decoded View---------------
Arg [0] : initialOwner (address): 0x37950C488Cd8f0f58AA661B7560D1Ba03a608b93
Arg [1] : token (address): 0x70726f28ec6f462CaC1Fc7c60Cc25281c72630f9

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000037950c488cd8f0f58aa661b7560d1ba03a608b93
Arg [1] : 00000000000000000000000070726f28ec6f462cac1fc7c60cc25281c72630f9


Deployed Bytecode Sourcemap

28940:34400:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30401:48;;;;;;;;;;;;;;;;;;;160:25:1;;;148:2;133:18;30401:48:0;;;;;;;;30132:34;;;;;;;;;;;;;;;;31097:64;;;;;;;;;;-1:-1:-1;31097:64:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;31097:64:0;;;;;;;;;;;;;;;;;;;;;;:::i;30772:60::-;;;;;;;;;;-1:-1:-1;30772:60:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1503:25:1;;;1559:2;1544:18;;1537:34;;;;1587:18;;;1580:34;;;;1645:2;1630:18;;1623:34;1688:3;1673:19;;1666:35;1490:3;1475:19;30772:60:0;1244:463:1;30971:57:0;;;;;;;;;;-1:-1:-1;30971:57:0;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;30971:57:0;;;;;;;;;;:::i;31479:87::-;;;;;;;;;;-1:-1:-1;31479:87:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;39087:1014;;;;;;;;;;-1:-1:-1;39087:1014:0;;;;;:::i;:::-;;:::i;:::-;;46104:424;;;;;;;;;;-1:-1:-1;46104:424:0;;;;;:::i;:::-;;:::i;48625:338::-;;;;;;;;;;-1:-1:-1;48625:338:0;;;;;:::i;:::-;;:::i;30253:33::-;;;;;;;;;;;;;;;;29933:28;;;;;;;;;;;;;;;;30613:34;;;;;;;;;;-1:-1:-1;30613:34:0;;;;;;;;;;;2713:14:1;;2706:22;2688:41;;2676:2;2661:18;30613:34:0;2548:187:1;30095:30:0;;;;;;;;;;;;;;;;30293:43;;;;;;;;;;;;;;;;63246:91;;;;;;;;;;;;;:::i;47418:408::-;;;;;;;;;;-1:-1:-1;47418:408:0;;;;;:::i;:::-;;:::i;30343:51::-;;;;;;;;;;;;;;;;51394:569;;;;;;;;;;-1:-1:-1;51394:569:0;;;;;:::i;:::-;;:::i;54131:1107::-;;;;;;;;;;-1:-1:-1;54131:1107:0;;;;;:::i;:::-;;:::i;30057:31::-;;;;;;;;;;;;;;;;26771:86;;;;;;;;;;-1:-1:-1;26842:7:0;;;;26771:86;;30839:64;;;;;;;;;;-1:-1:-1;30839:64:0;;;;;:::i;:::-;;;;;;;;;;;;;;30509:51;;;;;;;;;;;;;;;;50761:282;;;;;;;;;;-1:-1:-1;50761:282:0;;;;;:::i;:::-;;:::i;19147:103::-;;;;;;;;;;;;;:::i;40412:579::-;;;;;;;;;;-1:-1:-1;40412:579:0;;;;;:::i;:::-;;:::i;31035:55::-;;;;;;;;;;-1:-1:-1;31035:55:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30654:39;;;;;;;;;;-1:-1:-1;30654:39:0;;;;;;;;;;;62957:90;;;;;;;;;;;;;:::i;52183:82::-;;;;;;;;;;;;;:::i;18423:87::-;;;;;;;;;;;;;:::i;30012:38::-;;;;;;;;;;;;;;;;29897:27;;;;;;;;;;-1:-1:-1;29897:27:0;;;;-1:-1:-1;;;;;29897:27:0;;;31406:66;;;;;;;;;;-1:-1:-1;31406:66:0;;;;;:::i;:::-;;;;;;;;;;;;;;30456:46;;;;;;;;;;;;;;;;29863:27;;;;;;;;;;-1:-1:-1;29863:27:0;;;;;;;-1:-1:-1;;;;;29863:27:0;;;31333:66;;;;;;;;;;-1:-1:-1;31333:66:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;31333:66:0;;;;;;;;;;;30567:37;;;;;;;;;;;;;;;;29968;;;;;;;;;;;;;;;;22928:255;;;;;;;;;;-1:-1:-1;22928:255:0;;;;;:::i;:::-;;:::i;31240:86::-;;;;;;;;;;-1:-1:-1;31240:86:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;31168:65;;;;;;;;;;-1:-1:-1;31168:65:0;;;;;:::i;:::-;;;;;;;;;;;;;;55470:1801;;;;;;;;;;-1:-1:-1;55470:1801:0;;;;;:::i;:::-;;:::i;30212:34::-;;;;;;;;;;;;;;;;20700:45;;;;;;;;;;-1:-1:-1;20700:45:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;48061:323;;;;;;;;;;-1:-1:-1;48061:323:0;;;;;:::i;:::-;;:::i;49200:1304::-;;;:::i;30700:41::-;;;;;;;;;;-1:-1:-1;30700:41:0;;;;;;;;;;;45438:429;;;;;;;;;;-1:-1:-1;45438:429:0;;;;;:::i;:::-;;:::i;44769:430::-;;;;;;;;;;-1:-1:-1;44769:430:0;;;;;:::i;:::-;;:::i;30910:54::-;;;;;;;;;;-1:-1:-1;30910:54:0;;;;;:::i;:::-;;;;;;;;;;;;;;43087:1423;;;;;;;;;;-1:-1:-1;43087:1423:0;;;;;:::i;:::-;;:::i;:::-;;;;2961:14:1;;2954:22;2936:41;;3008:2;2993:18;;2986:34;;;;3036:18;;;3029:34;2924:2;2909:18;43087:1423:0;2740:329:1;30173:32:0;;;;;;;;;;;;;;;;52472:1414;;;;;;;;;;-1:-1:-1;52472:1414:0;;;;;:::i;:::-;;:::i;23537:258::-;;;;;;;;;;-1:-1:-1;23537:258:0;;;;;:::i;:::-;;:::i;62489:263::-;;;;;;;;;;-1:-1:-1;62489:263:0;;;;;:::i;:::-;;:::i;46769:428::-;;;;;;;;;;-1:-1:-1;46769:428:0;;;;;:::i;:::-;;:::i;39087:1014::-;39155:14;39188:15;;39172:13;;:31;:69;;39240:1;39172:69;;;39222:15;;39206:13;;:31;;;;:::i;:::-;39309:12;;39155:86;;-1:-1:-1;39273:6:0;;-1:-1:-1;;;;;39309:12:0;;;;;;;39346:19;;39342:752;;39396:21;39386:6;:31;39382:101;;39445:22;;-1:-1:-1;;;39445:22:0;;;;;;;;;;;39382:101;39510:30;39534:6;39510:21;:30;:::i;:::-;39501:6;:39;39497:105;;;39568:18;;-1:-1:-1;;;39568:18:0;;;;;;;;;;;39497:105;-1:-1:-1;;;;;39620:22:0;;:10;:22;39616:107;;39670:37;;-1:-1:-1;;;39670:37:0;;;;;;;;;;;39616:107;39741:6;39751:1;39741:11;39737:95;;39786:30;39810:6;39786:21;:30;:::i;:::-;39773:43;;39737:95;39846:38;;-1:-1:-1;;;;;39846:26:0;;;:38;;;;;39873:10;;39846:38;;;;39873:10;39846:26;:38;;;;;;;;;;;;;;;;;;;;;39342:752;;;39921:6;39931:1;39921:11;39917:103;;39966:38;;-1:-1:-1;;;39966:38:0;;-1:-1:-1;;;;;39966:23:0;;;;;:38;;39998:4;;39966:38;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;39953:51;;39917:103;40034:48;-1:-1:-1;;;;;40034:26:0;;40061:8;40071:10;40034:26;:48::i;:::-;39144:957;;;39087:1014;;:::o;46104:424::-;20806:18;:16;:18::i;:::-;46204:7:::1;46193:8;:18;46189:80;;;46235:22;::::0;-1:-1:-1;;;46235:22:0;;::::1;::::0;::::1;160:25:1::0;;;133:18;;46235:22:0::1;;;;;;;;46189:80;46279:49;46297:8;46307:20;;46279:17;:49::i;:::-;46358:20;::::0;;46389:31;;;;46436:84:::1;::::0;;3842:3:1;3824:22;;;3883:2;3862:19;;;3855:31;-1:-1:-1;;;3917:3:1;3902:19;;3895:51;4013:4;3998:20;;3991:36;;;4043:18;;;4036:34;;;46492:10:0::1;-1:-1:-1::0;4086:18:1;;4079:60;46504:15:0::1;-1:-1:-1::0;4155:19:1;;4148:35;-1:-1:-1;;;;;;;;;;;46436:84:0;3978:3:1;3963:19;46436:84:0::1;;;;;;;;46178:350;46104:424:::0;:::o;48625:338::-;20806:18;:16;:18::i;:::-;48737:22:::1;::::0;48709:51:::1;::::0;48727:8;;48737:22;;::::1;;;48709:17;:51::i;:::-;48787:22;::::0;;48820:33;::::1;;48787:22:::0;48820:33;;::::1;-1:-1:-1::0;;48820:33:0;::::1;;::::0;;;48869:86:::1;::::0;;4496:3:1;4478:22;;;4537:2;4516:19;;;4509:31;-1:-1:-1;;;4571:3:1;4556:19;;4549:53;48787:22:0::1;::::0;;;::::1;::::0;;;::::1;4683:14:1::0;;4676:22;4669:4;4654:20;;4647:52;4715:18;;;4708:50;48927:10:0::1;-1:-1:-1::0;4774:18:1;;4767:60;48939:15:0::1;-1:-1:-1::0;4843:19:1;;4836:35;-1:-1:-1;;;;;;;;;;;48869:86:0;4634:3:1;4619:19;48869:86:0::1;4194:683:1::0;63246:91:0;26063:16;:14;:16::i;:::-;20806:18:::1;:16;:18::i;:::-;63314:15:::2;:13;:15::i;:::-;63246:91::o:0;47418:408::-;20806:18;:16;:18::i;:::-;47510:10:::1;47499:8;:21;:42;;;;47535:6;47524:8;:17;47499:42;47495:104;;;47565:22;::::0;-1:-1:-1;;;47565:22:0;;::::1;::::0;::::1;160:25:1::0;;;133:18;;47565:22:0::1;14:177:1::0;47495:104:0::1;47609:41;47627:8;47637:12;;47609:17;:41::i;:::-;47680:12;::::0;;47703:23;;;;47742:76:::1;::::0;;5196:3:1;5178:22;;;5237:2;5216:19;;;5209:31;-1:-1:-1;;;5271:3:1;5256:19;;5249:43;5359:4;5344:20;;5337:36;;;5389:18;;;5382:34;;;47790:10:0::1;-1:-1:-1::0;5432:18:1;;5425:60;47802:15:0::1;-1:-1:-1::0;5501:19:1;;5494:35;-1:-1:-1;;;;;;;;;;;47742:76:0;5324:3:1;5309:19;47742:76:0::1;4882:653:1::0;51394:569:0;-1:-1:-1;;;;;51549:23:0;;51478:7;51549:23;;;:15;:23;;;;;:38;;;51613:15;;51478:7;;51549:38;51602:26;;51598:85;;;51656:15;;51645:26;;51598:85;51710:10;51693:238;51726:12;:8;51737:1;51726:12;:::i;:::-;51722:1;:16;51693:238;;;51760:14;51844:13;;;:10;:13;;;;;;;;:43;;;;51811:29;;;;;-1:-1:-1;;;;;51778:23:0;;;;:15;:23;;;;;;:30;;;51844:43;;51778:62;;;:::i;:::-;51777:110;;;;:::i;:::-;51760:127;-1:-1:-1;51902:17:0;51760:127;51902:17;;:::i;:::-;;;51745:186;51740:3;;;;;:::i;:::-;;;;51693:238;;;-1:-1:-1;51948:7:0;;-1:-1:-1;;51394:569:0;;;;;:::o;54131:1107::-;33142:12;;-1:-1:-1;;;;;33142:12:0;33158:10;33142:26;33138:97;;33212:10;33192:31;;-1:-1:-1;;;33192:31:0;;;;;;;;:::i;33138:97::-;25797:19:::1;:17;:19::i;:::-;-1:-1:-1::0;;;;;54253:23:0;;::::2;54234:16;54253:23:::0;;;:15:::2;:23;::::0;;;;;:30:::2;;::::0;54320:12:::2;::::0;54313:38;;-1:-1:-1;;;54313:38:0;;54253:30;;54354:6;;54320:12:::2;::::0;54313:30:::2;::::0;:38:::2;::::0;54269:6;;54313:38:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:47;;;;:::i;:::-;54406:22;::::0;54464:12:::2;::::0;54457:38:::2;::::0;-1:-1:-1;;;54457:38:0;;54294:66;;-1:-1:-1;54394:34:0;;::::2;;::::0;54371:20:::2;::::0;54406:22;54498:6;;-1:-1:-1;;;;;54464:12:0;;::::2;::::0;54457:30:::2;::::0;:38:::2;::::0;54488:6;;54457:38:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:47;;;;:::i;:::-;:73;::::0;::::2;::::0;-1:-1:-1;54541:567:0::2;;54587:1;54576:8;:12;54572:70;;;54609:17;54619:6;54609:9;:17::i;:::-;54660:12:::0;;54656:250:::2;;54715:1;54697:15;;:19;:65;;;;-1:-1:-1::0;;;;;;54720:23:0;::::2;54761:1;54720:23:::0;;;:15:::2;:23;::::0;;;;:38:::2;;::::0;:42;;54697:65:::2;:129;;;;-1:-1:-1::0;54807:15:0::2;::::0;:19:::2;::::0;54825:1:::2;54807:19;:::i;:::-;-1:-1:-1::0;;;;;54766:23:0;::::2;;::::0;;;:15:::2;:23;::::0;;;;:38:::2;;::::0;:60:::2;54697:129;54693:198;;;54851:20;54864:6;54851:12;:20::i;:::-;-1:-1:-1::0;;;;;54920:23:0;::::2;;::::0;;;:15:::2;:23;::::0;;;;:30:::2;;:41:::0;;;54990:11:::2;::::0;54953:8;;54990:22:::2;::::0;55004:8;;54990:22:::2;:::i;:::-;:33;;;;:::i;:::-;54976:11;:47:::0;55043:53:::2;::::0;::::2;::::0;::::2;::::0;55052:6;;55060;;55068:10:::2;::::0;55080:15:::2;::::0;55043:53:::2;:::i;:::-;;;;;;;;54541:567;55122:15;:38;;;;-1:-1:-1::0;55141:19:0::2;::::0;::::2;::::0;::::2;;;55122:38;55118:113;;;55177:42;55190:6;55198;55206:5;55213::::0;55177:12:::2;:42::i;:::-;54223:1015;;;;54131:1107:::0;;:::o;50761:282::-;-1:-1:-1;;;;;50854:19:0;;50830:7;50854:19;;;:11;:19;;;;;;50876:1;-1:-1:-1;50854:23:0;:83;;-1:-1:-1;50922:15:0;;-1:-1:-1;;;;;50881:23:0;;;;;;:15;:23;;;;;:38;;;:56;50854:83;50850:124;;;-1:-1:-1;50961:1:0;;50761:282;-1:-1:-1;50761:282:0:o;50850:124::-;50991:44;51011:6;51019:15;;50991:19;:44::i;19147:103::-;16688:13;:11;:13::i;:::-;19212:30:::1;19239:1;19212:18;:30::i;40412:579::-:0;16688:13;:11;:13::i;:::-;40498:1:::1;40489:6;:10;:24;;;;;40512:1;40503:6;:10;40489:24;40485:84;;;40537:20;::::0;-1:-1:-1;;;40537:20:0;;::::1;::::0;::::1;160:25:1::0;;;133:18;;40537:20:0::1;14:177:1::0;40485:84:0::1;40605:15;40583:9;;40595:7;40583:19;;;;:::i;:::-;:37;40579:171;;;40660:15;40677:9;;40689:7;40677:19;;;;:::i;:::-;40722:15;40699:9;;40711:7;40699:19;;;;:::i;:::-;40698:39;;;;:::i;:::-;40644:94;::::0;-1:-1:-1;;;40644:94:0;;::::1;::::0;::::1;6859:25:1::0;;;;6900:18;;;6893:34;;;;6943:18;;;6936:34;6832:18;;40644:94:0::1;6657:319:1::0;40579:171:0::1;40780:15;::::0;;;40825:6;;40760:17:::1;40806:25;40825:6:::0;40780:15;40806:25:::1;:::i;:::-;::::0;;;-1:-1:-1;;40854:15:0::1;40842:9;:27:::0;40903:13:::1;::::0;40929:15:::1;::::0;40885:98:::1;::::0;40903:13;40918:9;;40929:24:::1;::::0;40947:6;;40929:24:::1;:::i;:::-;40885:98;::::0;;7240:25:1;;;7296:2;7281:18;;7274:34;;;;7324:18;;;7317:34;40955:10:0::1;7382:2:1::0;7367:18;;7360:60;40967:15:0::1;7451:3:1::0;7436:19;;7429:35;7227:3;7212:19;40885:98:0::1;6981:489:1::0;62957:90:0;25797:19;:17;:19::i;:::-;20806:18:::1;:16;:18::i;:::-;63026:13:::2;:11;:13::i;52183:82::-:0;52233:24;52246:10;52233:12;:24::i;18423:87::-;18469:7;18496:6;-1:-1:-1;;;;;18496:6:0;;18423:87::o;22928:255::-;16688:13;:11;:13::i;:::-;-1:-1:-1;;;;;23004:21:0;::::1;::::0;;:51:::1;;-1:-1:-1::0;;;;;;23029:26:0;::::1;23048:6;23029:26;23004:51;23000:124;;;23104:7;23079:33;;-1:-1:-1::0;;;23079:33:0::1;;;;;;;;:::i;23000:124::-;23134:41;23149:7;23158:10;23170:4;23134:14;:41::i;:::-;22928:255:::0;:::o;55470:1801::-;33142:12;;-1:-1:-1;;;;;33142:12:0;33158:10;33142:26;33138:97;;33212:10;33192:31;;-1:-1:-1;;;33192:31:0;;;;;;;;:::i;33138:97::-;25797:19:::1;:17;:19::i;:::-;-1:-1:-1::0;;;;;55595:23:0;;::::2;55576:16;55595:23:::0;;;:15:::2;:23;::::0;;;;;:30:::2;;::::0;55662:12:::2;::::0;55655:38;;-1:-1:-1;;;55655:38:0;;55595:30;;55696:6;;55662:12:::2;::::0;55655:30:::2;::::0;:38:::2;::::0;55611:6;;55655:38:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:47;;;;:::i;:::-;55748:22;::::0;55806:12:::2;::::0;55799:38:::2;::::0;-1:-1:-1;;;55799:38:0;;55636:66;;-1:-1:-1;55736:34:0;;::::2;;::::0;55713:20:::2;::::0;55748:22;55840:6;;-1:-1:-1;;;;;55806:12:0;;::::2;::::0;55799:30:::2;::::0;:38:::2;::::0;55830:6;;55799:38:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:47;;;;:::i;:::-;55922:14;::::0;55799:73;-1:-1:-1;55799:73:0::2;::::0;-1:-1:-1;55883:16:0::2;::::0;55922:14:::2;;55918:520;;;55998:12;::::0;55968:15:::2;::::0;55957:27:::2;::::0;;;:10:::2;:27;::::0;;;;:38;56014:15:::2;::::0;55957:53:::2;::::0;::::2;:::i;:::-;:72;55953:437;;56085:15;::::0;56050:21:::2;56074:27:::0;;;:10:::2;:27;::::0;;;;:41:::2;;::::0;:50:::2;::::0;56118:6;;56074:50:::2;:::i;:::-;56154:15;::::0;;56143:27:::2;::::0;;;:10:::2;:27;::::0;;;;;:41:::2;;:57:::0;;;56307:14:::2;::::0;56276:15;;56265:27;;;;:39:::2;;::::0;56050:74;;-1:-1:-1;56050:74:0;;56265:56:::2;::::0;56307:14;56265:56:::2;:::i;:::-;:72;;;;:::i;:::-;56230:15;::::0;56219:27:::2;::::0;;;:10:::2;:27;::::0;;;;:43:::2;;:118:::0;-1:-1:-1;56370:4:0::2;::::0;-1:-1:-1;55953:437:0::2;56404:14;:22:::0;;-1:-1:-1;;56404:22:0::2;::::0;;55918:520:::2;56452:15;:38;;;;;56489:1;56471:15;;:19;56452:38;:84;;;;-1:-1:-1::0;;;;;;56494:23:0;::::2;56535:1;56494:23:::0;;;:15:::2;:23;::::0;;;;:38:::2;;::::0;:42;;56452:84:::2;:148;;;;-1:-1:-1::0;56581:15:0::2;::::0;:19:::2;::::0;56599:1:::2;56581:19;:::i;:::-;-1:-1:-1::0;;;;;56540:23:0;::::2;;::::0;;;:15:::2;:23;::::0;;;;:38:::2;;::::0;:60:::2;56452:148;56448:201;;;56617:20;56630:6;56617:12;:20::i;:::-;56663:10;56659:222;;;-1:-1:-1::0;;;;;56690:23:0;::::2;;::::0;;;:15:::2;:23;::::0;;;;:30:::2;;:41:::0;;;56760:11:::2;::::0;56723:8;;56760:22:::2;::::0;56774:8;;56760:22:::2;:::i;:::-;:33;;;;:::i;:::-;56746:11;:47:::0;56813:56:::2;::::0;-1:-1:-1;;;;;;;;;;;56813:56:0;::::2;::::0;56825:6;;56833;;56841:10:::2;::::0;56853:15:::2;::::0;56813:56:::2;:::i;:::-;;;;;;;;56659:222;56896:10;56891:242;;56951:8;56937:11;;:22;;;;:::i;:::-;56923:11;:36:::0;-1:-1:-1;;;;;56974:23:0;::::2;57007:1;56974:23:::0;;;:15:::2;:23;::::0;;;;:30:::2;;:34:::0;57023:20:::2;56990:6:::0;57023:12:::2;:20::i;:::-;-1:-1:-1::0;;;;;;;;;;;57075:6:0::2;57083:8;57093:10;57105:15;57063:58;;;;;;;;;:::i;:::-;;;;;;;;56891:242;57147:15;:41;;;;-1:-1:-1::0;57166:22:0::2;::::0;;;::::2;;;57147:41;57143:121;;;57205:47;57218:6;57226;57234:4;57240:11;57205:12;:47::i;:::-;55565:1706;;;;;55470:1801:::0;;:::o;48061:323::-;20806:18;:16;:18::i;:::-;48170:19:::1;::::0;48142:48:::1;::::0;48160:8;;48170:19:::1;::::0;::::1;;;48142:17;:48::i;:::-;48217:19;::::0;;48247:30;::::1;;48217:19;48247:30:::0;;::::1;-1:-1:-1::0;;48247:30:0;::::1;;::::0;;48293:83:::1;::::0;;7777:3:1;7759:22;;;7797:19;;7790:31;;;;-1:-1:-1;;;7852:3:1;7837:19;;7830:50;48217:19:0::1;::::0;;;::::1;;7961:14:1::0;;7954:22;7947:4;7932:20;;7925:52;7993:18;;;7986:50;48348:10:0::1;-1:-1:-1::0;8052:18:1;;8045:60;48360:15:0::1;-1:-1:-1::0;8121:19:1;;8114:35;48217:19:0;-1:-1:-1;;;;;;;;;;;48293:83:0;7912:3:1;7897:19;48293:83:0::1;7475:680:1::0;49200:1304:0;25797:19;:17;:19::i;:::-;49290:15:::1;;49274:13;;:31;49270:148;;;49322:12;49355:13;;49337:15;;:31;;;;:::i;:::-;49322:46;;49402:4;49383:15;;:23;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;;49270:148:0::1;49430:21;49470:15;;49454:13;;:31;:69;;49522:1;49454:69;;;49504:15;;49488:13;;:31;;;;:::i;:::-;49430:93:::0;-1:-1:-1;49534:15:0::1;49552:37;49430:93:::0;49552:21:::1;:37;:::i;:::-;49534:55;;49635:1;49620:12;;:16;:48;;;;;49667:1;49653:11;;:15;49620:48;:96;;;;;49696:20;;49685:7;:31;;49620:96;:171;;;;;49776:15;49760:12;;49733:24;;:39;;;;:::i;:::-;:58;;49620:171;49602:895;;;49818:14;:21:::0;;-1:-1:-1;;49818:21:0::1;49835:4;49818:21:::0;;::::1;::::0;;;49872:15:::1;::::0;:19:::1;::::0;::::1;:::i;:::-;49854:15;:37:::0;49922:13:::1;::::0;:23:::1;::::0;49938:7;;49922:23:::1;:::i;:::-;49906:13;:39:::0;49987:15:::1;49960:24;:42:::0;;;50028:15:::1;::::0;;-1:-1:-1;50017:27:0;;;:10:::1;:27;::::0;;;;;:56;;;;50099:15;;50088:27;;;;;:39:::1;;:49:::0;;;50196:11:::1;::::0;50163:15;;50152:27;;;;;;:41:::1;;:55:::0;;;50278:14:::1;::::0;50268:24:::1;::::0;50130:7;50268:24:::1;:::i;:::-;:38;;;;:::i;:::-;50233:15;::::0;;50222:27:::1;::::0;;;:10:::1;:27;::::0;;;;;:43:::1;;:84:::0;;;;50381:14:::1;::::0;50332:15;;50321:27;;;;;;:57:::1;;:74:::0;50431:15;50415:70;;::::1;::::0;::::1;::::0;50448:7;;50457:10:::1;::::0;50469:15:::1;::::0;8391:25:1;;;8447:2;8432:18;;8425:34;;;;-1:-1:-1;;;;;8495:32:1;8490:2;8475:18;;8468:60;8559:2;8544:18;;8537:34;8378:3;8363:19;;8160:417;49602:895:0::1;49259:1245;;49200:1304::o:0;45438:429::-;20806:18;:16;:18::i;:::-;45539:7:::1;45528:8;:18;45524:80;;;45570:22;::::0;-1:-1:-1;;;45570:22:0;;::::1;::::0;::::1;160:25:1::0;;;133:18;;45570:22:0::1;14:177:1::0;45524:80:0::1;45614:50;45632:8;45642:21;;45614:17;:50::i;:::-;45694:21;::::0;;45726:32;;;;45774:85:::1;::::0;;8896:3:1;8878:22;;;8937:2;8916:19;;;8909:31;-1:-1:-1;;;8971:3:1;8956:19;;8949:52;9068:4;9053:20;;9046:36;;;9098:18;;;9091:34;;;45831:10:0::1;-1:-1:-1::0;9141:18:1;;9134:60;45843:15:0::1;-1:-1:-1::0;9210:19:1;;9203:35;-1:-1:-1;;;;;;;;;;;45774:85:0;9033:3:1;9018:19;45774:85:0::1;8582:662:1::0;44769:430:0;20806:18;:16;:18::i;:::-;44870:8:::1;44859;:19;44855:81;;;44902:22;::::0;-1:-1:-1;;;44902:22:0;;::::1;::::0;::::1;160:25:1::0;;;133:18;;44902:22:0::1;14:177:1::0;44855:81:0::1;44946:50;44964:8;44974:21;;44946:17;:50::i;:::-;45026:21;::::0;;45058:32;;;;45106:85:::1;::::0;;9563:3:1;9545:22;;;9604:2;9583:19;;;9576:31;-1:-1:-1;;;9638:3:1;9623:19;;9616:52;9735:4;9720:20;;9713:36;;;9765:18;;;9758:34;;;45163:10:0::1;-1:-1:-1::0;9808:18:1;;9801:60;45175:15:0::1;-1:-1:-1::0;9877:19:1;;9870:35;-1:-1:-1;;;;;;;;;;;45106:85:0;9700:3:1;9685:19;45106:85:0::1;9249:662:1::0;43087:1423:0;-1:-1:-1;;;;;43223:23:0;;43170:4;43223:23;;;:15;:23;;;;;:31;;43284:32;;;;;43170:4;;;;43223:31;43284:32;43170:4;;43396:12;;;:73;;-1:-1:-1;43457:12:0;;43429:25;43447:7;43429:15;:25;:::i;:::-;:40;43396:73;:131;;;-1:-1:-1;43519:8:0;43490:25;43508:7;43490:15;:25;:::i;:::-;:37;;43396:131;43377:294;;;;;43575:21;;43565:6;:31;;:91;;;;-1:-1:-1;;;;;;43627:29:0;;;;;;:21;:29;;;;;;43617:39;;;43565:91;43359:1144;;;43778:12;;43724:6;;43750:25;43768:7;43750:15;:25;:::i;:::-;:40;:98;;;-1:-1:-1;43840:8:0;43811:25;43829:7;43811:15;:25;:::i;:::-;:37;;43750:98;:214;;43938:25;43956:7;43938:15;:25;:::i;:::-;43926:38;;:8;:38;:::i;:::-;43750:214;;;43873:12;;43750:214;-1:-1:-1;;;;;43984:29:0;;;;;;:21;:29;;;;;;:38;-1:-1:-1;43984:144:0;;44127:1;43984:144;;;-1:-1:-1;;;;;44047:29:0;;;;;;:21;:29;;;;;;:38;;44079:6;;44047:38;:::i;:::-;43698:445;;;;;;;;;;;43359:1144;-1:-1:-1;;;;;;44185:29:0;;;;;;:21;:29;;;;;;:38;-1:-1:-1;44185:38:0;44302:25;44320:7;44302:15;:25;:::i;:::-;44290:38;;:8;:38;:::i;43087:1423::-;;;;;;:::o;52472:1414::-;-1:-1:-1;;;;;52549:23:0;;52528:18;52549:23;;;:15;:23;;;;;:38;;;52655:15;;52549:38;;52643:27;;52639:66;;;52687:7;;52472:1414;:::o;52639:66::-;52732:1;52719:10;:14;52715:53;;;52750:7;;52472:1414;:::o;52715:53::-;52834:12;;52799:21;;;;:10;:21;;;;;:32;52849:15;;52799:47;;;:::i;:::-;:65;:113;;;;-1:-1:-1;52893:15:0;;:19;;52911:1;52893:19;:::i;:::-;52881:9;:31;52799:113;52778:184;;;52939:11;;;;:::i;:::-;;;;52778:184;;;52974:15;52992:42;53012:6;53020:13;53032:1;53020:9;:13;:::i;52992:42::-;52974:60;;53074:7;53049:21;;:32;53045:834;;-1:-1:-1;;;;;53098:23:0;;;;;;:15;:23;;;;;:38;;:50;;;53163:15;:26;;53182:7;;53098:23;53163:26;;53182:7;;53163:26;:::i;:::-;;;;-1:-1:-1;;53204:18:0;:20;;;:18;:20;;;:::i;:::-;;;;-1:-1:-1;;53253:18:0;;;53239:33;;;;:13;:33;;;;;;:49;;-1:-1:-1;;;;;;53239:49:0;-1:-1:-1;;;;;53239:49:0;;;;;53317:18;;53303:33;;;;;53355:15;-1:-1:-1;53303:49:0;;;:67;53399:18;;53385:33;;;;;:45;;:55;;;53469:18;;53455:33;;;;:44;;:57;;;53573:13;;:9;:13;:::i;:::-;53541:18;;53527:33;;;;:13;:33;;;;;;;;:43;;:59;;;;-1:-1:-1;;;;;53601:30:0;;;;:22;:30;;;;;:35;;53635:1;;53527:33;53601:35;;53635:1;;53601:35;:::i;:::-;;;;-1:-1:-1;;53711:18:0;;-1:-1:-1;;;;;53651:25:0;;;;;;:17;:25;;;;;;;;53677:22;:30;;;;;;53651:57;;;;;;;;:78;;;;53744:33;;53651:25;;53744:33;;;;;53769:7;;53744:33;53651:25;53744:33;53769:7;53651:25;53744:33;;;;;;;;;;;;;;;;;;;;;53797:70;53811:6;53819:7;53828:10;53840:9;53851:15;53797:70;;;;;;;;;;:::i;:::-;;;;;;;;53045:834;52517:1369;;;52472:1414;:::o;23537:258::-;16688:13;:11;:13::i;:::-;-1:-1:-1;;;;;23615:21:0;::::1;::::0;;:51:::1;;-1:-1:-1::0;;;;;;23640:26:0;::::1;23659:6;23640:26;23615:51;23611:124;;;23715:7;23690:33;;-1:-1:-1::0;;;23690:33:0::1;;;;;;;;:::i;23611:124::-;23745:42;23760:7;23769:10;23781:5;23745:14;:42::i;62489:263::-:0;16688:13;:11;:13::i;:::-;62571:38:::1;62591:8;62601:7;:5;:7::i;:::-;62571:19;:38::i;:::-;62620:46;62640:8;62658:6;62620:19;:46::i;:::-;62677:12;:23:::0;;-1:-1:-1;;;;;;62677:23:0::1;;-1:-1:-1::0;;;;;62677:23:0;::::1;;;::::0;;62711:33:::1;62677:23:::0;62711::::1;:33::i;46769:428::-:0;20806:18;:16;:18::i;:::-;46940:51:::1;46958:8;46968:22;;46940:17;:51::i;:::-;47021:22;::::0;;47054:33;;;;47103:86:::1;::::0;;10230:3:1;10212:22;;;10271:2;10250:19;;;10243:31;-1:-1:-1;;;10305:3:1;10290:19;;10283:53;10403:4;10388:20;;10381:36;;;10433:18;;;10426:34;;;47161:10:0::1;-1:-1:-1::0;10476:18:1;;10469:60;47173:15:0::1;-1:-1:-1::0;10545:19:1;;10538:35;-1:-1:-1;;;;;;;;;;;47103:86:0;10368:3:1;10353:19;47103:86:0::1;9916:663:1::0;6907:162:0;7017:43;;;-1:-1:-1;;;;;10776:32:1;;7017:43:0;;;10758:51:1;10825:18;;;;10818:34;;;7017:43:0;;;;;;;;;;10731:18:1;;;;7017:43:0;;;;;;;;-1:-1:-1;;;;;7017:43:0;-1:-1:-1;;;7017:43:0;;;6990:71;;7010:5;;6990:19;:71::i;:::-;6907:162;;;:::o;22408:172::-;22488:10;22474:25;;;;:13;:25;;;;;;;;22469:104;;22550:10;22523:38;;-1:-1:-1;;;22523:38:0;;;;;;;;:::i;41452:184::-;41555:7;41543:8;:19;41539:90;;41586:31;;-1:-1:-1;;;41586:31:0;;;;;160:25:1;;;133:18;;41586:31:0;14:177:1;41142:178:0;41239:7;41227:19;;:8;:19;;;41223:90;;41270:31;;-1:-1:-1;;;41270:31:0;;2713:14:1;;2706:22;41270:31:0;;;2688:41:1;2661:18;;41270:31:0;2548:187:1;27760:130:0;26842:7;;;;27819:64;;27856:15;;-1:-1:-1;;;27856:15:0;;;;;;;;;;;27232:74;26063:16;:14;:16::i;:::-;27288:10:::1;:8;:10::i;27467:132::-:0;26842:7;;;;27529:63;;;27565:15;;-1:-1:-1;;;27565:15:0;;;;;;;;;;;60951:305;61006:12;:14;;;:12;:14;;;:::i;:::-;;;;-1:-1:-1;;61045:12:0;;;61031:27;;;;:13;:27;;;;;;;;:36;;-1:-1:-1;;;;;;61031:36:0;-1:-1:-1;;;;;61031:36:0;;;;;;;;61100:12;;61078:19;;;:11;:19;;;;;:34;;;;61123:15;:23;;;61162:15;61123:36;;;;:54;61229:15;;:19;;-1:-1:-1;61229:19:0;:::i;:::-;-1:-1:-1;;;;;61188:23:0;;;;;;;:15;:23;;;;;:38;;:60;60951:305::o;57657:3021::-;-1:-1:-1;;;;;57781:23:0;;57763:15;57781:23;;;:15;:23;;;;;:31;;57842:32;;;;;57781:31;;57842:32;;57943:12;;;:69;;-1:-1:-1;58000:12:0;;57972:25;57990:7;57972:15;:25;:::i;:::-;:40;57943:69;:147;;;-1:-1:-1;;;;;;58058:23:0;;;;;;:15;:23;;;;;:32;;;58029:25;58047:7;58029:15;:25;:::i;:::-;:61;;57943:147;57925:607;;;58152:12;;-1:-1:-1;;;;;58117:23:0;;;;;;:15;:23;;;;;;;;:32;;:47;;;;58211:21;;58179;:29;;;;;;:53;57925:607;;;-1:-1:-1;;;;;;58274:29:0;;;;;;:21;:29;;;;;;:38;-1:-1:-1;58364:25:0;58382:7;58364:15;:25;:::i;:::-;-1:-1:-1;;;;;58327:23:0;;;;;;:15;:23;;;;;:32;;:63;;:32;;:23;:63;;;;;:::i;:::-;;;;-1:-1:-1;;;;;;;58437:29:0;;;;;;:21;:29;;;;;;:38;-1:-1:-1;58437:83:0;;58519:1;58437:83;;;-1:-1:-1;;;;;58478:29:0;;;;;;:21;:29;;;;;;:38;;58510:6;;58478:38;:::i;:::-;-1:-1:-1;;;;;58405:29:0;;;;;;:21;:29;;;;;:115;57925:607;-1:-1:-1;;;;;58544:23:0;;;;;;:15;:23;;;;;58578:15;58544:49;;58627:38;;;;58719:184;58775:12;;58740:21;;;;:10;:21;;;;;:32;58790:15;;58740:47;;;:::i;:::-;:65;:113;;;;-1:-1:-1;58834:15:0;;:19;;58852:1;58834:19;:::i;:::-;58822:9;:31;58740:113;58719:184;;;58880:11;;;;:::i;:::-;;;;58719:184;;;58919:7;:33;;;;;58943:9;58930:10;:22;58919:33;58915:897;;;58985:10;59010:791;59025:9;59017:5;:17;59010:791;;;59060:11;59055:705;;59096:21;59120:17;;;:10;:17;;;;;:31;;;:40;;59154:6;;59120:40;:::i;:::-;59183:17;;;;:10;:17;;;;;:31;;;:47;;;59321:14;;59289:29;;;;;59096:64;;-1:-1:-1;59096:64:0;;59289:46;;59321:14;59289:46;:::i;:::-;:62;;;;:::i;:::-;59253:17;;;;:10;:17;;;;;:33;;:98;-1:-1:-1;59055:705:0;;;59412:13;59424:1;59412:9;:13;:::i;:::-;59404:5;:21;59400:341;;;59454:21;59478:17;;;:10;:17;;;;;:31;;;:40;;59512:6;;59478:40;:::i;:::-;59545:17;;;;:10;:17;;;;;:31;;;:47;;;59687:14;;59655:29;;;;;59454:64;;-1:-1:-1;59454:64:0;;59655:46;;59687:14;59655:46;:::i;:::-;:62;;;;:::i;:::-;59619:17;;;;:10;:17;;;;;:33;;:98;-1:-1:-1;59400:341:0;59778:7;;;;:::i;:::-;;;;59010:791;;;58954:858;58915:897;59828:6;59824:847;;;59851:15;59869:42;59889:6;59897:13;59909:1;59897:9;:13;:::i;59869:42::-;-1:-1:-1;;;;;59926:23:0;;;;;;:15;:23;;;;;:38;;:50;;;59991:15;:26;;59851:60;;-1:-1:-1;59851:60:0;;59991:15;;59926:23;59991:26;;59851:60;;59991:26;:::i;:::-;;;;-1:-1:-1;;60034:19:0;:21;;;:19;:21;;;:::i;:::-;;;;-1:-1:-1;;60085:19:0;;;60070:35;;;;:14;:35;;;;;;:51;;-1:-1:-1;;;;;;60070:51:0;-1:-1:-1;;;;;60070:51:0;;;;;60151:19;;60136:35;;;;;60186:15;-1:-1:-1;60136:47:0;;;:65;60231:19;;60216:35;;;;;:47;;:57;;;60303:19;;60288:35;;;;:46;;:59;;;60410:13;;:9;:13;:::i;:::-;60377:19;;60362:35;;;;:14;:35;;;;;;;;:45;;:61;;;;-1:-1:-1;;;;;60438:31:0;;;;:23;:31;;;;;:36;;60473:1;;60362:35;60438:36;;60473:1;;60438:36;:::i;:::-;;;;-1:-1:-1;;60551:19:0;;-1:-1:-1;;;;;60489:26:0;;;;;;:18;:26;;;;;;;;60516:23;:31;;;;;;60489:59;;;;;;;;;:81;;;;60590:69;;;;;60508:6;;60611:7;;60620:10;;60632:9;;60643:15;;60590:69;:::i;:::-;;;;;;;;59836:835;59824:847;57752:2926;;;;;57657:3021;;;;:::o;18707:162::-;18778:10;18767:7;:5;:7::i;:::-;-1:-1:-1;;;;;18767:21:0;;18763:99;;18839:10;18812:38;;-1:-1:-1;;;18812:38:0;;;;;;;;:::i;20238:191::-;20312:16;20331:6;;-1:-1:-1;;;;;20348:17:0;;;-1:-1:-1;;;;;;20348:17:0;;;;;;20381:40;;20331:6;;;;;;;20381:40;;20312:16;20381:40;20301:128;20238:191;:::o;27009:73::-;25797:19;:17;:19::i;:::-;27066:8:::1;:6;:8::i;24419:334::-:0;-1:-1:-1;;;;;24520:22:0;;;;;;:13;:22;;;;;;:31;;;:22;;;;:31;;;24516:109;;24575:38;;-1:-1:-1;;;24575:38:0;;-1:-1:-1;;;;;11049:32:1;;24575:38:0;;;11031:51:1;11125:14;;11118:22;11098:18;;;11091:50;11004:18;;24575:38:0;10863:284:1;24516:109:0;-1:-1:-1;;;;;24635:22:0;;;;;;;:13;:22;;;;;;;;;:30;;-1:-1:-1;;24635:30:0;;;;;;;;;;24681:64;;11415:34:1;;;11485:15;;;11465:18;;;11458:43;11517:18;;11510:50;;;;24729:15:0;11591:2:1;11576:18;;11569:34;24681:64:0;;11364:3:1;11349:19;24681:64:0;;;;;;;24419:334;;;:::o;61516:493::-;-1:-1:-1;;;;;61597:19:0;;;61574:20;61597:19;;;:11;:19;;;;;;;;;;61662:12;;;61648:27;;:13;:27;;;;;;;;;;61696:23;;;;;;;;;:38;;;61745:27;;;;;;;;;:40;;-1:-1:-1;;;;;;61745:40:0;;;;;;;;61796:23;;;;61844:12;;61830:27;;;;;:40;;;;;;;;61881:23;;;:15;:23;;;;;:36;;;:40;;;61932:38;;:42;;;61987:14;;61597:19;;61648:27;;61987:14;;;;:::i;:::-;;;;;;61563:446;;61516:493;:::o;42083:194::-;42192:7;-1:-1:-1;;;;;42178:21:0;:10;-1:-1:-1;;;;;42178:21:0;;42174:96;;42247:10;42223:35;;-1:-1:-1;;;42223:35:0;;;;;;;;:::i;42417:185::-;42526:7;-1:-1:-1;;;;;42512:21:0;:10;-1:-1:-1;;;;;42512:21:0;;42508:87;;42572:10;42557:26;;-1:-1:-1;;;42557:26:0;;;;;;;;:::i;19681:220::-;16688:13;:11;:13::i;:::-;-1:-1:-1;;;;;19766:22:0;::::1;19762:93;;19840:1;19812:31;;-1:-1:-1::0;;;19812:31:0::1;;;;;;;;:::i;19762:93::-;19865:28;19884:8;19865:18;:28::i;7459:295::-:0;7540:23;7566:33;-1:-1:-1;;;;;7566:27:0;;7594:4;7566:27;:33::i;:::-;7540:59;;7614:10;:17;7635:1;7614:22;;:57;;;;;7652:10;7641:30;;;;;;;;;;;;:::i;:::-;7640:31;7614:57;7610:137;;;7728:5;7695:40;;-1:-1:-1;;;7695:40:0;;;;;;;;:::i;28292:118::-;26063:16;:14;:16::i;:::-;28351:7:::1;:15:::0;;-1:-1:-1;;28351:15:0::1;::::0;;28382:20:::1;::::0;::::1;::::0;::::1;::::0;28391:10:::1;::::0;28382:20:::1;:::i;:::-;;;;;;;;28292:118::o:0;28031:116::-;25797:19;:17;:19::i;:::-;28091:7:::1;:14:::0;;-1:-1:-1;;28091:14:0::1;28101:4;28091:14;::::0;;28121:18:::1;::::0;::::1;::::0;::::1;::::0;28128:10:::1;::::0;28121:18:::1;:::i;2829:153::-:0;2904:12;2936:38;2958:6;2966:4;2972:1;2936:21;:38::i;:::-;2929:45;2829:153;-1:-1:-1;;;2829:153:0:o;3575:398::-;3674:12;3727:5;3703:21;:29;3699:110;;;3791:4;3756:41;;-1:-1:-1;;;3756:41:0;;;;;;;;:::i;3699:110::-;3820:12;3834:23;3861:6;-1:-1:-1;;;;;3861:11:0;3880:5;3887:4;3861:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3819:73;;;;3910:55;3937:6;3945:7;3954:10;3910:26;:55::i;:::-;3903:62;3575:398;-1:-1:-1;;;;;;3575:398:0:o;4737:391::-;4851:12;4881:7;4876:245;;4905:19;4913:10;4905:7;:19::i;:::-;4876:245;;;4961:17;;:22;:49;;;;-1:-1:-1;;;;;;4987:18:0;;;:23;4961:49;4957:121;;;5055:6;5038:24;;-1:-1:-1;;;5038:24:0;;;;;;;;:::i;4957:121::-;-1:-1:-1;5099:10:0;5092:17;;5396:328;5466:17;;:21;5462:255;;5561:10;5555:17;5618:15;5605:10;5601:2;5597:19;5590:44;5462:255;5688:17;;-1:-1:-1;;;5688:17:0;;;;;;;;;;;196:180:1;255:6;308:2;296:9;287:7;283:23;279:32;276:52;;;324:1;321;314:12;276:52;-1:-1:-1;347:23:1;;196:180;-1:-1:-1;196:180:1:o;381:489::-;-1:-1:-1;;;;;658:32:1;;;;640:51;;722:2;707:18;;700:34;;;;765:2;750:18;;743:34;;;;808:2;793:18;;786:34;851:3;836:19;;829:35;627:3;612:19;;381:489::o;875:173::-;943:20;;-1:-1:-1;;;;;992:31:1;;982:42;;972:70;;1038:1;1035;1028:12;972:70;875:173;;;:::o;1053:186::-;1112:6;1165:2;1153:9;1144:7;1140:23;1136:32;1133:52;;;1181:1;1178;1171:12;1133:52;1204:29;1223:9;1204:29;:::i;1712:203::-;-1:-1:-1;;;;;1876:32:1;;;;1858:51;;1846:2;1831:18;;1712:203::o;1920:254::-;1988:6;1996;2049:2;2037:9;2028:7;2024:23;2020:32;2017:52;;;2065:1;2062;2055:12;2017:52;2088:29;2107:9;2088:29;:::i;:::-;2078:39;2164:2;2149:18;;;;2136:32;;-1:-1:-1;;;1920:254:1:o;2179:118::-;2265:5;2258:13;2251:21;2244:5;2241:32;2231:60;;2287:1;2284;2277:12;2302:241;2358:6;2411:2;2399:9;2390:7;2386:23;2382:32;2379:52;;;2427:1;2424;2417:12;2379:52;2466:9;2453:23;2485:28;2507:5;2485:28;:::i;3074:127::-;3135:10;3130:3;3126:20;3123:1;3116:31;3166:4;3163:1;3156:15;3190:4;3187:1;3180:15;3206:128;3273:9;;;3294:11;;;3291:37;;;3308:18;;:::i;3339:184::-;3409:6;3462:2;3450:9;3441:7;3437:23;3433:32;3430:52;;;3478:1;3475;3468:12;3430:52;-1:-1:-1;3501:16:1;;3339:184;-1:-1:-1;3339:184:1:o;5540:125::-;5605:9;;;5626:10;;;5623:36;;;5639:18;;:::i;5670:168::-;5743:9;;;5774;;5791:15;;;5785:22;;5771:37;5761:71;;5812:18;;:::i;5843:217::-;5883:1;5909;5899:132;;5953:10;5948:3;5944:20;5941:1;5934:31;5988:4;5985:1;5978:15;6016:4;6013:1;6006:15;5899:132;-1:-1:-1;6045:9:1;;5843:217::o;6065:135::-;6104:3;6125:17;;;6122:43;;6145:18;;:::i;:::-;-1:-1:-1;6192:1:1;6181:13;;6065:135::o;6205:447::-;-1:-1:-1;;;;;6492:15:1;;;6474:34;;6539:2;6524:18;;6517:34;;;;6587:15;;6582:2;6567:18;;6560:43;6634:2;6619:18;;6612:34;;;;6423:3;6408:19;;6205:447::o;11614:136::-;11653:3;11681:5;11671:39;;11690:18;;:::i;:::-;-1:-1:-1;;;11726:18:1;;11614:136::o;11755:245::-;11822:6;11875:2;11863:9;11854:7;11850:23;11846:32;11843:52;;;11891:1;11888;11881:12;11843:52;11923:9;11917:16;11942:28;11964:5;11942:28;:::i;12005:412::-;12134:3;12172:6;12166:13;12197:1;12207:129;12221:6;12218:1;12215:13;12207:129;;;12319:4;12303:14;;;12299:25;;12293:32;12280:11;;;12273:53;12236:12;12207:129;;;-1:-1:-1;12391:1:1;12355:16;;12380:13;;;-1:-1:-1;12355:16:1;12005:412;-1:-1:-1;12005:412:1:o

Swarm Source

ipfs://ac5ab9f1967bc1fd1fd8ac59148ddce8a16b4752d4ff534453078115384046f5

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.