false
false
0

Contract Address Details

0x83736D58F496afab4cF7D8453575ab59279810ec

Token
CHOAM token (CHOAM)
Creator
0x67c20e–f52b67 at 0xaf4656–7205a9
Balance
0 CLO
Tokens
Fetching tokens...
Transactions
70 Transactions
Transfers
0 Transfers
Gas Used
2,875,583
Last Balance Update
18597400
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
ChoamToken




Optimization enabled
true
Compiler version
v0.8.0+commit.c7dfd78e




Optimization runs
200
EVM Version
default




Verified at
2024-09-26T15:25:15.345267Z

Contract source code

// SPDX-License-Identifier: No License (None)

pragma solidity ^0.8.0;
/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain`call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
      return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return _functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        return _functionCallWithValue(target, data, value, errorMessage);
    }

    function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a / b + (a % b == 0 ? 0 : 1);
    }
}


/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 */
library Counters {
    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        unchecked {
            counter._value += 1;
        }
    }

    function decrement(Counter storage counter) internal {
        uint256 value = counter._value;
        require(value > 0, "Counter: decrement overflow");
        unchecked {
            counter._value = value - 1;
        }
    }

    function reset(Counter storage counter) internal {
        counter._value = 0;
    }
}

/**
 * @dev Collection of functions related to array types.
 */
library Arrays {
    /**
     * @dev Searches a sorted `array` and returns the first index that contains
     * a value greater or equal to `element`. If no such index exists (i.e. all
     * values in the array are strictly less than `element`), the array length is
     * returned. Time complexity O(log n).
     *
     * `array` is expected to be sorted in ascending order, and to contain no
     * repeated elements.
     */
    function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
        if (array.length == 0) {
            return 0;
        }

        uint256 low = 0;
        uint256 high = array.length;

        while (low < high) {
            uint256 mid = Math.average(low, high);

            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
            // because Math.average rounds down (it does integer division with truncation).
            if (array[mid] > element) {
                high = mid;
            } else {
                low = mid + 1;
            }
        }

        // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
        if (low > 0 && array[low - 1] == element) {
            return low - 1;
        } else {
            return low;
        }
    }
}

abstract contract IERC223Recipient { 
/**
 * @dev Standard ERC223 function that will handle incoming token transfers.
 *
 * @param _from  Token sender address.
 * @param _value Amount of tokens.
 * @param _data  Transaction metadata.
 */
    function tokenReceived(address _from, uint _value, bytes memory _data) external virtual;
}


/**
 * @dev Interface of the ERC223 standard as defined in the EIP.
 */
interface IERC223 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

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

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

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

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable {
    address public _owner;

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

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

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

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

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

interface IWhitelist {
    function onlyWhitelisted(address _sender, address _recipient) external view returns (bool);
    function isWhitelisted(address _who) external view returns (bool);
    function isBlacklisted(address _who) external view returns (bool);
}

contract ERC223WhiteListToken is IERC223, Ownable {
    using Address for address;

    IWhitelist public whitelistContract;

    mapping (address => uint256) private _balances;

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

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;
    uint8 private _decimals;

    event SetWhitelistContract(address oldWhitelistContract, address newWhitelistContract);

    /**
     * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
     * a default value of 18.
     *
     * To select a different value for {decimals}, use {_setupDecimals}.
     *
     * All three of these values are immutable: they can only be set once during
     * construction.
     */
     
    constructor(string memory new_name, string memory new_symbol, uint8 new_decimals) {
        _name = new_name;
        _symbol = new_symbol;
        _decimals = new_decimals;
        _owner = msg.sender;
    }

    function setWhitelistContract(address _whitelistContract) onlyOwner external {
        emit SetWhitelistContract(address(whitelistContract), _whitelistContract);
        whitelistContract = IWhitelist(_whitelistContract);
    }

    /**
     * @dev Returns the name of the token.
     */
    function standard() public pure returns (string memory) {
        return "erc223";
    }

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

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

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

    /**
     * @dev See {IERC223-totalSupply}.
     */
    function totalSupply() public view override returns (uint256) {
        return _totalSupply;
    }

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

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

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

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

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

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

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

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

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

        _beforeTokenTransfer(sender, recipient, amount);
        
        _balances[sender] = _balances[sender] - amount;
        _balances[recipient] = _balances[recipient] + amount;
        
        if(recipient.isContract())
        {
            IERC223Recipient(recipient).tokenReceived(sender, amount, data);
        }
        emit Transfer(sender, recipient, amount);
        emit TransferData(data);
    }
    
    function _transferFrom(address sender, address recipient, uint256 amount) internal virtual {
        require(sender != address(0), "ERC223: transfer from the zero address");
        require(recipient != address(0), "ERC223: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);
        
        _balances[sender] = _balances[sender] - amount;
        _balances[recipient] = _balances[recipient] + amount;
        emit Transfer(sender, recipient, amount);
    }

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

        _beforeTokenTransfer(address(0), account, amount);

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

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

        _beforeTokenTransfer(account, address(0), amount);

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

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

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

    /**
     * @dev Sets {decimals} to a value other than the default one of 18.
     *
     * WARNING: This function should only be called from the constructor. Most
     * applications that interact with token contracts will not expect
     * {decimals} to ever change, and may work incorrectly if it does.
     */
    function _setupDecimals(uint8 decimals_) internal {
        _decimals = decimals_;
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be to transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}




/**
 * @dev This contract extends an ERC223 token with a snapshot mechanism. When a snapshot is created, the balances and
 * total supply at the time are recorded for later access.
 *
 * This can be used to safely create mechanisms based on token balances such as trustless dividends or weighted voting.
 * In naive implementations it's possible to perform a "double spend" attack by reusing the same balance from different
 * accounts. By using snapshots to calculate dividends or voting power, those attacks no longer apply. It can also be
 * used to create an efficient ERC223 forking mechanism.
 *
 * Snapshots are created by the internal {_snapshot} function, which will emit the {Snapshot} event and return a
 * snapshot id. To get the total supply at the time of a snapshot, call the function {totalSupplyAt} with the snapshot
 * id. To get the balance of an account at the time of a snapshot, call the {balanceOfAt} function with the snapshot id
 * and the account address.
 *
 * NOTE: Snapshot policy can be customized by overriding the {_getCurrentSnapshotId} method. For example, having it
 * return `block.number` will trigger the creation of snapshot at the begining of each new block. When overridding this
 * function, be careful about the monotonicity of its result. Non-monotonic snapshot ids will break the contract.
 *
 * Implementing snapshots for every block using this method will incur significant gas costs. For a gas-efficient
 * alternative consider {ERC223Votes}.
 *
 * ==== Gas Costs
 *
 * Snapshots are efficient. Snapshot creation is _O(1)_. Retrieval of balances or total supply from a snapshot is _O(log
 * n)_ in the number of snapshots that have been created, although _n_ for a specific account will generally be much
 * smaller since identical balances in subsequent snapshots are stored as a single entry.
 *
 * There is a constant overhead for normal ERC223 transfers due to the additional snapshot bookkeeping. This overhead is
 * only significant for the first transfer that immediately follows a snapshot for a particular account. Subsequent
 * transfers will have normal cost until the next snapshot, and so on.
 */

abstract contract ERC223Snapshot is ERC223WhiteListToken("CHOAM token", "CHOAM", 18) {
    // Inspired by Jordi Baylina's MiniMeToken to record historical balances:
    // https://github.com/Giveth/minimd/blob/ea04d950eea153a04c51fa510b068b9dded390cb/contracts/MiniMeToken.sol

    using Arrays for uint256[];
    using Counters for Counters.Counter;

    // Snapshotted values have arrays of ids and the value corresponding to that id. These could be an array of a
    // Snapshot struct, but that would impede usage of functions that work on an array.
    struct Snapshots {
        uint256[] ids;
        uint256[] values;
    }

    mapping(address => Snapshots) private _accountBalanceSnapshots;
    Snapshots private _totalSupplySnapshots;

    // Snapshot ids increase monotonically, with the first value being 1. An id of 0 is invalid.
    Counters.Counter private _currentSnapshotId;

    /**
     * @dev Emitted by {_snapshot} when a snapshot identified by `id` is created.
     */
    event Snapshot(uint256 id);

    /**
     * @dev Creates a new snapshot and returns its snapshot id.
     *
     * Emits a {Snapshot} event that contains the same id.
     *
     * {_snapshot} is `internal` and you have to decide how to expose it externally. Its usage may be restricted to a
     * set of accounts, for example using {AccessControl}, or it may be open to the public.
     *
     * [WARNING]
     * ====
     * While an open way of calling {_snapshot} is required for certain trust minimization mechanisms such as forking,
     * you must consider that it can potentially be used by attackers in two ways.
     *
     * First, it can be used to increase the cost of retrieval of values from snapshots, although it will grow
     * logarithmically thus rendering this attack ineffective in the long term. Second, it can be used to target
     * specific accounts and increase the cost of ERC223 transfers for them, in the ways specified in the Gas Costs
     * section above.
     *
     * We haven't measured the actual numbers; if this is something you're interested in please reach out to us.
     * ====
     */
    function _snapshot() internal virtual returns (uint256) {
        _currentSnapshotId.increment();

        uint256 currentId = _getCurrentSnapshotId();
        emit Snapshot(currentId);
        return currentId;
    }

    /**
     * @dev Get the current snapshotId
     */
    function _getCurrentSnapshotId() public view returns (uint256) {
        return _currentSnapshotId.current();
    }

    /**
     * @dev Retrieves the balance of `account` at the time `snapshotId` was created.
     */
    function balanceOfAt(address account, uint256 snapshotId) public view virtual returns (uint256) {
        (bool snapshotted, uint256 value) = _valueAt(snapshotId, _accountBalanceSnapshots[account]);

        return snapshotted ? value : balanceOf(account);
    }

    /**
     * @dev Retrieves the total supply at the time `snapshotId` was created.
     */
    function totalSupplyAt(uint256 snapshotId) public view virtual returns (uint256) {
        (bool snapshotted, uint256 value) = _valueAt(snapshotId, _totalSupplySnapshots);

        return snapshotted ? value : totalSupply();
    }

    // Update balance and/or total supply snapshots before the values are modified. This is implemented
    // in the _beforeTokenTransfer hook, which is executed for _mint, _burn, and _transfer operations.
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual override {
        super._beforeTokenTransfer(from, to, amount);

        if (from == address(0)) {
            // mint
            _updateAccountSnapshot(to);
            _updateTotalSupplySnapshot();
        } else if (to == address(0)) {
            // burn
            _updateAccountSnapshot(from);
            _updateTotalSupplySnapshot();
        } else {
            // transfer
            _updateAccountSnapshot(from);
            _updateAccountSnapshot(to);
        }
    }

    function _valueAt(uint256 snapshotId, Snapshots storage snapshots) private view returns (bool, uint256) {
        require(snapshotId > 0, "ERC223Snapshot: id is 0");
        require(snapshotId <= _getCurrentSnapshotId(), "ERC223Snapshot: nonexistent id");

        // When a valid snapshot is queried, there are three possibilities:
        //  a) The queried value was not modified after the snapshot was taken. Therefore, a snapshot entry was never
        //  created for this id, and all stored snapshot ids are smaller than the requested one. The value that corresponds
        //  to this id is the current one.
        //  b) The queried value was modified after the snapshot was taken. Therefore, there will be an entry with the
        //  requested id, and its value is the one to return.
        //  c) More snapshots were created after the requested one, and the queried value was later modified. There will be
        //  no entry for the requested id: the value that corresponds to it is that of the smallest snapshot id that is
        //  larger than the requested one.
        //
        // In summary, we need to find an element in an array, returning the index of the smallest value that is larger if
        // it is not found, unless said value doesn't exist (e.g. when all values are smaller). Arrays.findUpperBound does
        // exactly this.

        uint256 index = snapshots.ids.findUpperBound(snapshotId);

        if (index == snapshots.ids.length) {
            return (false, 0);
        } else {
            return (true, snapshots.values[index]);
        }
    }

    function _updateAccountSnapshot(address account) private {
        _updateSnapshot(_accountBalanceSnapshots[account], balanceOf(account));
    }

    function _updateTotalSupplySnapshot() private {
        _updateSnapshot(_totalSupplySnapshots, totalSupply());
    }

    function _updateSnapshot(Snapshots storage snapshots, uint256 currentValue) private {
        uint256 currentId = _getCurrentSnapshotId();
        if (_lastSnapshotId(snapshots.ids) < currentId) {
            snapshots.ids.push(currentId);
            snapshots.values.push(currentValue);
        }
    }

    function _lastSnapshotId(uint256[] storage ids) private view returns (uint256) {
        if (ids.length == 0) {
            return 0;
        } else {
            return ids[ids.length - 1];
        }
    }
}

// CHOAM token
contract ChoamToken is ERC223Snapshot {
    
    address public revenue_contract;
    
    modifier onlyRevenueContract
    {
        require(msg.sender == revenue_contract, "Only revenue contract is allowed to call snapshots");
        _;
    }
    
    constructor() {
        _mint(msg.sender, 15000000 * 1e18);
    }
    
    function makeSnapshot() onlyRevenueContract public
    {
        _snapshot();
    }
    
    function setRevenueContract(address _revenue_contract) onlyOwner external
    {
        revenue_contract = _revenue_contract;
    }
    
    function burnFrom(address _who, uint _amount) onlyOwner external
    {
        require(whitelistContract.isBlacklisted(_who), "Only blacklisted tokens can be burned");
        
        _burn(_who, _amount);
    }
    
    function rescueERC20(address token, address to) external onlyOwner {
        uint256 value = IERC223(token).balanceOf(address(this));
        IERC223(token).transfer(to, value);
    }
}

contract RevenueContract is Ownable {

    // Owner of the RevenueContract: 0xBF516C212015c0644cBF9536ddAaAd2125013CA3
    address public token_contract;
    mapping (uint256 => uint256)                   public reward_at_round;
    mapping (uint256 => bool)                      public claimable;
    mapping (address => mapping (uint256 => bool)) public paid_rewards;
    
    uint256 public last_round = 0;
    
    event PaymentSnapshot(uint256 id);
    event RewardDeposited(uint256 round_id);
    event RewardClaimed(address indexed claimer, uint256 round_id, uint256 amount);
    
    constructor() 
    {
        _owner = 0xBF516C212015c0644cBF9536ddAaAd2125013CA3; 
    }
    
    function setTokenContract(address new_token_contract) onlyOwner external
    {
        token_contract = new_token_contract;
    }
    
    function nextPaymentRoundSnapshot() onlyOwner external
    {
        ChoamToken(token_contract).makeSnapshot();
        last_round++;
        emit PaymentSnapshot(last_round);
    }
    
    function makeUnclaimable(uint256 _round_id) onlyOwner external payable
    {
        claimable[_round_id] = false;
    }
    
    function depositReward(uint256 _round_id) onlyOwner external payable
    {
        reward_at_round[_round_id] += msg.value;
        claimable[_round_id] = true;
        emit RewardDeposited(_round_id);
    }
    
    function claimReward(uint256 _round) external
    {
        require(!paid_rewards[msg.sender][_round], "Reward for this round was already paid to this address");
        require(_round <= last_round, "Rewards can be claimed for completed rounds only");
        require(claimable[_round], "The reward for this round is not yet deposited");
        
        uint256 _reward;
        _reward = reward_at_round[_round] * ChoamToken(token_contract).balanceOfAt(msg.sender, _round) / ChoamToken(token_contract).totalSupplyAt(_round);
        
        paid_rewards[msg.sender][_round] = true;
        payable(msg.sender).transfer(_reward);
        
        emit RewardClaimed(msg.sender, _round, _reward);
    }
    
    function claimRewardForUser(address _who, uint256 _round) external
    {
        require(!paid_rewards[_who][_round], "Reward for this round was already paid to this address");
        require(_round <= last_round, "Rewards can be claimed for completed rounds only");
        require(claimable[_round], "The reward for this round is not yet deposited");
        
        uint256 _reward;
        _reward = reward_at_round[_round] * ChoamToken(token_contract).balanceOfAt(_who, _round) / ChoamToken(token_contract).totalSupplyAt(_round);
        
        paid_rewards[_who][_round] = true;
        payable(_who).transfer(_reward);
        
        emit RewardClaimed(_who, _round, _reward);
    }
    
    function rewardForRound(address _who, uint256 _round) public view returns (uint256 _reward, bool _claimed_already)
    {
        return (reward_at_round[_round] * ChoamToken(token_contract).balanceOfAt(_who, _round) / ChoamToken(token_contract).totalSupplyAt(_round), paid_rewards[_who][_round]);
    }
    
    function rescueERC20(address token, address to) external onlyOwner {
        uint256 value = IERC223(token).balanceOf(address(this));
        IERC223(token).transfer(to, value);
    }
}
        

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[]},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"spender","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"SetWhitelistContract","inputs":[{"type":"address","name":"oldWhitelistContract","internalType":"address","indexed":false},{"type":"address","name":"newWhitelistContract","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Snapshot","inputs":[{"type":"uint256","name":"id","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"TransferData","inputs":[{"type":"bytes","name":"data","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"_getCurrentSnapshotId","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"_owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"address","name":"spender","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approve","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOfAt","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"snapshotId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"burnFrom","inputs":[{"type":"address","name":"_who","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"decimals","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"decreaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"subtractedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"increaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"addedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"makeSnapshot","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"rescueERC20","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"address","name":"to","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"revenue_contract","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRevenueContract","inputs":[{"type":"address","name":"_revenue_contract","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setWhitelistContract","inputs":[{"type":"address","name":"_whitelistContract","internalType":"address"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"standard","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupplyAt","inputs":[{"type":"uint256","name":"snapshotId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferFrom","inputs":[{"type":"address","name":"sender","internalType":"address"},{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IWhitelist"}],"name":"whitelistContract","inputs":[]}]
              

Contract Creation Code

Verify & Publish
0x60806040523480156200001157600080fd5b506040518060400160405280600b81526020016a21a427a0a6903a37b5b2b760a91b8152506040518060400160405280600581526020016443484f414d60d81b815250601282600590805190602001906200006e9291906200034b565b508151620000849060069060208501906200034b565b506007805460ff90921660ff199092169190911790555050600080546001600160a01b03191633908117909155620000c8906a0c685fa11e01ec6f000000620000ce565b620004b7565b6001600160a01b038216620001005760405162461bcd60e51b8152600401620000f790620003f1565b60405180910390fd5b6200010e60008383620001a4565b806004546200011e91906200042f565b6004556001600160a01b038216600090815260026020526040902054620001479082906200042f565b6001600160a01b0383166000818152600260205260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906200019890859062000426565b60405180910390a35050565b620001bc8383836200021660201b62000c651760201c565b6001600160a01b038316620001e657620001d6826200021b565b620001e06200024c565b62000216565b6001600160a01b0382166200020057620001d6836200021b565b6200020b836200021b565b62000216826200021b565b505050565b6001600160a01b0381166000908152600860205260409020620002499062000243836200025e565b6200027d565b50565b6200025c600962000243620002cc565b565b6001600160a01b0381166000908152600260205260409020545b919050565b600062000289620002d2565b9050806200029784620002f0565b101562000216578254600180820185556000858152602080822090930193909355938401805494850181558252902090910155565b60045490565b6000620002eb600b6200034760201b62000c6a1760201c565b905090565b8054600090620003035750600062000278565b8154829062000315906001906200044a565b815481106200033457634e487b7160e01b600052603260045260246000fd5b9060005260206000200154905062000278565b5490565b828054620003599062000464565b90600052602060002090601f0160209004810192826200037d5760008555620003c8565b82601f106200039857805160ff1916838001178555620003c8565b82800160010185558215620003c8579182015b82811115620003c8578251825591602001919060010190620003ab565b50620003d6929150620003da565b5090565b5b80821115620003d65760008155600101620003db565b6020808252818101527f4552433232333a206d696e7420746f20746865207a65726f2061646472657373604082015260600190565b90815260200190565b60008219821115620004455762000445620004a1565b500190565b6000828210156200045f576200045f620004a1565b500390565b6002810460018216806200047957607f821691505b602082108114156200049b57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b611a4980620004c76000396000f3fe608060405234801561001057600080fd5b50600436106101a95760003560e01c806379cc6790116100f9578063a457c2d711610097578063b3b2216311610071578063b3b2216314610336578063be45fd621461033e578063dd62ed3e14610351578063f2fde38b14610364576101a9565b8063a457c2d714610308578063a9059cbb1461031b578063b2bdfa7b1461032e576101a9565b8063879a8540116100d3578063879a8540146102dd5780638da5cb5b146102e557806395d89b41146102ed578063981b24d0146102f5576101a9565b806379cc6790146102ad57806383b76b1f146102c057806384900b04146102d5576101a9565b806339509351116101665780635a3b7e42116101405780635a3b7e42146102775780635d799f871461027f57806370a0823114610292578063715018a6146102a5576101a9565b8063395093511461023e578063498a6de7146102515780634ee2cd7e14610264576101a9565b806306fdde03146101ae578063095ea7b3146101cc57806312f26140146101ec57806318160ddd1461020157806323b872dd14610216578063313ce56714610229575b600080fd5b6101b6610377565b6040516101c39190611675565b60405180910390f35b6101df6101da3660046114b6565b610409565b6040516101c3919061166a565b6101ff6101fa36600461142f565b610420565b005b6102096104bc565b6040516101c3919061195c565b6101df61022436600461147b565b6104c2565b610231610596565b6040516101c39190611965565b6101df61024c3660046114b6565b61059f565b6101ff61025f36600461142f565b6105d6565b6102096102723660046114b6565b610622565b6101b661066b565b6101ff61028d366004611449565b61068b565b6102096102a036600461142f565b6107bd565b6101ff6107dc565b6101ff6102bb3660046114b6565b610850565b6102c8610924565b6040516101c391906115fc565b6102c8610933565b610209610942565b6102c8610953565b6101b6610962565b610209610303366004611581565b610971565b6101df6103163660046114b6565b6109a1565b6101df6103293660046114b6565b6109d8565b6102c8610a7a565b6101ff610a89565b6101df61034c3660046114df565b610abe565b61020961035f366004611449565b610b8f565b6101ff61037236600461142f565b610bba565b606060058054610386906119c2565b80601f01602080910402602001604051908101604052809291908181526020018280546103b2906119c2565b80156103ff5780601f106103d4576101008083540402835291602001916103ff565b820191906000526020600020905b8154815290600101906020018083116103e257829003601f168201915b5050505050905090565b6000610416338484610c6e565b5060015b92915050565b6000546001600160a01b031633146104535760405162461bcd60e51b815260040161044a90611780565b60405180910390fd5b6001546040517f1465a382917ea64603bfcdbf38f9dc1df9edcc414980b0b670da47f990c572a791610492916001600160a01b03909116908490611610565b60405180910390a1600180546001600160a01b0319166001600160a01b0392909216919091179055565b60045490565b6001546040516360ec778160e11b81526000916001600160a01b03169063c1d8ef02906104f59087908790600401611610565b60206040518083038186803b15801561050d57600080fd5b505afa158015610521573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105459190611561565b50610551848484610d22565b6001600160a01b03841660009081526003602090815260408083203380855292529091205461058c9186916105879086906119ab565b610c6e565b5060019392505050565b60075460ff1690565b3360008181526003602090815260408083206001600160a01b03871684529091528120549091610416918590610587908690611973565b6000546001600160a01b031633146106005760405162461bcd60e51b815260040161044a90611780565b600c80546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038216600090815260086020526040812081908190610649908590610e1f565b91509150816106605761065b856107bd565b610662565b805b95945050505050565b60408051808201909152600681526565726332323360d01b602082015290565b6000546001600160a01b031633146106b55760405162461bcd60e51b815260040161044a90611780565b6040516370a0823160e01b81526000906001600160a01b038416906370a08231906106e49030906004016115fc565b60206040518083038186803b1580156106fc57600080fd5b505afa158015610710573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107349190611599565b60405163a9059cbb60e01b81529091506001600160a01b0384169063a9059cbb90610765908590859060040161162a565b602060405180830381600087803b15801561077f57600080fd5b505af1158015610793573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b79190611561565b50505050565b6001600160a01b0381166000908152600260205260409020545b919050565b6000546001600160a01b031633146108065760405162461bcd60e51b815260040161044a90611780565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000546001600160a01b0316331461087a5760405162461bcd60e51b815260040161044a90611780565b60015460405163fe575a8760e01b81526001600160a01b039091169063fe575a87906108aa9085906004016115fc565b60206040518083038186803b1580156108c257600080fd5b505afa1580156108d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108fa9190611561565b6109165760405162461bcd60e51b815260040161044a9061184d565b6109208282610ecb565b5050565b600c546001600160a01b031681565b6001546001600160a01b031681565b600061094e600b610c6a565b905090565b6000546001600160a01b031690565b606060068054610386906119c2565b6000806000610981846009610e1f565b9150915081610997576109926104bc565b610999565b805b949350505050565b3360008181526003602090815260408083206001600160a01b038716845290915281205490916104169185906105879086906119ab565b6001546040516360ec778160e11b81526000916001600160a01b03169063c1d8ef0290610a0b9033908790600401611610565b60206040518083038186803b158015610a2357600080fd5b505afa158015610a37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a5b9190611561565b5060408051600081526020810190915261041690339085908590610f95565b6000546001600160a01b031681565b600c546001600160a01b03163314610ab35760405162461bcd60e51b815260040161044a906117fb565b610abb611155565b50565b6001546040516360ec778160e11b81526000916001600160a01b03169063c1d8ef0290610af19033908990600401611610565b60206040518083038186803b158015610b0957600080fd5b505afa158015610b1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b419190611561565b50610b8433868686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610f9592505050565b506001949350505050565b6001600160a01b03918216600090815260036020908152604080832093909416825291909152205490565b6000546001600160a01b03163314610be45760405162461bcd60e51b815260040161044a90611780565b6001600160a01b038116610c0a5760405162461bcd60e51b815260040161044a906116bf565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b505050565b5490565b6001600160a01b038316610c945760405162461bcd60e51b815260040161044a906118d4565b6001600160a01b038216610cba5760405162461bcd60e51b815260040161044a90611919565b6001600160a01b0380841660008181526003602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610d1590859061195c565b60405180910390a3505050565b6001600160a01b038316610d485760405162461bcd60e51b815260040161044a906117b5565b6001600160a01b038216610d6e5760405162461bcd60e51b815260040161044a90611705565b610d798383836111a9565b6001600160a01b038316600090815260026020526040902054610d9d9082906119ab565b6001600160a01b038085166000908152600260205260408082209390935590841681522054610dcd908290611973565b6001600160a01b0380841660008181526002602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610d1590859061195c565b60008060008411610e425760405162461bcd60e51b815260040161044a90611688565b610e4a610942565b841115610e695760405162461bcd60e51b815260040161044a90611749565b6000610e758486611201565b8454909150811415610e8e576000809250925050610ec4565b6001846001018281548110610eb357634e487b7160e01b600052603260045260246000fd5b906000526020600020015492509250505b9250929050565b6001600160a01b038216610ef15760405162461bcd60e51b815260040161044a90611892565b610efd826000836111a9565b6001600160a01b038216600090815260026020526040902054610f219082906119ab565b6001600160a01b038316600090815260026020526040902055600454610f489082906119ab565b6004556040516000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610f8990859061195c565b60405180910390a35050565b6001600160a01b038416610fbb5760405162461bcd60e51b815260040161044a906117b5565b6001600160a01b038316610fe15760405162461bcd60e51b815260040161044a90611705565b610fec8484846111a9565b6001600160a01b0384166000908152600260205260409020546110109083906119ab565b6001600160a01b038086166000908152600260205260408082209390935590851681522054611040908390611973565b6001600160a01b038416600081815260026020526040902091909155611065906112e0565b156110cd576040516344a1f60160e11b81526001600160a01b03841690638943ec029061109a90879086908690600401611643565b600060405180830381600087803b1580156110b457600080fd5b505af11580156110c8573d6000803e3d6000fd5b505050505b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051611110919061195c565b60405180910390a37f3ba9136826ac751de05d770d8d34fa4440ada49a5fb0e9aa1678aece66dad976816040516111479190611675565b60405180910390a150505050565b6000611161600b611319565b600061116b610942565b90507f8030e83b04d87bef53480e26263266d6ca66863aa8506aca6f2559d18aa1cb678160405161119c919061195c565b60405180910390a1905090565b6111b4838383610c65565b6001600160a01b0383166111d8576111cb82611322565b6111d361134c565b610c65565b6001600160a01b0382166111ef576111cb83611322565b6111f883611322565b610c6582611322565b81546000906112125750600061041a565b82546000905b8082101561127c57600061122c838361135b565b90508486828154811061124f57634e487b7160e01b600052603260045260246000fd5b9060005260206000200154111561126857809150611276565b611273816001611973565b92505b50611218565b6000821180156112bf575083856112946001856119ab565b815481106112b257634e487b7160e01b600052603260045260246000fd5b9060005260206000200154145b156112d8576112cf6001836119ab565b9250505061041a565b50905061041a565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610999575050151592915050565b80546001019055565b6001600160a01b0381166000908152600860205260409020610abb90611347836107bd565b61137d565b61135960096113476104bc565b565b600061136a600284841861198b565b61137690848416611973565b9392505050565b6000611387610942565b905080611393846113c7565b1015610c65578254600180820185556000858152602080822090930193909355938401805494850181558252902090910155565b80546000906113d8575060006107d7565b815482906113e8906001906119ab565b8154811061140657634e487b7160e01b600052603260045260246000fd5b906000526020600020015490506107d7565b80356001600160a01b03811681146107d757600080fd5b600060208284031215611440578081fd5b61137682611418565b6000806040838503121561145b578081fd5b61146483611418565b915061147260208401611418565b90509250929050565b60008060006060848603121561148f578081fd5b61149884611418565b92506114a660208501611418565b9150604084013590509250925092565b600080604083850312156114c8578182fd5b6114d183611418565b946020939093013593505050565b600080600080606085870312156114f4578081fd5b6114fd85611418565b935060208501359250604085013567ffffffffffffffff80821115611520578283fd5b818701915087601f830112611533578283fd5b813581811115611541578384fd5b886020828501011115611552578384fd5b95989497505060200194505050565b600060208284031215611572578081fd5b81518015158114611376578182fd5b600060208284031215611592578081fd5b5035919050565b6000602082840312156115aa578081fd5b5051919050565b60008151808452815b818110156115d6576020818501810151868301820152016115ba565b818111156115e75782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b600060018060a01b03851682528360208301526060604083015261066260608301846115b1565b901515815260200190565b60006020825261137660208301846115b1565b60208082526017908201527f455243323233536e617073686f743a2069642069732030000000000000000000604082015260600190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b60208082526024908201527f4552433232333a207472616e7366657220746f20746865207a65726f206164646040820152637265737360e01b606082015260800190565b6020808252601e908201527f455243323233536e617073686f743a206e6f6e6578697374656e742069640000604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526026908201527f4552433232333a207472616e736665722066726f6d20746865207a65726f206160408201526564647265737360d01b606082015260800190565b60208082526032908201527f4f6e6c7920726576656e756520636f6e747261637420697320616c6c6f77656460408201527120746f2063616c6c20736e617073686f747360701b606082015260800190565b60208082526025908201527f4f6e6c7920626c61636b6c697374656420746f6b656e732063616e20626520626040820152641d5c9b995960da1b606082015260800190565b60208082526022908201527f4552433232333a206275726e2066726f6d20746865207a65726f206164647265604082015261737360f01b606082015260800190565b60208082526025908201527f4552433232333a20617070726f76652066726f6d20746865207a65726f206164604082015264647265737360d81b606082015260800190565b60208082526023908201527f4552433232333a20617070726f766520746f20746865207a65726f206164647260408201526265737360e81b606082015260800190565b90815260200190565b60ff91909116815260200190565b60008219821115611986576119866119fd565b500190565b6000826119a657634e487b7160e01b81526012600452602481fd5b500490565b6000828210156119bd576119bd6119fd565b500390565b6002810460018216806119d657607f821691505b602082108114156119f757634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fdfea2646970667358221220a7d5cc9322305ff2ee056398fcd6d0dc5bf7b2cd214a66c1f2ae4be8f884fab864736f6c63430008000033

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106101a95760003560e01c806379cc6790116100f9578063a457c2d711610097578063b3b2216311610071578063b3b2216314610336578063be45fd621461033e578063dd62ed3e14610351578063f2fde38b14610364576101a9565b8063a457c2d714610308578063a9059cbb1461031b578063b2bdfa7b1461032e576101a9565b8063879a8540116100d3578063879a8540146102dd5780638da5cb5b146102e557806395d89b41146102ed578063981b24d0146102f5576101a9565b806379cc6790146102ad57806383b76b1f146102c057806384900b04146102d5576101a9565b806339509351116101665780635a3b7e42116101405780635a3b7e42146102775780635d799f871461027f57806370a0823114610292578063715018a6146102a5576101a9565b8063395093511461023e578063498a6de7146102515780634ee2cd7e14610264576101a9565b806306fdde03146101ae578063095ea7b3146101cc57806312f26140146101ec57806318160ddd1461020157806323b872dd14610216578063313ce56714610229575b600080fd5b6101b6610377565b6040516101c39190611675565b60405180910390f35b6101df6101da3660046114b6565b610409565b6040516101c3919061166a565b6101ff6101fa36600461142f565b610420565b005b6102096104bc565b6040516101c3919061195c565b6101df61022436600461147b565b6104c2565b610231610596565b6040516101c39190611965565b6101df61024c3660046114b6565b61059f565b6101ff61025f36600461142f565b6105d6565b6102096102723660046114b6565b610622565b6101b661066b565b6101ff61028d366004611449565b61068b565b6102096102a036600461142f565b6107bd565b6101ff6107dc565b6101ff6102bb3660046114b6565b610850565b6102c8610924565b6040516101c391906115fc565b6102c8610933565b610209610942565b6102c8610953565b6101b6610962565b610209610303366004611581565b610971565b6101df6103163660046114b6565b6109a1565b6101df6103293660046114b6565b6109d8565b6102c8610a7a565b6101ff610a89565b6101df61034c3660046114df565b610abe565b61020961035f366004611449565b610b8f565b6101ff61037236600461142f565b610bba565b606060058054610386906119c2565b80601f01602080910402602001604051908101604052809291908181526020018280546103b2906119c2565b80156103ff5780601f106103d4576101008083540402835291602001916103ff565b820191906000526020600020905b8154815290600101906020018083116103e257829003601f168201915b5050505050905090565b6000610416338484610c6e565b5060015b92915050565b6000546001600160a01b031633146104535760405162461bcd60e51b815260040161044a90611780565b60405180910390fd5b6001546040517f1465a382917ea64603bfcdbf38f9dc1df9edcc414980b0b670da47f990c572a791610492916001600160a01b03909116908490611610565b60405180910390a1600180546001600160a01b0319166001600160a01b0392909216919091179055565b60045490565b6001546040516360ec778160e11b81526000916001600160a01b03169063c1d8ef02906104f59087908790600401611610565b60206040518083038186803b15801561050d57600080fd5b505afa158015610521573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105459190611561565b50610551848484610d22565b6001600160a01b03841660009081526003602090815260408083203380855292529091205461058c9186916105879086906119ab565b610c6e565b5060019392505050565b60075460ff1690565b3360008181526003602090815260408083206001600160a01b03871684529091528120549091610416918590610587908690611973565b6000546001600160a01b031633146106005760405162461bcd60e51b815260040161044a90611780565b600c80546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038216600090815260086020526040812081908190610649908590610e1f565b91509150816106605761065b856107bd565b610662565b805b95945050505050565b60408051808201909152600681526565726332323360d01b602082015290565b6000546001600160a01b031633146106b55760405162461bcd60e51b815260040161044a90611780565b6040516370a0823160e01b81526000906001600160a01b038416906370a08231906106e49030906004016115fc565b60206040518083038186803b1580156106fc57600080fd5b505afa158015610710573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107349190611599565b60405163a9059cbb60e01b81529091506001600160a01b0384169063a9059cbb90610765908590859060040161162a565b602060405180830381600087803b15801561077f57600080fd5b505af1158015610793573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b79190611561565b50505050565b6001600160a01b0381166000908152600260205260409020545b919050565b6000546001600160a01b031633146108065760405162461bcd60e51b815260040161044a90611780565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000546001600160a01b0316331461087a5760405162461bcd60e51b815260040161044a90611780565b60015460405163fe575a8760e01b81526001600160a01b039091169063fe575a87906108aa9085906004016115fc565b60206040518083038186803b1580156108c257600080fd5b505afa1580156108d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108fa9190611561565b6109165760405162461bcd60e51b815260040161044a9061184d565b6109208282610ecb565b5050565b600c546001600160a01b031681565b6001546001600160a01b031681565b600061094e600b610c6a565b905090565b6000546001600160a01b031690565b606060068054610386906119c2565b6000806000610981846009610e1f565b9150915081610997576109926104bc565b610999565b805b949350505050565b3360008181526003602090815260408083206001600160a01b038716845290915281205490916104169185906105879086906119ab565b6001546040516360ec778160e11b81526000916001600160a01b03169063c1d8ef0290610a0b9033908790600401611610565b60206040518083038186803b158015610a2357600080fd5b505afa158015610a37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a5b9190611561565b5060408051600081526020810190915261041690339085908590610f95565b6000546001600160a01b031681565b600c546001600160a01b03163314610ab35760405162461bcd60e51b815260040161044a906117fb565b610abb611155565b50565b6001546040516360ec778160e11b81526000916001600160a01b03169063c1d8ef0290610af19033908990600401611610565b60206040518083038186803b158015610b0957600080fd5b505afa158015610b1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b419190611561565b50610b8433868686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610f9592505050565b506001949350505050565b6001600160a01b03918216600090815260036020908152604080832093909416825291909152205490565b6000546001600160a01b03163314610be45760405162461bcd60e51b815260040161044a90611780565b6001600160a01b038116610c0a5760405162461bcd60e51b815260040161044a906116bf565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b505050565b5490565b6001600160a01b038316610c945760405162461bcd60e51b815260040161044a906118d4565b6001600160a01b038216610cba5760405162461bcd60e51b815260040161044a90611919565b6001600160a01b0380841660008181526003602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610d1590859061195c565b60405180910390a3505050565b6001600160a01b038316610d485760405162461bcd60e51b815260040161044a906117b5565b6001600160a01b038216610d6e5760405162461bcd60e51b815260040161044a90611705565b610d798383836111a9565b6001600160a01b038316600090815260026020526040902054610d9d9082906119ab565b6001600160a01b038085166000908152600260205260408082209390935590841681522054610dcd908290611973565b6001600160a01b0380841660008181526002602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610d1590859061195c565b60008060008411610e425760405162461bcd60e51b815260040161044a90611688565b610e4a610942565b841115610e695760405162461bcd60e51b815260040161044a90611749565b6000610e758486611201565b8454909150811415610e8e576000809250925050610ec4565b6001846001018281548110610eb357634e487b7160e01b600052603260045260246000fd5b906000526020600020015492509250505b9250929050565b6001600160a01b038216610ef15760405162461bcd60e51b815260040161044a90611892565b610efd826000836111a9565b6001600160a01b038216600090815260026020526040902054610f219082906119ab565b6001600160a01b038316600090815260026020526040902055600454610f489082906119ab565b6004556040516000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610f8990859061195c565b60405180910390a35050565b6001600160a01b038416610fbb5760405162461bcd60e51b815260040161044a906117b5565b6001600160a01b038316610fe15760405162461bcd60e51b815260040161044a90611705565b610fec8484846111a9565b6001600160a01b0384166000908152600260205260409020546110109083906119ab565b6001600160a01b038086166000908152600260205260408082209390935590851681522054611040908390611973565b6001600160a01b038416600081815260026020526040902091909155611065906112e0565b156110cd576040516344a1f60160e11b81526001600160a01b03841690638943ec029061109a90879086908690600401611643565b600060405180830381600087803b1580156110b457600080fd5b505af11580156110c8573d6000803e3d6000fd5b505050505b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051611110919061195c565b60405180910390a37f3ba9136826ac751de05d770d8d34fa4440ada49a5fb0e9aa1678aece66dad976816040516111479190611675565b60405180910390a150505050565b6000611161600b611319565b600061116b610942565b90507f8030e83b04d87bef53480e26263266d6ca66863aa8506aca6f2559d18aa1cb678160405161119c919061195c565b60405180910390a1905090565b6111b4838383610c65565b6001600160a01b0383166111d8576111cb82611322565b6111d361134c565b610c65565b6001600160a01b0382166111ef576111cb83611322565b6111f883611322565b610c6582611322565b81546000906112125750600061041a565b82546000905b8082101561127c57600061122c838361135b565b90508486828154811061124f57634e487b7160e01b600052603260045260246000fd5b9060005260206000200154111561126857809150611276565b611273816001611973565b92505b50611218565b6000821180156112bf575083856112946001856119ab565b815481106112b257634e487b7160e01b600052603260045260246000fd5b9060005260206000200154145b156112d8576112cf6001836119ab565b9250505061041a565b50905061041a565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610999575050151592915050565b80546001019055565b6001600160a01b0381166000908152600860205260409020610abb90611347836107bd565b61137d565b61135960096113476104bc565b565b600061136a600284841861198b565b61137690848416611973565b9392505050565b6000611387610942565b905080611393846113c7565b1015610c65578254600180820185556000858152602080822090930193909355938401805494850181558252902090910155565b80546000906113d8575060006107d7565b815482906113e8906001906119ab565b8154811061140657634e487b7160e01b600052603260045260246000fd5b906000526020600020015490506107d7565b80356001600160a01b03811681146107d757600080fd5b600060208284031215611440578081fd5b61137682611418565b6000806040838503121561145b578081fd5b61146483611418565b915061147260208401611418565b90509250929050565b60008060006060848603121561148f578081fd5b61149884611418565b92506114a660208501611418565b9150604084013590509250925092565b600080604083850312156114c8578182fd5b6114d183611418565b946020939093013593505050565b600080600080606085870312156114f4578081fd5b6114fd85611418565b935060208501359250604085013567ffffffffffffffff80821115611520578283fd5b818701915087601f830112611533578283fd5b813581811115611541578384fd5b886020828501011115611552578384fd5b95989497505060200194505050565b600060208284031215611572578081fd5b81518015158114611376578182fd5b600060208284031215611592578081fd5b5035919050565b6000602082840312156115aa578081fd5b5051919050565b60008151808452815b818110156115d6576020818501810151868301820152016115ba565b818111156115e75782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b600060018060a01b03851682528360208301526060604083015261066260608301846115b1565b901515815260200190565b60006020825261137660208301846115b1565b60208082526017908201527f455243323233536e617073686f743a2069642069732030000000000000000000604082015260600190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b60208082526024908201527f4552433232333a207472616e7366657220746f20746865207a65726f206164646040820152637265737360e01b606082015260800190565b6020808252601e908201527f455243323233536e617073686f743a206e6f6e6578697374656e742069640000604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526026908201527f4552433232333a207472616e736665722066726f6d20746865207a65726f206160408201526564647265737360d01b606082015260800190565b60208082526032908201527f4f6e6c7920726576656e756520636f6e747261637420697320616c6c6f77656460408201527120746f2063616c6c20736e617073686f747360701b606082015260800190565b60208082526025908201527f4f6e6c7920626c61636b6c697374656420746f6b656e732063616e20626520626040820152641d5c9b995960da1b606082015260800190565b60208082526022908201527f4552433232333a206275726e2066726f6d20746865207a65726f206164647265604082015261737360f01b606082015260800190565b60208082526025908201527f4552433232333a20617070726f76652066726f6d20746865207a65726f206164604082015264647265737360d81b606082015260800190565b60208082526023908201527f4552433232333a20617070726f766520746f20746865207a65726f206164647260408201526265737360e81b606082015260800190565b90815260200190565b60ff91909116815260200190565b60008219821115611986576119866119fd565b500190565b6000826119a657634e487b7160e01b81526012600452602481fd5b500490565b6000828210156119bd576119bd6119fd565b500390565b6002810460018216806119d657607f821691505b602082108114156119f757634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fdfea2646970667358221220a7d5cc9322305ff2ee056398fcd6d0dc5bf7b2cd214a66c1f2ae4be8f884fab864736f6c63430008000033