ETH Price: $2,519.68 (+0.18%)
Gas: 1.03 Gwei

Token

Spyral (Spyral)
 

Overview

Max Total Supply

500,000,000 Spyral

Holders

35

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Balance
2,294,997.708389195239706971 Spyral

Value
$0.00
0x6f55548c6676F62BcAF8E8d3bDa2378ae8271C50
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
Spyral

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, None license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2023-12-11
*/

///SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @dev Standard ERC20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
 */
interface IERC20Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @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.
     */
    error ERC20InsufficientBalance(
        address sender,
        uint256 balance,
        uint256 needed
    );

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC20InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC20InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     * @param allowance Amount of tokens a `spender` is allowed to operate with.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientAllowance(
        address spender,
        uint256 allowance,
        uint256 needed
    );

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC20InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC20InvalidSpender(address spender);
}

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

/**
 * @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.
 *
 * The initial owner is set to the address provided by the deployer. 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 is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(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 {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) 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 a `value` amount of tokens 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 value) external returns (bool);

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

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
    mapping(address => uint256) private _balances;

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

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

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

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

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual 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 default value returned by this function, unless
     * it's overridden.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual returns (uint8) {
        return 18;
    }

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

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

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `value`.
     */
    function transfer(address to, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, value);
        return true;
    }

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

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 value)
        public
        virtual
        returns (bool)
    {
        address owner = _msgSender();
        _approve(owner, spender, value);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `value`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `value`.
     */
    function transferFrom(
        address from,
        address to,
        uint256 value
    ) public virtual returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, value);
        _transfer(from, to, value);
        return true;
    }

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _transfer(
        address from,
        address to,
        uint256 value
    ) internal {
        if (from == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        if (to == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(from, to, value);
    }

    /**
     * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
     * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
     * this function.
     *
     * Emits a {Transfer} event.
     */
    function _update(
        address from,
        address to,
        uint256 value
    ) internal virtual {
        if (from == address(0)) {
            // Overflow check required: The rest of the code assumes that totalSupply never overflows
            _totalSupply += value;
        } else {
            uint256 fromBalance = _balances[from];
            if (fromBalance < value) {
                revert ERC20InsufficientBalance(from, fromBalance, value);
            }
            unchecked {
                // Overflow not possible: value <= fromBalance <= totalSupply.
                _balances[from] = fromBalance - value;
            }
        }

        if (to == address(0)) {
            unchecked {
                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                _totalSupply -= value;
            }
        } else {
            unchecked {
                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                _balances[to] += value;
            }
        }

        emit Transfer(from, to, value);
    }

    /**
     * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
     * Relies on the `_update` mechanism
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _mint(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(address(0), account, value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
     * Relies on the `_update` mechanism.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead
     */
    function _burn(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        _update(account, address(0), value);
    }

    /**
     * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
     *
     * This 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.
     *
     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
     */
    function _approve(
        address owner,
        address spender,
        uint256 value
    ) internal {
        _approve(owner, spender, value, true);
    }

    /**
     * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
     *
     * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
     * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
     * `Approval` event during `transferFrom` operations.
     *
     * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
     * true using the following override:
     * ```
     * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
     *     super._approve(owner, spender, value, true);
     * }
     * ```
     *
     * Requirements are the same as {_approve}.
     */
    function _approve(
        address owner,
        address spender,
        uint256 value,
        bool emitEvent
    ) internal virtual {
        if (owner == address(0)) {
            revert ERC20InvalidApprover(address(0));
        }
        if (spender == address(0)) {
            revert ERC20InvalidSpender(address(0));
        }
        _allowances[owner][spender] = value;
        if (emitEvent) {
            emit Approval(owner, spender, value);
        }
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `value`.
     *
     * Does not update the allowance value in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Does not emit an {Approval} event.
     */
    function _spendAllowance(
        address owner,
        address spender,
        uint256 value
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            if (currentAllowance < value) {
                revert ERC20InsufficientAllowance(
                    spender,
                    currentAllowance,
                    value
                );
            }
            unchecked {
                _approve(owner, spender, currentAllowance - value, false);
            }
        }
    }
}

// uniswap v2 factory iterface
interface IUniswapV2Factory {
    function createPair(address tokenA, address tokenB)
        external
        returns (address pair);

    function getPair(address tokenA, address tokenB)
        external
        view
        returns (address pair);
}

/// uniswap v2 router interface
interface IUniswapV2Router02 {
    function factory() external pure returns (address);

    function WETH() external pure returns (address);

    function getAmountsOut(uint256 amountIn, address[] calldata path)
        external
        view
        returns (uint256[] memory amounts);

    function getAmountsIn(uint256 amountOut, address[] calldata path)
        external
        view
        returns (uint256[] memory amounts);

    function addLiquidityETH(
        address token,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    )
        external
        payable
        returns (
            uint256 amountToken,
            uint256 amountETH,
            uint256 liquidity
        );

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external;

    function swapExactETHForTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amounts);

    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable;

    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external;
}

/// iterable mapping

library IterableMapping {
    // Iterable mapping from address to uint;
    struct Map {
        address[] keys;
        mapping(address => uint256) values;
        mapping(address => uint256) indexOf;
        mapping(address => bool) inserted;
    }

    function get(Map storage map, address key) internal view returns (uint256) {
        return map.values[key];
    }

    function getIndexOfKey(Map storage map, address key)
        internal
        view
        returns (int256)
    {
        if (!map.inserted[key]) {
            return -1;
        }
        return int256(map.indexOf[key]);
    }

    function getKeyAtIndex(Map storage map, uint256 index)
        internal
        view
        returns (address)
    {
        return map.keys[index];
    }

    function size(Map storage map) internal view returns (uint256) {
        return map.keys.length;
    }

    function set(
        Map storage map,
        address key,
        uint256 val
    ) internal {
        if (map.inserted[key]) {
            map.values[key] = val;
        } else {
            map.inserted[key] = true;
            map.values[key] = val;
            map.indexOf[key] = map.keys.length;
            map.keys.push(key);
        }
    }

    function remove(Map storage map, address key) internal {
        if (!map.inserted[key]) {
            return;
        }

        delete map.inserted[key];
        delete map.values[key];

        uint256 index = map.indexOf[key];
        uint256 lastIndex = map.keys.length - 1;
        address lastKey = map.keys[lastIndex];

        map.indexOf[lastKey] = index;
        delete map.indexOf[key];

        map.keys[index] = lastKey;
        map.keys.pop();
    }
}

/// @title Dividend-Paying Token Optional Interface
/// @author Roger Wu (https://github.com/roger-wu)
/// @dev OPTIONAL functions for a dividend-paying token contract.
interface DividendPayingTokenOptionalInterface {
    /// @notice View the amount of dividend in wei that an address can withdraw.
    /// @param _owner The address of a token holder.
    /// @return The amount of dividend in wei that `_owner` can withdraw.
    function withdrawableDividendOf(address _owner)
        external
        view
        returns (uint256);

    /// @notice View the amount of dividend in wei that an address has withdrawn.
    /// @param _owner The address of a token holder.
    /// @return The amount of dividend in wei that `_owner` has withdrawn.
    function withdrawnDividendOf(address _owner)
        external
        view
        returns (uint256);

    /// @notice View the amount of dividend in wei that an address has earned in total.
    /// @dev accumulativeDividendOf(_owner) = withdrawableDividendOf(_owner) + withdrawnDividendOf(_owner)
    /// @param _owner The address of a token holder.
    /// @return The amount of dividend in wei that `_owner` has earned in total.
    function accumulativeDividendOf(address _owner)
        external
        view
        returns (uint256);
}

/// @title Dividend-Paying Token Interface
/// @author Roger Wu (https://github.com/roger-wu)
/// @dev An interface for a dividend-paying token contract.
interface DividendPayingTokenInterface {
    /// @notice View the amount of dividend in wei that an address can withdraw.
    /// @param _owner The address of a token holder.
    /// @return The amount of dividend in wei that `_owner` can withdraw.
    function dividendOf(address _owner) external view returns (uint256);

    /// @notice Distributes ether to token holders as dividends.
    /// @dev SHOULD distribute the paid ether to token holders as dividends.
    ///  SHOULD NOT directly transfer ether to token holders in this function.
    ///  MUST emit a `DividendsDistributed` event when the amount of distributed ether is greater than 0.
    function distributeDividends() external payable;

    /// @notice Withdraws the ether distributed to the sender.
    /// @dev SHOULD transfer `dividendOf(msg.sender)` wei to `msg.sender`, and `dividendOf(msg.sender)` SHOULD be 0 after the transfer.
    ///  MUST emit a `DividendWithdrawn` event if the amount of ether transferred is greater than 0.
    function withdrawDividend() external;

    /// @dev This event MUST emit when ether is distributed to token holders.
    /// @param from The address which sends ether to this contract.
    /// @param weiAmount The amount of distributed ether in wei.
    event DividendsDistributed(address indexed from, uint256 weiAmount);

    /// @dev This event MUST emit when an address withdraws their dividend.
    /// @param to The address which withdraws ether from this contract.
    /// @param weiAmount The amount of withdrawn ether in wei.
    event DividendWithdrawn(address indexed to, uint256 weiAmount);
}

/**
 * @title SafeMathInt
 * @dev Math operations for int256 with overflow safety checks.
 */
library SafeMathInt {
    int256 private constant MIN_INT256 = int256(1) << 255;
    int256 private constant MAX_INT256 = ~(int256(1) << 255);

    /**
     * @dev Multiplies two int256 variables and fails on overflow.
     */
    function mul(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a * b;

        // Detect overflow when multiplying MIN_INT256 with -1
        require(c != MIN_INT256 || (a & MIN_INT256) != (b & MIN_INT256));
        require((b == 0) || (c / b == a));
        return c;
    }

    /**
     * @dev Division of two int256 variables and fails on overflow.
     */
    function div(int256 a, int256 b) internal pure returns (int256) {
        // Prevent overflow when dividing MIN_INT256 by -1
        require(b != -1 || a != MIN_INT256);

        // Solidity already throws when dividing by 0.
        return a / b;
    }

    /**
     * @dev Subtracts two int256 variables and fails on overflow.
     */
    function sub(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a - b;
        require((b >= 0 && c <= a) || (b < 0 && c > a));
        return c;
    }

    /**
     * @dev Adds two int256 variables and fails on overflow.
     */
    function add(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a + b;
        require((b >= 0 && c >= a) || (b < 0 && c < a));
        return c;
    }

    /**
     * @dev Converts to absolute value, and fails on overflow.
     */
    function abs(int256 a) internal pure returns (int256) {
        require(a != MIN_INT256);
        return a < 0 ? -a : a;
    }

    function toUint256Safe(int256 a) internal pure returns (uint256) {
        require(a >= 0);
        return uint256(a);
    }
}

/**
 * @title SafeMathUint
 * @dev Math operations with safety checks that revert on error
 */
library SafeMathUint {
    function toInt256Safe(uint256 a) internal pure returns (int256) {
        int256 b = int256(a);
        require(b >= 0);
        return b;
    }
}

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b)
        internal
        pure
        returns (bool, uint256)
    {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b)
        internal
        pure
        returns (bool, uint256)
    {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b)
        internal
        pure
        returns (bool, uint256)
    {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b)
        internal
        pure
        returns (bool, uint256)
    {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b)
        internal
        pure
        returns (bool, uint256)
    {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

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

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

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

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

/// @title Dividend-Paying Token
/// @author Roger Wu (https://github.com/roger-wu)
/// @dev modified to make more gas efficient
contract DividendPayingToken is
    Ownable,
    DividendPayingTokenInterface,
    DividendPayingTokenOptionalInterface
{
    using SafeMath for uint256;
    using SafeMathUint for uint256;
    using SafeMathInt for int256;

    // With `magnitude`, we can properly distribute dividends even if the amount of received ether is small.
    // For more discussion about choosing the value of `magnitude`,
    //  see https://github.com/ethereum/EIPs/issues/1726#issuecomment-472352728
    uint256 internal constant magnitude = 2**128;

    uint256 internal magnifiedDividendPerShare;

    // About dividendCorrection:
    // If the token balance of a `_user` is never changed, the dividend of `_user` can be computed with:
    //   `dividendOf(_user) = dividendPerShare * balanceOf(_user)`.
    // When `balanceOf(_user)` is changed (via minting/burning/transferring tokens),
    //   `dividendOf(_user)` should not be changed,
    //   but the computed value of `dividendPerShare * balanceOf(_user)` is changed.
    // To keep the `dividendOf(_user)` unchanged, we add a correction term:
    //   `dividendOf(_user) = dividendPerShare * balanceOf(_user) + dividendCorrectionOf(_user)`,
    //   where `dividendCorrectionOf(_user)` is updated whenever `balanceOf(_user)` is changed:
    //   `dividendCorrectionOf(_user) = dividendPerShare * (old balanceOf(_user)) - (new balanceOf(_user))`.
    // So now `dividendOf(_user)` returns the same value before and after `balanceOf(_user)` is changed.
    mapping(address => int256) internal magnifiedDividendCorrections;
    mapping(address => uint256) internal withdrawnDividends;
    mapping(address => uint256) internal balanceOf;
    uint256 private totalSupply;

    uint256 public totalDividendsDistributed;

    constructor() Ownable(msg.sender) {}

    /// @dev Distributes dividends whenever ether is paid to this contract.
    receive() external payable {
        distributeDividends();
    }

    /// @notice Distributes ether to token holders as dividends.
    /// @dev It reverts if the total supply of tokens is 0.
    /// It emits the `DividendsDistributed` event if the amount of received ether is greater than 0.
    /// About undistributed ether:
    ///   In each distribution, there is a small amount of ether not distributed,
    ///     the magnified amount of which is
    ///     `(msg.value * magnitude) % totalSupply()`.
    ///   With a well-chosen `magnitude`, the amount of undistributed ether
    ///     (de-magnified) in a distribution can be less than 1 wei.
    ///   We can actually keep track of the undistributed ether in a distribution
    ///     and try to distribute it in the next distribution,
    ///     but keeping track of such data on-chain costs much more than
    ///     the saved ether, so we don't do that.
    function distributeDividends() public payable override {
        require(totalSupply > 0);

        if (msg.value > 0) {
            magnifiedDividendPerShare = magnifiedDividendPerShare.add(
                (msg.value).mul(magnitude) / totalSupply
            );
            emit DividendsDistributed(msg.sender, msg.value);

            totalDividendsDistributed = totalDividendsDistributed.add(
                msg.value
            );
        }
    }

    /// @notice Withdraws the ether distributed to the sender.
    /// @dev It emits a `DividendWithdrawn` event if the amount of withdrawn ether is greater than 0.
    function withdrawDividend() public virtual override {
        _withdrawDividendOfUser(payable(msg.sender));
    }

    /// @notice Withdraws the ether distributed to the sender.
    /// @dev It emits a `DividendWithdrawn` event if the amount of withdrawn ether is greater than 0.
    function _withdrawDividendOfUser(address payable user)
        internal
        returns (uint256)
    {
        uint256 _withdrawableDividend = withdrawableDividendOf(user);
        if (_withdrawableDividend > 0) {
            withdrawnDividends[user] = withdrawnDividends[user].add(
                _withdrawableDividend
            );
            emit DividendWithdrawn(user, _withdrawableDividend);
            (bool success, ) = user.call{
                value: _withdrawableDividend,
                gas: 3000
            }("");

            if (!success) {
                withdrawnDividends[user] = withdrawnDividends[user].sub(
                    _withdrawableDividend
                );
                return 0;
            }

            return _withdrawableDividend;
        }

        return 0;
    }

    /// @notice View the amount of dividend in wei that an address can withdraw.
    /// @param _owner The address of a token holder.
    /// @return The amount of dividend in wei that `_owner` can withdraw.
    function dividendOf(address _owner) public view override returns (uint256) {
        return withdrawableDividendOf(_owner);
    }

    /// @notice View the amount of dividend in wei that an address can withdraw.
    /// @param _owner The address of a token holder.
    /// @return The amount of dividend in wei that `_owner` can withdraw.
    function withdrawableDividendOf(address _owner)
        public
        view
        override
        returns (uint256)
    {
        return accumulativeDividendOf(_owner).sub(withdrawnDividends[_owner]);
    }

    /// @notice View the amount of dividend in wei that an address has withdrawn.
    /// @param _owner The address of a token holder.
    /// @return The amount of dividend in wei that `_owner` has withdrawn.
    function withdrawnDividendOf(address _owner)
        public
        view
        override
        returns (uint256)
    {
        return withdrawnDividends[_owner];
    }

    /// @notice View the amount of dividend in wei that an address has earned in total.
    /// @dev accumulativeDividendOf(_owner) = withdrawableDividendOf(_owner) + withdrawnDividendOf(_owner)
    /// = (magnifiedDividendPerShare * balanceOf(_owner) + magnifiedDividendCorrections[_owner]) / magnitude
    /// @param _owner The address of a token holder.
    /// @return The amount of dividend in wei that `_owner` has earned in total.
    function accumulativeDividendOf(address _owner)
        public
        view
        override
        returns (uint256)
    {
        return
            magnifiedDividendPerShare
                .mul(balanceOf[_owner])
                .toInt256Safe()
                .add(magnifiedDividendCorrections[_owner])
                .toUint256Safe() / magnitude;
    }

    /// @dev set the user shares as per there balance, once they have bought more than minimum
    /// required
    /// @param account: user address
    /// @param newBalance: user balance
    function _setBalance(address account, uint256 newBalance) internal {
        uint256 currentBalance = balanceOf[account];

        if (newBalance > currentBalance) {
            uint256 amount = newBalance.sub(currentBalance);
            balanceOf[account] += amount;
            totalSupply += amount;
            magnifiedDividendCorrections[
                account
            ] = magnifiedDividendCorrections[account].sub(
                (magnifiedDividendPerShare.mul(amount)).toInt256Safe()
            );
        } else if (newBalance < currentBalance) {
            uint256 amount = currentBalance.sub(newBalance);
            balanceOf[account] -= amount;
            totalSupply -= amount;
            magnifiedDividendCorrections[
                account
            ] = magnifiedDividendCorrections[account].add(
                (magnifiedDividendPerShare.mul(amount)).toInt256Safe()
            );
        }
    }
}

contract Spyral is ERC20, Ownable {
    ///Custom errors
    error TryAfterNextClaimTime();
    error TradingIsAlreadyLive();
    error CannotClaimNativeToken();
    error TradingIsNotActiveYet();
    error CannotModifyMainPair();
    error OnlyMarketingWalletCanClaim();
    error EthClaimFailed();
    error MAX_FEE_LIMIT_EXCEEDS();
    error NoRewardsAvailableYet();

    /// uniswap v2 router
    IUniswapV2Router02 public uniswapV2Router;
    /// uniswap v2 pair address
    address public uniswapV2Pair;
    /// swapping is active
    bool private swapping;
    /// dividend tracker
    SpyralDividendTracker public dividendTracker;

    /// global burn wallet
    address private constant deadWallet = address(0xdead);
    /// swap threshold at which collected tax is swapped for ether
    uint256 public swapTokensAtAmount = 1e4 * 1e18;
    /// marketing wallet address
    address public marketingWallet = 0xf3cfd872c8E5F2A7Fd615b7E38Ef919D557B396b;

    /// fees variables
    struct BuyFee {
        uint256 ethReward;
        uint256 marketing;
    }

    struct SellFee {
        uint256 ethReward;
        uint256 marketing;
    }

    BuyFee public buyFee;
    SellFee public sellFee;

    // exlcude from fees and max transaction amount
    mapping(address => bool) private _isExcludedFromFees;

    /// events
    event ExcludeFromFees(address indexed account, bool isExcluded);
    event SellFeesUpdated(
        uint256 indexed rewardFee,
        uint256 indexed marketingFee
    );
    event BuyFeesUpdated(uint256 indexed rewardFee, uint256 marketingFee);
    event SetAutomatedMarketMakerPair(address indexed pair, bool indexed value);
    event MarketingWalletUpdated(
        address indexed newMarketingWallet,
        address indexed oldMarketingWallet
    );
    event SwapAndLiquify(
        uint256 tokensSwapped,
        uint256 ethReceived,
        uint256 ethForDividends
    );

    constructor() ERC20("Spyral", "Spyral") Ownable(msg.sender) {
        dividendTracker = new SpyralDividendTracker();

        IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(
            0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D /// uniswap v2 router
        );
        // Create a uniswap pair for this  token
        address _uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory())
            .createPair(address(this), _uniswapV2Router.WETH());

        /// intializes the router and pair values
        uniswapV2Router = _uniswapV2Router;
        uniswapV2Pair = _uniswapV2Pair;

        /// initializes the fees values for buy / sell
        buyFee.ethReward = 2;
        buyFee.marketing = 28;

        sellFee.ethReward = 2;
        sellFee.marketing = 28;

        // exclude from receiving dividends
        dividendTracker.excludeFromDividends(address(dividendTracker));
        dividendTracker.excludeFromDividends(uniswapV2Pair);
        dividendTracker.excludeFromDividends(address(this));
        dividendTracker.excludeFromDividends(owner());
        dividendTracker.excludeFromDividends(deadWallet);
        dividendTracker.excludeFromDividends(address(_uniswapV2Router));

        // exclude from paying fees or having max transaction amount
        _isExcludedFromFees[owner()] = true;
        _isExcludedFromFees[address(this)] = true;
        /// mint the max supply to owner address upon deployment
        _mint(owner(), 5e8 * 1e18);
    }

    receive() external payable {}

    /// @dev set marketing wallet
    /// @param wallet: new marketing wallet
    function setMarketingWallet(address wallet) external onlyOwner {
        address oldWallet = marketingWallet;
        marketingWallet = wallet;
        emit MarketingWalletUpdated(wallet, oldWallet);
    }

    /// @dev claim eth rewards
    /// @notice users have to wait as per claimTime b/w two consequitve claims
    function claimEthReward() external {
        bool claiming = true;
        (, , , uint256 claimable, , , uint256 nextClaimTime, ) = dividendTracker
            .getAccount(msg.sender);
        if (claimable == 0) {
            revert NoRewardsAvailableYet();
        }
        if (block.timestamp < nextClaimTime) {
            revert TryAfterNextClaimTime();
        }
        dividendTracker.processAccount(payable(msg.sender), false);
        claiming = false;
    }

    /// @dev update duration b/w two consequtive claims
    /// @param claimWait: time in seconds (must be within 3600 and 86400)
    function updateClaimWait(uint256 claimWait) external onlyOwner {
        dividendTracker.updateClaimWait(claimWait);
    }

    /// @notice returns how many eth has been contributed to eth rewards so far
    function getTotalDividendsDistributed() external view returns (uint256) {
        return dividendTracker.totalDividendsDistributed();
    }

    /// @dev set fees for buy
    /// max fees can be 30% combined for reward and marketing buy tax
    function setBuyFees(uint256 reward, uint256 marketing) external onlyOwner {
        if (reward + marketing > 30) {
            revert MAX_FEE_LIMIT_EXCEEDS();
        }
        buyFee.ethReward = reward;
        buyFee.marketing = marketing;
        emit BuyFeesUpdated(reward, marketing);
    }

    /// @dev set sell fees
    /// max fees can be 30% combined for reward and marketing sell tax
    function setSellFees(uint256 reward, uint256 marketing) external onlyOwner {
        if (reward + marketing > 30) {
            revert MAX_FEE_LIMIT_EXCEEDS();
        }
        sellFee.ethReward = reward;
        sellFee.marketing = marketing;
        emit SellFeesUpdated(reward, marketing);
    }

    /// @notice return user info, how much he can claim
    /// total rewards alloted to him in lifetime(including unclaimed),
    /// last claim time,
    /// next claim time etc
    function getUserDividendsInfo(address account)
        external
        view
        returns (
            uint256 claimable,
            uint256 totalEthEarned,
            uint256 lastClaimTime,
            uint256 nextClaimTime
        )
    {
        (
            ,
            ,
            ,
            claimable,
            totalEthEarned,
            lastClaimTime,
            nextClaimTime,

        ) = dividendTracker.getAccount(account);
    }

    /// @notice return number of eligible reward holders
    function getNumberOfRewardHolders() external view returns (uint256) {
        return dividendTracker.getNumberOfTokenHolders();
    }

    /// @notice manage the transfer / fees of token
    /// override required by solidity
    function _update(
        address from,
        address to,
        uint256 amount
    ) internal override {
        if (amount == 0) {
            super._update(from, to, 0);
            return;
        }

        uint256 contractTokenBalance = balanceOf(address(this));

        bool canSwap = contractTokenBalance >= swapTokensAtAmount;

        if (
            canSwap &&
            !swapping &&
            from != uniswapV2Pair &&
            from != owner() &&
            to != owner()
        ) {
            swapping = true;

            swapAndLiquify(contractTokenBalance);

            swapping = false;
        }

        bool takeFee = !swapping;

        // if any account belongs to _isExcludedFromFee account then remove the fee
        // when liquidity is added for first 10 minutes tax is 30% on buy/sell
        // , for subsequent 10 minutes it's 15% on buy/sell
        // afterwards, it's 3% on buy/sell
        if (_isExcludedFromFees[from] || _isExcludedFromFees[to]) {
            takeFee = false;
        }

        if (takeFee) {
            uint256 fees = 0;
            
            /// if it's a buy
            if (from == uniswapV2Pair) {
                fees = (amount * (buyFee.marketing + buyFee.ethReward)) / 100;
            }
            /// if it's a sell
            if (to == uniswapV2Pair) {
                fees = (amount * (sellFee.marketing + sellFee.ethReward)) / 100;
            }

            amount = amount - fees;
            if (fees > 0) {
                super._update(from, address(this), fees);
            }
        }

        super._update(from, to, amount);

        try
            dividendTracker.setBalance(payable(from), balanceOf(from))
        {} catch {}
        try dividendTracker.setBalance(payable(to), balanceOf(to)) {} catch {}
    }

    /// @notice swap the input tokens for eth and send to
    /// marketing wallet as well as to dividend tracker
    function swapAndLiquify(uint256 tokens) private {
        uint256 initialBalance = address(this).balance;

        // swap tokens for ETH
        swapTokensForEth(tokens);

        // how much ETH did we just swap into?
        uint256 newBalance = address(this).balance - initialBalance;
        uint256 totalFees = buyFee.marketing +
            buyFee.ethReward +
            sellFee.marketing +
            sellFee.ethReward;
        if (totalFees > 0) {
            uint256 marketingPart = (newBalance *
                (buyFee.marketing + sellFee.marketing)) / totalFees;
            (bool sent, ) = payable(address(dividendTracker)).call{
                value: newBalance - marketingPart
            }("");
            (bool sent2, ) = payable(marketingWallet).call{
                value: address(this).balance
            }("");
            if (sent || sent2) {
                emit SwapAndLiquify(
                    tokens,
                    marketingPart,
                    newBalance - marketingPart
                );
            }
        } else {
             bool s;
            (s,) = payable(address(marketingWallet)).call{
                value: address(this).balance
            }("");
           
        }
    }

    /// @notice swap the tokens for eth
    function swapTokensForEth(uint256 tokenAmount) private {
        // generate the uniswap pair path of token -> weth
        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = uniswapV2Router.WETH();
        uint256 out = uniswapV2Router.getAmountsOut(tokenAmount, path)[1];
        if (allowance(address(this), address(uniswapV2Router)) < tokenAmount) {
            _approve(
                address(this),
                address(uniswapV2Router),
                type(uint256).max
            );
        }

        // make the swap
        uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
            tokenAmount,
            (out * (100 - 20)) / 100, // 20% slippage
            path,
            address(this),
            block.timestamp + 360
        );
    }
}

//// Spyral dividend tracker, manage eth rewards
////{ see: DividendPayingToken }
contract SpyralDividendTracker is DividendPayingToken {
    using SafeMath for uint256;
    using SafeMathInt for int256;
    using IterableMapping for IterableMapping.Map;

    error TimeLimitMustBeBetween1to24Hours();

    IterableMapping.Map private tokenHoldersMap;
    uint256 public lastProcessedIndex;

    mapping(address => bool) public excludedFromDividends;

    mapping(address => uint256) public lastClaimTimes;

    uint256 public claimWait;
    uint256 public immutable minimumTokenBalanceForDividends;

    event ExcludeFromDividends(address indexed account);
    event ClaimWaitUpdated(uint256 indexed newValue, uint256 indexed oldValue);

    event Claim(
        address indexed account,
        uint256 amount,
        bool indexed automatic
    );

    constructor() {
        claimWait = 12 hours; // cooldown b/w two consequtive claims for user
        minimumTokenBalanceForDividends = 100 * (10**18); //must hold 100+ tokens
    }

    function withdrawDividend() public pure override {
        require(false);
    }

    function excludeFromDividends(address account) external onlyOwner {
        require(!excludedFromDividends[account]);
        excludedFromDividends[account] = true;
        _setBalance(account, 0);
        tokenHoldersMap.remove(account);

        emit ExcludeFromDividends(account);
    }

    function updateClaimWait(uint256 newClaimWait) external onlyOwner {
        if (newClaimWait < 3600 || newClaimWait > 86400) {
            revert TimeLimitMustBeBetween1to24Hours();
        }

        emit ClaimWaitUpdated(newClaimWait, claimWait);
        claimWait = newClaimWait;
    }

    function getLastProcessedIndex() external view returns (uint256) {
        return lastProcessedIndex;
    }

    function getNumberOfTokenHolders() external view returns (uint256) {
        return tokenHoldersMap.keys.length;
    }

    function getAccount(address _account)
        public
        view
        returns (
            address account,
            int256 index,
            int256 iterationsUntilProcessed,
            uint256 withdrawableDividends,
            uint256 totalDividends,
            uint256 lastClaimTime,
            uint256 nextClaimTime,
            uint256 secondsUntilAutoClaimAvailable
        )
    {
        account = _account;

        index = tokenHoldersMap.getIndexOfKey(account);

        iterationsUntilProcessed = -1;

        if (index >= 0) {
            if (uint256(index) > lastProcessedIndex) {
                iterationsUntilProcessed = index.sub(
                    int256(lastProcessedIndex)
                );
            } else {
                uint256 processesUntilEndOfArray = tokenHoldersMap.keys.length >
                    lastProcessedIndex
                    ? tokenHoldersMap.keys.length.sub(lastProcessedIndex)
                    : 0;

                iterationsUntilProcessed = index.add(
                    int256(processesUntilEndOfArray)
                );
            }
        }

        withdrawableDividends = withdrawableDividendOf(account);
        totalDividends = accumulativeDividendOf(account);

        lastClaimTime = lastClaimTimes[account];

        nextClaimTime = lastClaimTime > 0 ? lastClaimTime.add(claimWait) : 0;

        secondsUntilAutoClaimAvailable = nextClaimTime > block.timestamp
            ? nextClaimTime.sub(block.timestamp)
            : 0;
    }

    function getAccountAtIndex(uint256 index)
        public
        view
        returns (
            address,
            int256,
            int256,
            uint256,
            uint256,
            uint256,
            uint256,
            uint256
        )
    {
        if (index >= tokenHoldersMap.size()) {
            return (
                0x0000000000000000000000000000000000000000,
                -1,
                -1,
                0,
                0,
                0,
                0,
                0
            );
        }

        address account = tokenHoldersMap.getKeyAtIndex(index);

        return getAccount(account);
    }

    function setBalance(address payable account, uint256 newBalance)
        external
        onlyOwner
    {
        if (excludedFromDividends[account]) {
            return;
        }

        if (newBalance >= minimumTokenBalanceForDividends) {
            _setBalance(account, newBalance);
            tokenHoldersMap.set(account, newBalance);
        } else {
            _setBalance(account, 0);
            tokenHoldersMap.remove(account);
        }
    }

    function processAccount(address payable account, bool automatic)
        public
        onlyOwner
        returns (bool)
    {
        uint256 amount = _withdrawDividendOfUser(account);

        if (amount > 0) {
            lastClaimTimes[account] = block.timestamp;
            emit Claim(account, amount, automatic);
            return true;
        }

        return false;
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CannotClaimNativeToken","type":"error"},{"inputs":[],"name":"CannotModifyMainPair","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[],"name":"EthClaimFailed","type":"error"},{"inputs":[],"name":"MAX_FEE_LIMIT_EXCEEDS","type":"error"},{"inputs":[],"name":"NoRewardsAvailableYet","type":"error"},{"inputs":[],"name":"OnlyMarketingWalletCanClaim","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":"TradingIsAlreadyLive","type":"error"},{"inputs":[],"name":"TradingIsNotActiveYet","type":"error"},{"inputs":[],"name":"TryAfterNextClaimTime","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"rewardFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"marketingFee","type":"uint256"}],"name":"BuyFeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"isExcluded","type":"bool"}],"name":"ExcludeFromFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newMarketingWallet","type":"address"},{"indexed":true,"internalType":"address","name":"oldMarketingWallet","type":"address"}],"name":"MarketingWalletUpdated","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":true,"internalType":"uint256","name":"rewardFee","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"marketingFee","type":"uint256"}],"name":"SellFeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pair","type":"address"},{"indexed":true,"internalType":"bool","name":"value","type":"bool"}],"name":"SetAutomatedMarketMakerPair","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokensSwapped","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ethReceived","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ethForDividends","type":"uint256"}],"name":"SwapAndLiquify","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"buyFee","outputs":[{"internalType":"uint256","name":"ethReward","type":"uint256"},{"internalType":"uint256","name":"marketing","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimEthReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dividendTracker","outputs":[{"internalType":"contract SpyralDividendTracker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNumberOfRewardHolders","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalDividendsDistributed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getUserDividendsInfo","outputs":[{"internalType":"uint256","name":"claimable","type":"uint256"},{"internalType":"uint256","name":"totalEthEarned","type":"uint256"},{"internalType":"uint256","name":"lastClaimTime","type":"uint256"},{"internalType":"uint256","name":"nextClaimTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketingWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sellFee","outputs":[{"internalType":"uint256","name":"ethReward","type":"uint256"},{"internalType":"uint256","name":"marketing","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"marketing","type":"uint256"}],"name":"setBuyFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"}],"name":"setMarketingWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"marketing","type":"uint256"}],"name":"setSellFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapTokensAtAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniswapV2Pair","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"uniswapV2Router","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"claimWait","type":"uint256"}],"name":"updateClaimWait","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

608060405269021e19e0c9bab2400000600955600a80546001600160a01b03191673f3cfd872c8e5f2a7fd615b7e38ef919d557b396b17905534801562000044575f80fd5b5060408051808201825260068082526514dc1e5c985b60d21b60208084018290528451808601909552918452908301523391600362000084838262001044565b50600462000093828262001044565b5050506001600160a01b038116620000c557604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b620000d08162000589565b50604051620000df9062000f9f565b604051809103905ff080158015620000f9573d5f803e3d5ffd5b5060085f6101000a8154816001600160a01b0302191690836001600160a01b031602179055505f737a250d5630b4cf539739df2c5dacb4c659f2488d90505f816001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000175573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200019b91906200110c565b6001600160a01b031663c9c6539630846001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001e7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200020d91906200110c565b6040516001600160e01b031960e085901b1681526001600160a01b039283166004820152911660248201526044016020604051808303815f875af115801562000258573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200027e91906200110c565b600680546001600160a01b038581166001600160a01b0319928316179092556007805484841692169190911790556002600b819055601c600c819055600d91909155600e5560085460405163031e79db60e41b81529116600482018190529192506331e79db0906024015f604051808303815f87803b15801562000300575f80fd5b505af115801562000313573d5f803e3d5ffd5b505060085460075460405163031e79db60e41b81526001600160a01b039182166004820152911692506331e79db091506024015f604051808303815f87803b1580156200035e575f80fd5b505af115801562000371573d5f803e3d5ffd5b505060085460405163031e79db60e41b81523060048201526001600160a01b0390911692506331e79db091506024015f604051808303815f87803b158015620003b8575f80fd5b505af1158015620003cb573d5f803e3d5ffd5b50506008546001600160a01b031691506331e79db09050620003f56005546001600160a01b031690565b6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024015f604051808303815f87803b15801562000434575f80fd5b505af115801562000447573d5f803e3d5ffd5b505060085460405163031e79db60e41b815261dead60048201526001600160a01b0390911692506331e79db091506024015f604051808303815f87803b15801562000490575f80fd5b505af1158015620004a3573d5f803e3d5ffd5b505060085460405163031e79db60e41b81526001600160a01b03868116600483015290911692506331e79db091506024015f604051808303815f87803b158015620004ec575f80fd5b505af1158015620004ff573d5f803e3d5ffd5b505050506001600f5f62000518620005da60201b60201c565b6001600160a01b0316815260208082019290925260409081015f908120805494151560ff19958616179055308152600f909252902080549091166001179055620005816200056e6005546001600160a01b031690565b6b019d971e4fe8401e74000000620005e9565b505062001330565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6005546001600160a01b031690565b6001600160a01b038216620006145760405163ec442f0560e01b81525f6004820152602401620000bc565b620006215f838362000625565b5050565b805f036200063f576200063a83835f62000925565b505050565b305f90815260208190526040902054600954811080159081906200066d5750600754600160a01b900460ff16155b80156200068857506007546001600160a01b03868116911614155b8015620006a357506005546001600160a01b03868116911614155b8015620006be57506005546001600160a01b03858116911614155b15620006f0576007805460ff60a01b1916600160a01b179055620006e28262000a54565b6007805460ff60a01b191690555b6007546001600160a01b0386165f908152600f602052604090205460ff600160a01b9092048216159116806200073d57506001600160a01b0385165f908152600f602052604090205460ff165b156200074657505f5b8015620007ff576007545f906001600160a01b03908116908816036200079557600b54600c546064916200077a916200114f565b62000786908762001165565b6200079291906200117f565b90505b6007546001600160a01b0390811690871603620007db57600d54600e54606491620007c0916200114f565b620007cc908762001165565b620007d891906200117f565b90505b620007e781866200119f565b94508015620007fd57620007fd87308362000925565b505b6200080c86868662000925565b6008546001600160a01b031663e30443bc876200083d816001600160a01b03165f9081526020819052604090205490565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044015f604051808303815f87803b15801562000881575f80fd5b505af192505050801562000893575060015b506008546001600160a01b031663e30443bc86620008c5816001600160a01b03165f9081526020819052604090205490565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044015f604051808303815f87803b15801562000909575f80fd5b505af19250505080156200091b575060015b505b505050505050565b6001600160a01b03831662000953578060025f8282546200094791906200114f565b90915550620009c59050565b6001600160a01b0383165f9081526020819052604090205481811015620009a75760405163391434e360e21b81526001600160a01b03851660048201526024810182905260448101839052606401620000bc565b6001600160a01b0384165f9081526020819052604090209082900390555b6001600160a01b038216620009e35760028054829003905562000a01565b6001600160a01b0382165f9081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405162000a4791815260200190565b60405180910390a3505050565b4762000a608262000c55565b5f62000a6d82476200119f565b600d54600e54600b54600c549394505f9362000a8a91906200114f565b62000a9691906200114f565b62000aa291906200114f565b9050801562000bf957600e54600c545f91839162000ac191906200114f565b62000acd908562001165565b62000ad991906200117f565b6008549091505f906001600160a01b031662000af683866200119f565b6040515f81818185875af1925050503d805f811462000b31576040519150601f19603f3d011682016040523d82523d5f602084013e62000b36565b606091505b5050600a546040519192505f916001600160a01b039091169047908381818185875af1925050503d805f811462000b89576040519150601f19603f3d011682016040523d82523d5f602084013e62000b8e565b606091505b50509050818062000b9c5750805b1562000bf0577f17bbfb9a6069321b6ded73bd96327c9e6b7212a5cd51ff219cd61370acafb561878462000bd181896200119f565b6040805193845260208401929092529082015260600160405180910390a15b50505062000c4f565b600a546040515f916001600160a01b03169047908381818185875af1925050503d805f811462000c45576040519150601f19603f3d011682016040523d82523d5f602084013e62000c4a565b606091505b505050505b50505050565b6040805160028082526060820183525f9260208301908036833701905050905030815f8151811062000c8b5762000c8b620011b5565b6001600160a01b03928316602091820292909201810191909152600654604080516315ab88c960e31b81529051919093169263ad5c46489260048083019391928290030181865afa15801562000ce3573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000d0991906200110c565b8160018151811062000d1f5762000d1f620011b5565b6001600160a01b03928316602091820292909201015260065460405163d06ca61f60e01b81525f92919091169063d06ca61f9062000d6490869086906004016200120d565b5f60405180830381865afa15801562000d7f573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405262000da891908101906200122f565b60018151811062000dbd5762000dbd620011b5565b6020908102919091010151600654909150839062000de69030906001600160a01b031662000e92565b101562000e085760065462000e089030906001600160a01b03165f1962000ebe565b6006546001600160a01b031663791ac94784606462000e2985605062001165565b62000e3591906200117f565b853062000e45426101686200114f565b6040518663ffffffff1660e01b815260040162000e67959493929190620012f3565b5f604051808303815f87803b15801562000e7f575f80fd5b505af11580156200091b573d5f803e3d5ffd5b6001600160a01b038083165f908152600160209081526040808320938516835292905220545b92915050565b6200063a83838360016001600160a01b03841662000ef25760405163e602df0560e01b81525f6004820152602401620000bc565b6001600160a01b03831662000f1d57604051634a1406b160e11b81525f6004820152602401620000bc565b6001600160a01b038085165f908152600160209081526040808320938716835292905220829055801562000c4f57826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405162000f9191815260200190565b60405180910390a350505050565b6111c48062002c4683390190565b634e487b7160e01b5f52604160045260245ffd5b600181811c9082168062000fd657607f821691505b60208210810362000ff557634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156200063a575f81815260208120601f850160051c81016020861015620010235750805b601f850160051c820191505b818110156200091d578281556001016200102f565b81516001600160401b0381111562001060576200106062000fad565b620010788162001071845462000fc1565b8462000ffb565b602080601f831160018114620010ae575f8415620010965750858301515b5f19600386901b1c1916600185901b1785556200091d565b5f85815260208120601f198616915b82811015620010de57888601518255948401946001909101908401620010bd565b5085821015620010fc57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f602082840312156200111d575f80fd5b81516001600160a01b038116811462001134575f80fd5b9392505050565b634e487b7160e01b5f52601160045260245ffd5b8082018082111562000eb85762000eb86200113b565b808202811582820484141762000eb85762000eb86200113b565b5f826200119a57634e487b7160e01b5f52601260045260245ffd5b500490565b8181038181111562000eb85762000eb86200113b565b634e487b7160e01b5f52603260045260245ffd5b5f8151808452602080850194508084015f5b83811015620012025781516001600160a01b031687529582019590820190600101620011db565b509495945050505050565b828152604060208201525f620012276040830184620011c9565b949350505050565b5f602080838503121562001241575f80fd5b82516001600160401b038082111562001258575f80fd5b818501915085601f8301126200126c575f80fd5b81518181111562001281576200128162000fad565b8060051b604051601f19603f83011681018181108582111715620012a957620012a962000fad565b604052918252848201925083810185019188831115620012c7575f80fd5b938501935b82851015620012e757845184529385019392850192620012cc565b98975050505050505050565b85815284602082015260a060408201525f6200131360a0830186620011c9565b6001600160a01b0394909416606083015250608001529392505050565b611908806200133e5f395ff3fe608060405260043610610198575f3560e01c8063715018a6116100e7578063a9059cbb11610087578063e2f4560511610062578063e2f45605146104ae578063e98030c7146104c3578063ecc41ee5146104e2578063f2fde38b146104f6575f80fd5b8063a9059cbb14610451578063b2d8f20814610470578063dd62ed3e1461048f575f80fd5b806395d89b41116100c257806395d89b41146103cb5780639fd8234e146103df578063a0a0c465146103fe578063a35c85b014610412575f80fd5b8063715018a61461037b57806375f0a8741461038f5780638da5cb5b146103ae575f80fd5b80632c1f521611610152578063470624021161012d57806347062402146102ed57806349bd5a5e146103075780635d098b381461032657806370a0823114610347575f80fd5b80632c1f52161461029f57806330bb4cff146102be578063313ce567146102d2575f80fd5b806306fdde03146101a3578063095ea7b3146101cd5780631694505e146101fc57806318160ddd1461023357806323b872dd146102515780632b14ca5614610270575f80fd5b3661019f57005b5f80fd5b3480156101ae575f80fd5b506101b7610515565b6040516101c4919061149f565b60405180910390f35b3480156101d8575f80fd5b506101ec6101e73660046114fe565b6105a5565b60405190151581526020016101c4565b348015610207575f80fd5b5060065461021b906001600160a01b031681565b6040516001600160a01b0390911681526020016101c4565b34801561023e575f80fd5b506002545b6040519081526020016101c4565b34801561025c575f80fd5b506101ec61026b366004611528565b6105be565b34801561027b575f80fd5b50600d54600e5461028a919082565b604080519283526020830191909152016101c4565b3480156102aa575f80fd5b5060085461021b906001600160a01b031681565b3480156102c9575f80fd5b506102436105e1565b3480156102dd575f80fd5b50604051601281526020016101c4565b3480156102f8575f80fd5b50600b54600c5461028a919082565b348015610312575f80fd5b5060075461021b906001600160a01b031681565b348015610331575f80fd5b50610345610340366004611566565b610651565b005b348015610352575f80fd5b50610243610361366004611566565b6001600160a01b03165f9081526020819052604090205490565b348015610386575f80fd5b506103456106a9565b34801561039a575f80fd5b50600a5461021b906001600160a01b031681565b3480156103b9575f80fd5b506005546001600160a01b031661021b565b3480156103d6575f80fd5b506101b76106bc565b3480156103ea575f80fd5b506103456103f9366004611588565b6106cb565b348015610409575f80fd5b50610345610738565b34801561041d575f80fd5b5061043161042c366004611566565b61086a565b6040805194855260208501939093529183015260608201526080016101c4565b34801561045c575f80fd5b506101ec61046b3660046114fe565b6108f0565b34801561047b575f80fd5b5061034561048a366004611588565b6108fd565b34801561049a575f80fd5b506102436104a93660046115a8565b610973565b3480156104b9575f80fd5b5061024360095481565b3480156104ce575f80fd5b506103456104dd3660046115df565b61099d565b3480156104ed575f80fd5b50610243610a01565b348015610501575f80fd5b50610345610510366004611566565b610a48565b606060038054610524906115f6565b80601f0160208091040260200160405190810160405280929190818152602001828054610550906115f6565b801561059b5780601f106105725761010080835404028352916020019161059b565b820191905f5260205f20905b81548152906001019060200180831161057e57829003601f168201915b5050505050905090565b5f336105b2818585610a8a565b60019150505b92915050565b5f336105cb858285610a9c565b6105d6858585610af9565b506001949350505050565b600854604080516342d359d760e11b815290515f926001600160a01b0316916385a6b3ae9160048083019260209291908290030181865afa158015610628573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061064c919061162e565b905090565b610659610b56565b600a80546001600160a01b038381166001600160a01b03198316811790935560405191169182917f8616c7a330e3cf61290821331585511f1e2778171e2b005fb5ec60cfe874dc67905f90a35050565b6106b1610b56565b6106ba5f610b83565b565b606060048054610524906115f6565b6106d3610b56565b601e6106df8284611659565b11156106fe57604051631255745b60e31b815260040160405180910390fd5b600d829055600e819055604051819083907f2c7448b63380296b372453c5287509524b5b645dc6a93ffe09e0af53e6b8935b905f90a35050565b60085460405163fbcbc0f160e01b81523360048201526001915f9182916001600160a01b03169063fbcbc0f19060240161010060405180830381865afa158015610784573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107a8919061166c565b50965050509450505050815f036107d25760405163b5596c7560e01b815260040160405180910390fd5b804210156107f3576040516394424e4560e01b815260040160405180910390fd5b60085460405163bc4c4b3760e01b81523360048201525f60248201526001600160a01b039091169063bc4c4b37906044016020604051808303815f875af1158015610840573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061086491906116d1565b50505050565b60085460405163fbcbc0f160e01b81526001600160a01b0383811660048301525f92839283928392169063fbcbc0f19060240161010060405180830381865afa1580156108b9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108dd919061166c565b50929b919a509850909650945050505050565b5f336105b2818585610af9565b610905610b56565b601e6109118284611659565b111561093057604051631255745b60e31b815260040160405180910390fd5b600b829055600c81905560405181815282907f480af1f773972b1df72af32ec463e0fdeb1b49f1ca37d07982f677919d5fdd0c9060200160405180910390a25050565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205490565b6109a5610b56565b60085460405163e98030c760e01b8152600481018390526001600160a01b039091169063e98030c7906024015f604051808303815f87803b1580156109e8575f80fd5b505af11580156109fa573d5f803e3d5ffd5b5050505050565b600854604080516304ddf6ef60e11b815290515f926001600160a01b0316916309bbedde9160048083019260209291908290030181865afa158015610628573d5f803e3d5ffd5b610a50610b56565b6001600160a01b038116610a7e57604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b610a8781610b83565b50565b610a978383836001610bd4565b505050565b5f610aa78484610973565b90505f1981146108645781811015610aeb57604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610a75565b61086484848484035f610bd4565b6001600160a01b038316610b2257604051634b637e8f60e11b81525f6004820152602401610a75565b6001600160a01b038216610b4b5760405163ec442f0560e01b81525f6004820152602401610a75565b610a97838383610ca6565b6005546001600160a01b031633146106ba5760405163118cdaa760e01b8152336004820152602401610a75565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6001600160a01b038416610bfd5760405163e602df0560e01b81525f6004820152602401610a75565b6001600160a01b038316610c2657604051634a1406b160e11b81525f6004820152602401610a75565b6001600160a01b038085165f908152600160209081526040808320938716835292905220829055801561086457826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610c9891815260200190565b60405180910390a350505050565b805f03610cb857610a9783835f610f78565b305f9081526020819052604090205460095481108015908190610ce55750600754600160a01b900460ff16155b8015610cff57506007546001600160a01b03868116911614155b8015610d1957506005546001600160a01b03868116911614155b8015610d3357506005546001600160a01b03858116911614155b15610d62576007805460ff60a01b1916600160a01b179055610d548261109e565b6007805460ff60a01b191690555b6007546001600160a01b0386165f908152600f602052604090205460ff600160a01b909204821615911680610dae57506001600160a01b0385165f908152600f602052604090205460ff165b15610db657505f5b8015610e5b576007545f906001600160a01b0390811690881603610dfd57600b54600c54606491610de691611659565b610df090876116f0565b610dfa9190611707565b90505b6007546001600160a01b0390811690871603610e3c57600d54600e54606491610e2591611659565b610e2f90876116f0565b610e399190611707565b90505b610e468186611726565b94508015610e5957610e59873083610f78565b505b610e66868686610f78565b6008546001600160a01b031663e30443bc87610e96816001600160a01b03165f9081526020819052604090205490565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044015f604051808303815f87803b158015610ed9575f80fd5b505af1925050508015610eea575060015b506008546001600160a01b031663e30443bc86610f1b816001600160a01b03165f9081526020819052604090205490565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044015f604051808303815f87803b158015610f5e575f80fd5b505af1925050508015610f6f575060015b50505050505050565b6001600160a01b038316610fa2578060025f828254610f979190611659565b909155506110129050565b6001600160a01b0383165f9081526020819052604090205481811015610ff45760405163391434e360e21b81526001600160a01b03851660048201526024810182905260448101839052606401610a75565b6001600160a01b0384165f9081526020819052604090209082900390555b6001600160a01b03821661102e5760028054829003905561104c565b6001600160a01b0382165f9081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161109191815260200190565b60405180910390a3505050565b476110a882611280565b5f6110b38247611726565b600d54600e54600b54600c549394505f936110ce9190611659565b6110d89190611659565b6110e29190611659565b9050801561122757600e54600c545f9183916110fe9190611659565b61110890856116f0565b6111129190611707565b6008549091505f906001600160a01b031661112d8386611726565b6040515f81818185875af1925050503d805f8114611166576040519150601f19603f3d011682016040523d82523d5f602084013e61116b565b606091505b5050600a546040519192505f916001600160a01b039091169047908381818185875af1925050503d805f81146111bc576040519150601f19603f3d011682016040523d82523d5f602084013e6111c1565b606091505b5050905081806111ce5750805b1561121f577f17bbfb9a6069321b6ded73bd96327c9e6b7212a5cd51ff219cd61370acafb56187846112008189611726565b6040805193845260208401929092529082015260600160405180910390a15b505050610864565b600a546040515f916001600160a01b03169047908381818185875af1925050503d805f8114611271576040519150601f19603f3d011682016040523d82523d5f602084013e611276565b606091505b5050505050505050565b6040805160028082526060820183525f9260208301908036833701905050905030815f815181106112b3576112b361174d565b6001600160a01b03928316602091820292909201810191909152600654604080516315ab88c960e31b81529051919093169263ad5c46489260048083019391928290030181865afa15801561130a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061132e9190611761565b816001815181106113415761134161174d565b6001600160a01b03928316602091820292909201015260065460405163d06ca61f60e01b81525f92919091169063d06ca61f9061138490869086906004016117be565b5f60405180830381865afa15801561139e573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526113c591908101906117de565b6001815181106113d7576113d761174d565b60200260200101519050826114003060065f9054906101000a90046001600160a01b0316610973565b101561141f5760065461141f9030906001600160a01b03165f19610a8a565b6006546001600160a01b031663791ac94784606461143e8560506116f0565b6114489190611707565b853061145642610168611659565b6040518663ffffffff1660e01b8152600401611476959493929190611897565b5f604051808303815f87803b15801561148d575f80fd5b505af1158015610f6f573d5f803e3d5ffd5b5f6020808352835180828501525f5b818110156114ca578581018301518582016040015282016114ae565b505f604082860101526040601f19601f8301168501019250505092915050565b6001600160a01b0381168114610a87575f80fd5b5f806040838503121561150f575f80fd5b823561151a816114ea565b946020939093013593505050565b5f805f6060848603121561153a575f80fd5b8335611545816114ea565b92506020840135611555816114ea565b929592945050506040919091013590565b5f60208284031215611576575f80fd5b8135611581816114ea565b9392505050565b5f8060408385031215611599575f80fd5b50508035926020909101359150565b5f80604083850312156115b9575f80fd5b82356115c4816114ea565b915060208301356115d4816114ea565b809150509250929050565b5f602082840312156115ef575f80fd5b5035919050565b600181811c9082168061160a57607f821691505b60208210810361162857634e487b7160e01b5f52602260045260245ffd5b50919050565b5f6020828403121561163e575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b808201808211156105b8576105b8611645565b5f805f805f805f80610100898b031215611684575f80fd5b885161168f816114ea565b809850506020890151965060408901519550606089015194506080890151935060a0890151925060c0890151915060e089015190509295985092959890939650565b5f602082840312156116e1575f80fd5b81518015158114611581575f80fd5b80820281158282048414176105b8576105b8611645565b5f8261172157634e487b7160e01b5f52601260045260245ffd5b500490565b818103818111156105b8576105b8611645565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215611771575f80fd5b8151611581816114ea565b5f8151808452602080850194508084015f5b838110156117b35781516001600160a01b03168752958201959082019060010161178e565b509495945050505050565b828152604060208201525f6117d6604083018461177c565b949350505050565b5f60208083850312156117ef575f80fd5b825167ffffffffffffffff80821115611806575f80fd5b818501915085601f830112611819575f80fd5b81518181111561182b5761182b611739565b8060051b604051601f19603f8301168101818110858211171561185057611850611739565b60405291825284820192508381018501918883111561186d575f80fd5b938501935b8285101561188b57845184529385019392850192611872565b98975050505050505050565b85815284602082015260a060408201525f6118b560a083018661177c565b6001600160a01b039490941660608301525060800152939250505056fea26469706673582212203e19f995260af59be03184a9d273d9c2f7a2e774c67533f814298c87945b6e8a64736f6c6343000814003360a060405234801561000f575f80fd5b50338061003557604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b61003e81610057565b5061a8c0600e5568056bc75e2d631000006080526100a6565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6080516110ff6100c55f395f81816103b6015261074401526110ff5ff3fe60806040526004361061013f575f3560e01c806385a6b3ae116100b3578063be10b6141161006d578063be10b614146103a5578063e30443bc146103d8578063e7841ec0146103f7578063e98030c71461040b578063f2fde38b1461042a578063fbcbc0f114610449575f80fd5b806385a6b3ae146102d95780638da5cb5b146102ee57806391b89fba14610314578063a8b9d24014610333578063aafd847a14610352578063bc4c4b3714610386575f80fd5b806331e79db01161010457806331e79db0146101dc5780634e7b827f146101fb5780635183d6fd146102395780636a4740021461029d5780636f2789ec146102b0578063715018a6146102c5575f80fd5b806303c833021461015257806309bbedde1461015a578063226cfa3d1461017d57806327ce0147146101a85780633009a609146101c7575f80fd5b3661014e5761014c610468565b005b5f80fd5b61014c610468565b348015610165575f80fd5b506007545b6040519081526020015b60405180910390f35b348015610188575f80fd5b5061016a610197366004610f54565b600d6020525f908152604090205481565b3480156101b3575f80fd5b5061016a6101c2366004610f54565b6104ee565b3480156101d2575f80fd5b5061016a600b5481565b3480156101e7575f80fd5b5061014c6101f6366004610f54565b610550565b348015610206575f80fd5b50610229610215366004610f54565b600c6020525f908152604090205460ff1681565b6040519015158152602001610174565b348015610244575f80fd5b50610258610253366004610f6f565b6105ea565b604080516001600160a01b0390991689526020890197909752958701949094526060860192909252608085015260a084015260c083015260e082015261010001610174565b3480156102a8575f80fd5b5061014c5f80fd5b3480156102bb575f80fd5b5061016a600e5481565b3480156102d0575f80fd5b5061014c610652565b3480156102e4575f80fd5b5061016a60065481565b3480156102f9575f80fd5b505f546040516001600160a01b039091168152602001610174565b34801561031f575f80fd5b5061016a61032e366004610f54565b610663565b34801561033e575f80fd5b5061016a61034d366004610f54565b610669565b34801561035d575f80fd5b5061016a61036c366004610f54565b6001600160a01b03165f9081526003602052604090205490565b348015610391575f80fd5b506102296103a0366004610f86565b610694565b3480156103b0575f80fd5b5061016a7f000000000000000000000000000000000000000000000000000000000000000081565b3480156103e3575f80fd5b5061014c6103f2366004610fc1565b61071b565b348015610402575f80fd5b50600b5461016a565b348015610416575f80fd5b5061014c610425366004610f6f565b610798565b348015610435575f80fd5b5061014c610444366004610f54565b610802565b348015610454575f80fd5b50610258610463366004610f54565b610844565b5f60055411610475575f80fd5b34156104ec576005546104a39061049034600160801b610925565b61049a9190610fff565b60015490610937565b60015560405134815233907fa493a9229478c3fcd73f66d2cdeb7f94fd0f341da924d1054236d784541165119060200160405180910390a26006546104e89034610937565b6006555b565b6001600160a01b0381165f908152600260209081526040808320546004909252822054600154600160801b926105409261053b92610535916105309190610925565b610942565b90610950565b61098a565b61054a9190610fff565b92915050565b61055861099b565b6001600160a01b0381165f908152600c602052604090205460ff161561057c575f80fd5b6001600160a01b0381165f908152600c60205260408120805460ff191660011790556105a99082906109c7565b6105b4600782610b20565b6040516001600160a01b038216907fa878b31040b2e6d0a9a3d3361209db3908ba62014b0dca52adbaee451d128b25905f90a250565b5f805f805f805f806105fb60075490565b891061061e57505f96505f19955085945086935083925082915081905080610647565b5f61062a60078b610c53565b905061063581610844565b98509850985098509850985098509850505b919395975091939597565b61065a61099b565b6104ec5f610c83565b5f61054a825b6001600160a01b0381165f9081526003602052604081205461054a9061068e846104ee565b90610cd2565b5f61069d61099b565b5f6106a784610cdd565b90508015610712576001600160a01b0384165f818152600d6020526040908190204290555184151591907fa2c38e2d2fb7e3e1912d937fd1ca11ed6d51864dee4cfa7a7bf02becd7acf092906107009085815260200190565b60405180910390a3600191505061054a565b505f9392505050565b61072361099b565b6001600160a01b0382165f908152600c602052604090205460ff1661077f577f000000000000000000000000000000000000000000000000000000000000000081106107835761077382826109c7565b61077f60078383610e19565b5050565b61078d825f6109c7565b61077f600783610b20565b6107a061099b565b610e108110806107b257506201518081115b156107d057604051633ff1100360e01b815260040160405180910390fd5b600e5460405182907f474ea64804364a1e29a4487ddb63c3342a2dd826ccd8acf48825e680a0e6f20f905f90a3600e55565b61080a61099b565b6001600160a01b03811661083857604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b61084181610c83565b50565b805f808080808080610857600789610ebf565b96505f1995505f87126108b557600b5487111561088357600b5461087c908890610f07565b95506108b5565b600b546007545f9110610896575f6108a5565b600b546007546108a591610cd2565b90506108b18882610950565b9650505b6108be88610669565b94506108c9886104ee565b6001600160a01b0389165f908152600d60205260409020549094509250826108f1575f6108ff565b600e546108ff908490610937565b915042821161090e575f610918565b6109188242610cd2565b9050919395975091939597565b5f610930828461101e565b9392505050565b5f6109308284611035565b5f818181121561054a575f80fd5b5f8061095c8385611048565b90505f831215801561096e5750838112155b8061098257505f8312801561098257508381125b610930575f80fd5b5f80821215610997575f80fd5b5090565b5f546001600160a01b031633146104ec5760405163118cdaa760e01b815233600482015260240161082f565b6001600160a01b0382165f9081526004602052604090205480821115610a8c575f6109f28383610cd2565b6001600160a01b0385165f90815260046020526040812080549293508392909190610a1e908490611035565b925050819055508060055f828254610a369190611035565b9091555050600154610a6e90610a50906105309084610925565b6001600160a01b0386165f9081526002602052604090205490610f07565b6001600160a01b0385165f9081526002602052604090205550505050565b80821015610b1b575f610a9f8284610cd2565b6001600160a01b0385165f90815260046020526040812080549293508392909190610acb90849061106f565b925050819055508060055f828254610ae3919061106f565b9091555050600154610a6e90610afd906105309084610925565b6001600160a01b0386165f9081526002602052604090205490610950565b505050565b6001600160a01b0381165f90815260038301602052604090205460ff16610b45575050565b6001600160a01b0381165f9081526003830160209081526040808320805460ff1916905560018086018352818420849055600286019092528220548454909291610b8e9161106f565b90505f845f018281548110610ba557610ba5611082565b5f9182526020808320909101546001600160a01b03908116808452600289019092526040808420879055908716835282209190915585549091508190869085908110610bf357610bf3611082565b5f91825260209091200180546001600160a01b0319166001600160a01b03929092169190911790558454859080610c2c57610c2c611096565b5f8281526020902081015f1990810180546001600160a01b03191690550190555050505050565b5f825f018281548110610c6857610c68611082565b5f918252602090912001546001600160a01b03169392505050565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f610930828461106f565b5f80610ce883610669565b90508015610e11576001600160a01b0383165f90815260036020526040902054610d129082610937565b6001600160a01b0384165f81815260036020526040908190209290925590517fee503bee2bb6a87e57bc57db795f98137327401a0e7b7ce42e37926cc1a9ca4d90610d609084815260200190565b60405180910390a25f836001600160a01b031682610bb8906040515f60405180830381858888f193505050503d805f8114610db6576040519150601f19603f3d011682016040523d82523d5f602084013e610dbb565b606091505b5050905080610e0a576001600160a01b0384165f90815260036020526040902054610de69083610cd2565b6001600160a01b039094165f90815260036020526040812094909455509192915050565b5092915050565b505f92915050565b6001600160a01b0382165f90815260038401602052604090205460ff1615610e5c576001600160a01b0382165f9081526001840160205260409020819055505050565b6001600160a01b0382165f8181526003850160209081526040808320805460ff19166001908117909155878101835281842086905587546002890184529184208290558101875586835291200180546001600160a01b0319169091179055505050565b6001600160a01b0381165f90815260038301602052604081205460ff16610ee857505f1961054a565b506001600160a01b03165f908152600291909101602052604090205490565b5f80610f1383856110aa565b90505f8312158015610f255750838113155b8061098257505f831280156109825750838113610930575f80fd5b6001600160a01b0381168114610841575f80fd5b5f60208284031215610f64575f80fd5b813561093081610f40565b5f60208284031215610f7f575f80fd5b5035919050565b5f8060408385031215610f97575f80fd5b8235610fa281610f40565b915060208301358015158114610fb6575f80fd5b809150509250929050565b5f8060408385031215610fd2575f80fd5b8235610fdd81610f40565b946020939093013593505050565b634e487b7160e01b5f52601160045260245ffd5b5f8261101957634e487b7160e01b5f52601260045260245ffd5b500490565b808202811582820484141761054a5761054a610feb565b8082018082111561054a5761054a610feb565b8082018281125f83128015821682158216171561106757611067610feb565b505092915050565b8181038181111561054a5761054a610feb565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52603160045260245ffd5b8181035f831280158383131683831282161715610e0a57610e0a610feb56fea26469706673582212200589d0e5c32d8c73f9ad1e9b97102c0d9415a29951bd0fdaad32d6040b68e36564736f6c63430008140033

Deployed Bytecode

0x608060405260043610610198575f3560e01c8063715018a6116100e7578063a9059cbb11610087578063e2f4560511610062578063e2f45605146104ae578063e98030c7146104c3578063ecc41ee5146104e2578063f2fde38b146104f6575f80fd5b8063a9059cbb14610451578063b2d8f20814610470578063dd62ed3e1461048f575f80fd5b806395d89b41116100c257806395d89b41146103cb5780639fd8234e146103df578063a0a0c465146103fe578063a35c85b014610412575f80fd5b8063715018a61461037b57806375f0a8741461038f5780638da5cb5b146103ae575f80fd5b80632c1f521611610152578063470624021161012d57806347062402146102ed57806349bd5a5e146103075780635d098b381461032657806370a0823114610347575f80fd5b80632c1f52161461029f57806330bb4cff146102be578063313ce567146102d2575f80fd5b806306fdde03146101a3578063095ea7b3146101cd5780631694505e146101fc57806318160ddd1461023357806323b872dd146102515780632b14ca5614610270575f80fd5b3661019f57005b5f80fd5b3480156101ae575f80fd5b506101b7610515565b6040516101c4919061149f565b60405180910390f35b3480156101d8575f80fd5b506101ec6101e73660046114fe565b6105a5565b60405190151581526020016101c4565b348015610207575f80fd5b5060065461021b906001600160a01b031681565b6040516001600160a01b0390911681526020016101c4565b34801561023e575f80fd5b506002545b6040519081526020016101c4565b34801561025c575f80fd5b506101ec61026b366004611528565b6105be565b34801561027b575f80fd5b50600d54600e5461028a919082565b604080519283526020830191909152016101c4565b3480156102aa575f80fd5b5060085461021b906001600160a01b031681565b3480156102c9575f80fd5b506102436105e1565b3480156102dd575f80fd5b50604051601281526020016101c4565b3480156102f8575f80fd5b50600b54600c5461028a919082565b348015610312575f80fd5b5060075461021b906001600160a01b031681565b348015610331575f80fd5b50610345610340366004611566565b610651565b005b348015610352575f80fd5b50610243610361366004611566565b6001600160a01b03165f9081526020819052604090205490565b348015610386575f80fd5b506103456106a9565b34801561039a575f80fd5b50600a5461021b906001600160a01b031681565b3480156103b9575f80fd5b506005546001600160a01b031661021b565b3480156103d6575f80fd5b506101b76106bc565b3480156103ea575f80fd5b506103456103f9366004611588565b6106cb565b348015610409575f80fd5b50610345610738565b34801561041d575f80fd5b5061043161042c366004611566565b61086a565b6040805194855260208501939093529183015260608201526080016101c4565b34801561045c575f80fd5b506101ec61046b3660046114fe565b6108f0565b34801561047b575f80fd5b5061034561048a366004611588565b6108fd565b34801561049a575f80fd5b506102436104a93660046115a8565b610973565b3480156104b9575f80fd5b5061024360095481565b3480156104ce575f80fd5b506103456104dd3660046115df565b61099d565b3480156104ed575f80fd5b50610243610a01565b348015610501575f80fd5b50610345610510366004611566565b610a48565b606060038054610524906115f6565b80601f0160208091040260200160405190810160405280929190818152602001828054610550906115f6565b801561059b5780601f106105725761010080835404028352916020019161059b565b820191905f5260205f20905b81548152906001019060200180831161057e57829003601f168201915b5050505050905090565b5f336105b2818585610a8a565b60019150505b92915050565b5f336105cb858285610a9c565b6105d6858585610af9565b506001949350505050565b600854604080516342d359d760e11b815290515f926001600160a01b0316916385a6b3ae9160048083019260209291908290030181865afa158015610628573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061064c919061162e565b905090565b610659610b56565b600a80546001600160a01b038381166001600160a01b03198316811790935560405191169182917f8616c7a330e3cf61290821331585511f1e2778171e2b005fb5ec60cfe874dc67905f90a35050565b6106b1610b56565b6106ba5f610b83565b565b606060048054610524906115f6565b6106d3610b56565b601e6106df8284611659565b11156106fe57604051631255745b60e31b815260040160405180910390fd5b600d829055600e819055604051819083907f2c7448b63380296b372453c5287509524b5b645dc6a93ffe09e0af53e6b8935b905f90a35050565b60085460405163fbcbc0f160e01b81523360048201526001915f9182916001600160a01b03169063fbcbc0f19060240161010060405180830381865afa158015610784573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107a8919061166c565b50965050509450505050815f036107d25760405163b5596c7560e01b815260040160405180910390fd5b804210156107f3576040516394424e4560e01b815260040160405180910390fd5b60085460405163bc4c4b3760e01b81523360048201525f60248201526001600160a01b039091169063bc4c4b37906044016020604051808303815f875af1158015610840573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061086491906116d1565b50505050565b60085460405163fbcbc0f160e01b81526001600160a01b0383811660048301525f92839283928392169063fbcbc0f19060240161010060405180830381865afa1580156108b9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108dd919061166c565b50929b919a509850909650945050505050565b5f336105b2818585610af9565b610905610b56565b601e6109118284611659565b111561093057604051631255745b60e31b815260040160405180910390fd5b600b829055600c81905560405181815282907f480af1f773972b1df72af32ec463e0fdeb1b49f1ca37d07982f677919d5fdd0c9060200160405180910390a25050565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205490565b6109a5610b56565b60085460405163e98030c760e01b8152600481018390526001600160a01b039091169063e98030c7906024015f604051808303815f87803b1580156109e8575f80fd5b505af11580156109fa573d5f803e3d5ffd5b5050505050565b600854604080516304ddf6ef60e11b815290515f926001600160a01b0316916309bbedde9160048083019260209291908290030181865afa158015610628573d5f803e3d5ffd5b610a50610b56565b6001600160a01b038116610a7e57604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b610a8781610b83565b50565b610a978383836001610bd4565b505050565b5f610aa78484610973565b90505f1981146108645781811015610aeb57604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610a75565b61086484848484035f610bd4565b6001600160a01b038316610b2257604051634b637e8f60e11b81525f6004820152602401610a75565b6001600160a01b038216610b4b5760405163ec442f0560e01b81525f6004820152602401610a75565b610a97838383610ca6565b6005546001600160a01b031633146106ba5760405163118cdaa760e01b8152336004820152602401610a75565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6001600160a01b038416610bfd5760405163e602df0560e01b81525f6004820152602401610a75565b6001600160a01b038316610c2657604051634a1406b160e11b81525f6004820152602401610a75565b6001600160a01b038085165f908152600160209081526040808320938716835292905220829055801561086457826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610c9891815260200190565b60405180910390a350505050565b805f03610cb857610a9783835f610f78565b305f9081526020819052604090205460095481108015908190610ce55750600754600160a01b900460ff16155b8015610cff57506007546001600160a01b03868116911614155b8015610d1957506005546001600160a01b03868116911614155b8015610d3357506005546001600160a01b03858116911614155b15610d62576007805460ff60a01b1916600160a01b179055610d548261109e565b6007805460ff60a01b191690555b6007546001600160a01b0386165f908152600f602052604090205460ff600160a01b909204821615911680610dae57506001600160a01b0385165f908152600f602052604090205460ff165b15610db657505f5b8015610e5b576007545f906001600160a01b0390811690881603610dfd57600b54600c54606491610de691611659565b610df090876116f0565b610dfa9190611707565b90505b6007546001600160a01b0390811690871603610e3c57600d54600e54606491610e2591611659565b610e2f90876116f0565b610e399190611707565b90505b610e468186611726565b94508015610e5957610e59873083610f78565b505b610e66868686610f78565b6008546001600160a01b031663e30443bc87610e96816001600160a01b03165f9081526020819052604090205490565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044015f604051808303815f87803b158015610ed9575f80fd5b505af1925050508015610eea575060015b506008546001600160a01b031663e30443bc86610f1b816001600160a01b03165f9081526020819052604090205490565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044015f604051808303815f87803b158015610f5e575f80fd5b505af1925050508015610f6f575060015b50505050505050565b6001600160a01b038316610fa2578060025f828254610f979190611659565b909155506110129050565b6001600160a01b0383165f9081526020819052604090205481811015610ff45760405163391434e360e21b81526001600160a01b03851660048201526024810182905260448101839052606401610a75565b6001600160a01b0384165f9081526020819052604090209082900390555b6001600160a01b03821661102e5760028054829003905561104c565b6001600160a01b0382165f9081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161109191815260200190565b60405180910390a3505050565b476110a882611280565b5f6110b38247611726565b600d54600e54600b54600c549394505f936110ce9190611659565b6110d89190611659565b6110e29190611659565b9050801561122757600e54600c545f9183916110fe9190611659565b61110890856116f0565b6111129190611707565b6008549091505f906001600160a01b031661112d8386611726565b6040515f81818185875af1925050503d805f8114611166576040519150601f19603f3d011682016040523d82523d5f602084013e61116b565b606091505b5050600a546040519192505f916001600160a01b039091169047908381818185875af1925050503d805f81146111bc576040519150601f19603f3d011682016040523d82523d5f602084013e6111c1565b606091505b5050905081806111ce5750805b1561121f577f17bbfb9a6069321b6ded73bd96327c9e6b7212a5cd51ff219cd61370acafb56187846112008189611726565b6040805193845260208401929092529082015260600160405180910390a15b505050610864565b600a546040515f916001600160a01b03169047908381818185875af1925050503d805f8114611271576040519150601f19603f3d011682016040523d82523d5f602084013e611276565b606091505b5050505050505050565b6040805160028082526060820183525f9260208301908036833701905050905030815f815181106112b3576112b361174d565b6001600160a01b03928316602091820292909201810191909152600654604080516315ab88c960e31b81529051919093169263ad5c46489260048083019391928290030181865afa15801561130a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061132e9190611761565b816001815181106113415761134161174d565b6001600160a01b03928316602091820292909201015260065460405163d06ca61f60e01b81525f92919091169063d06ca61f9061138490869086906004016117be565b5f60405180830381865afa15801561139e573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526113c591908101906117de565b6001815181106113d7576113d761174d565b60200260200101519050826114003060065f9054906101000a90046001600160a01b0316610973565b101561141f5760065461141f9030906001600160a01b03165f19610a8a565b6006546001600160a01b031663791ac94784606461143e8560506116f0565b6114489190611707565b853061145642610168611659565b6040518663ffffffff1660e01b8152600401611476959493929190611897565b5f604051808303815f87803b15801561148d575f80fd5b505af1158015610f6f573d5f803e3d5ffd5b5f6020808352835180828501525f5b818110156114ca578581018301518582016040015282016114ae565b505f604082860101526040601f19601f8301168501019250505092915050565b6001600160a01b0381168114610a87575f80fd5b5f806040838503121561150f575f80fd5b823561151a816114ea565b946020939093013593505050565b5f805f6060848603121561153a575f80fd5b8335611545816114ea565b92506020840135611555816114ea565b929592945050506040919091013590565b5f60208284031215611576575f80fd5b8135611581816114ea565b9392505050565b5f8060408385031215611599575f80fd5b50508035926020909101359150565b5f80604083850312156115b9575f80fd5b82356115c4816114ea565b915060208301356115d4816114ea565b809150509250929050565b5f602082840312156115ef575f80fd5b5035919050565b600181811c9082168061160a57607f821691505b60208210810361162857634e487b7160e01b5f52602260045260245ffd5b50919050565b5f6020828403121561163e575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b808201808211156105b8576105b8611645565b5f805f805f805f80610100898b031215611684575f80fd5b885161168f816114ea565b809850506020890151965060408901519550606089015194506080890151935060a0890151925060c0890151915060e089015190509295985092959890939650565b5f602082840312156116e1575f80fd5b81518015158114611581575f80fd5b80820281158282048414176105b8576105b8611645565b5f8261172157634e487b7160e01b5f52601260045260245ffd5b500490565b818103818111156105b8576105b8611645565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215611771575f80fd5b8151611581816114ea565b5f8151808452602080850194508084015f5b838110156117b35781516001600160a01b03168752958201959082019060010161178e565b509495945050505050565b828152604060208201525f6117d6604083018461177c565b949350505050565b5f60208083850312156117ef575f80fd5b825167ffffffffffffffff80821115611806575f80fd5b818501915085601f830112611819575f80fd5b81518181111561182b5761182b611739565b8060051b604051601f19603f8301168101818110858211171561185057611850611739565b60405291825284820192508381018501918883111561186d575f80fd5b938501935b8285101561188b57845184529385019392850192611872565b98975050505050505050565b85815284602082015260a060408201525f6118b560a083018661177c565b6001600160a01b039490941660608301525060800152939250505056fea26469706673582212203e19f995260af59be03184a9d273d9c2f7a2e774c67533f814298c87945b6e8a64736f6c63430008140033

Deployed Bytecode Sourcemap

43662:10890:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9887:91;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;12221:222;;;;;;;;;;-1:-1:-1;12221:222:0;;;;;:::i;:::-;;:::i;:::-;;;1188:14:1;;1181:22;1163:41;;1151:2;1136:18;12221:222:0;1023:187:1;44076:41:0;;;;;;;;;;-1:-1:-1;44076:41:0;;;;-1:-1:-1;;;;;44076:41:0;;;;;;-1:-1:-1;;;;;1405:32:1;;;1387:51;;1375:2;1360:18;44076:41:0;1215:229:1;10989:99:0;;;;;;;;;;-1:-1:-1;11068:12:0;;10989:99;;;1595:25:1;;;1583:2;1568:18;10989:99:0;1449:177:1;13021:283:0;;;;;;;;;;-1:-1:-1;13021:283:0;;;;;:::i;:::-;;:::i;44878:22::-;;;;;;;;;;-1:-1:-1;44878:22:0;;;;;;;;;;;;;2266:25:1;;;2322:2;2307:18;;2300:34;;;;2239:18;44878:22:0;2092:248:1;44274:44:0;;;;;;;;;;-1:-1:-1;44274:44:0;;;;-1:-1:-1;;;;;44274:44:0;;;48441:141;;;;;;;;;;;;;:::i;10840:84::-;;;;;;;;;;-1:-1:-1;10840:84:0;;10914:2;2733:36:1;;2721:2;2706:18;10840:84:0;2591:184:1;44851:20:0;;;;;;;;;;-1:-1:-1;44851:20:0;;;;;;;;;44157:28;;;;;;;;;;-1:-1:-1;44157:28:0;;;;-1:-1:-1;;;;;44157:28:0;;;47278:209;;;;;;;;;;-1:-1:-1;47278:209:0;;;;;:::i;:::-;;:::i;:::-;;11151:118;;;;;;;;;;-1:-1:-1;11151:118:0;;;;;:::i;:::-;-1:-1:-1;;;;;11243:18:0;11216:7;11243:18;;;;;;;;;;;;11151:118;5046:103;;;;;;;;;;;;;:::i;44570:75::-;;;;;;;;;;-1:-1:-1;44570:75:0;;;;-1:-1:-1;;;;;44570:75:0;;;4371:87;;;;;;;;;;-1:-1:-1;4444:6:0;;-1:-1:-1;;;;;4444:6:0;4371:87;;10097:95;;;;;;;;;;;;;:::i;49102:306::-;;;;;;;;;;-1:-1:-1;49102:306:0;;;;;:::i;:::-;;:::i;47607:481::-;;;;;;;;;;;;;:::i;49600:479::-;;;;;;;;;;-1:-1:-1;49600:479:0;;;;;:::i;:::-;;:::i;:::-;;;;3724:25:1;;;3780:2;3765:18;;3758:34;;;;3808:18;;;3801:34;3866:2;3851:18;;3844:34;3711:3;3696:19;49600:479:0;3493:391:1;11474:182:0;;;;;;;;;;-1:-1:-1;11474:182:0;;;;;:::i;:::-;;:::i;48692:302::-;;;;;;;;;;-1:-1:-1;48692:302:0;;;;;:::i;:::-;;:::i;11719:183::-;;;;;;;;;;-1:-1:-1;11719:183:0;;;;;:::i;:::-;;:::i;44483:46::-;;;;;;;;;;;;;;;;48228:124;;;;;;;;;;-1:-1:-1;48228:124:0;;;;;:::i;:::-;;:::i;50145:135::-;;;;;;;;;;;;;:::i;5304:220::-;;;;;;;;;;-1:-1:-1;5304:220:0;;;;;:::i;:::-;;:::i;9887:91::-;9932:13;9965:5;9958:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9887:91;:::o;12221:222::-;12321:4;2701:10;12382:31;2701:10;12398:7;12407:5;12382:8;:31::i;:::-;12431:4;12424:11;;;12221:222;;;;;:::o;13021:283::-;13142:4;2701:10;13200:37;13216:4;2701:10;13231:5;13200:15;:37::i;:::-;13248:26;13258:4;13264:2;13268:5;13248:9;:26::i;:::-;-1:-1:-1;13292:4:0;;13021:283;-1:-1:-1;;;;13021:283:0:o;48441:141::-;48531:15;;:43;;;-1:-1:-1;;;48531:43:0;;;;48504:7;;-1:-1:-1;;;;;48531:15:0;;:41;;:43;;;;;;;;;;;;;;:15;:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;48524:50;;48441:141;:::o;47278:209::-;4257:13;:11;:13::i;:::-;47372:15:::1;::::0;;-1:-1:-1;;;;;47398:24:0;;::::1;-1:-1:-1::0;;;;;;47398:24:0;::::1;::::0;::::1;::::0;;;47438:41:::1;::::0;47372:15;::::1;::::0;;;47438:41:::1;::::0;47352:17:::1;::::0;47438:41:::1;47341:146;47278:209:::0;:::o;5046:103::-;4257:13;:11;:13::i;:::-;5111:30:::1;5138:1;5111:18;:30::i;:::-;5046:103::o:0;10097:95::-;10144:13;10177:7;10170:14;;;;;:::i;49102:306::-;4257:13;:11;:13::i;:::-;49213:2:::1;49192:18;49201:9:::0;49192:6;:18:::1;:::i;:::-;:23;49188:86;;;49239:23;;-1:-1:-1::0;;;49239:23:0::1;;;;;;;;;;;49188:86;49284:7;:26:::0;;;49321:17;:29;;;49366:34:::1;::::0;49341:9;;49304:6;;49366:34:::1;::::0;49284:17:::1;::::0;49366:34:::1;49102:306:::0;;:::o;47607:481::-;47741:15;;:52;;-1:-1:-1;;;47741:52:0;;47782:10;47741:52;;;1387:51:1;47669:4:0;;47653:13;;;;-1:-1:-1;;;;;47741:15:0;;:40;;1360:18:1;;47741:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;47684:109;;;;;;;;;;47808:9;47821:1;47808:14;47804:77;;47846:23;;-1:-1:-1;;;47846:23:0;;;;;;;;;;;47804:77;47913:13;47895:15;:31;47891:94;;;47950:23;;-1:-1:-1;;;47950:23:0;;;;;;;;;;;47891:94;47995:15;;:58;;-1:-1:-1;;;47995:58:0;;48034:10;47995:58;;;6173:51:1;47995:15:0;6240:18:1;;;6233:50;-1:-1:-1;;;;;47995:15:0;;;;:30;;6146:18:1;;47995:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;47607:481:0:o;49600:479::-;50036:15;;:35;;-1:-1:-1;;;50036:35:0;;-1:-1:-1;;;;;1405:32:1;;;50036:35:0;;;1387:51:1;49711:17:0;;;;;;;;50036:15;;:26;;1360:18:1;;50036:35:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;49865:206:0;;;;-1:-1:-1;49865:206:0;-1:-1:-1;49865:206:0;;-1:-1:-1;49600:479:0;-1:-1:-1;;;;;49600:479:0:o;11474:182::-;11543:4;2701:10;11599:27;2701:10;11616:2;11620:5;11599:9;:27::i;48692:302::-;4257:13;:11;:13::i;:::-;48802:2:::1;48781:18;48790:9:::0;48781:6;:18:::1;:::i;:::-;:23;48777:86;;;48828:23;;-1:-1:-1::0;;;48828:23:0::1;;;;;;;;;;;48777:86;48873:6;:25:::0;;;48909:16;:28;;;48953:33:::1;::::0;1595:25:1;;;48873::0;;48953:33:::1;::::0;1583:2:1;1568:18;48953:33:0::1;;;;;;;48692:302:::0;;:::o;11719:183::-;-1:-1:-1;;;;;11867:18:0;;;11835:7;11867:18;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;11719:183::o;48228:124::-;4257:13;:11;:13::i;:::-;48302:15:::1;::::0;:42:::1;::::0;-1:-1:-1;;;48302:42:0;;::::1;::::0;::::1;1595:25:1::0;;;-1:-1:-1;;;;;48302:15:0;;::::1;::::0;:31:::1;::::0;1568:18:1;;48302:42:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;48228:124:::0;:::o;50145:135::-;50231:15;;:41;;;-1:-1:-1;;;50231:41:0;;;;50204:7;;-1:-1:-1;;;;;50231:15:0;;:39;;:41;;;;;;;;;;;;;;:15;:41;;;;;;;;;;;;;;5304:220;4257:13;:11;:13::i;:::-;-1:-1:-1;;;;;5389:22:0;::::1;5385:93;;5435:31;::::0;-1:-1:-1;;;5435:31:0;;5463:1:::1;5435:31;::::0;::::1;1387:51:1::0;1360:18;;5435:31:0::1;;;;;;;;5385:93;5488:28;5507:8;5488:18;:28::i;:::-;5304:220:::0;:::o;17182:164::-;17301:37;17310:5;17317:7;17326:5;17333:4;17301:8;:37::i;:::-;17182:164;;;:::o;18975:603::-;19109:24;19136:25;19146:5;19153:7;19136:9;:25::i;:::-;19109:52;;-1:-1:-1;;19176:16:0;:37;19172:399;;19253:5;19234:16;:24;19230:214;;;19286:142;;-1:-1:-1;;;19286:142:0;;-1:-1:-1;;;;;6796:32:1;;19286:142:0;;;6778:51:1;6845:18;;;6838:34;;;6888:18;;;6881:34;;;6751:18;;19286:142:0;6576:345:1;19230:214:0;19487:57;19496:5;19503:7;19531:5;19512:16;:24;19538:5;19487:8;:57::i;13689:342::-;-1:-1:-1;;;;;13807:18:0;;13803:88;;13849:30;;-1:-1:-1;;;13849:30:0;;13876:1;13849:30;;;1387:51:1;1360:18;;13849:30:0;1215:229:1;13803:88:0;-1:-1:-1;;;;;13905:16:0;;13901:88;;13945:32;;-1:-1:-1;;;13945:32:0;;13974:1;13945:32;;;1387:51:1;1360:18;;13945:32:0;1215:229:1;13901:88:0;13999:24;14007:4;14013:2;14017:5;13999:7;:24::i;4536:166::-;4444:6;;-1:-1:-1;;;;;4444:6:0;2701:10;4596:23;4592:103;;4643:40;;-1:-1:-1;;;4643:40:0;;2701:10;4643:40;;;1387:51:1;1360:18;;4643:40:0;1215:229:1;5684:191:0;5777:6;;;-1:-1:-1;;;;;5794:17:0;;;-1:-1:-1;;;;;;5794:17:0;;;;;;;5827:40;;5777:6;;;5794:17;5777:6;;5827:40;;5758:16;;5827:40;5747:128;5684:191;:::o;18197:486::-;-1:-1:-1;;;;;18353:19:0;;18349:91;;18396:32;;-1:-1:-1;;;18396:32:0;;18425:1;18396:32;;;1387:51:1;1360:18;;18396:32:0;1215:229:1;18349:91:0;-1:-1:-1;;;;;18454:21:0;;18450:92;;18499:31;;-1:-1:-1;;;18499:31:0;;18527:1;18499:31;;;1387:51:1;1360:18;;18499:31:0;1215:229:1;18450:92:0;-1:-1:-1;;;;;18552:18:0;;;;;;;:11;:18;;;;;;;;:27;;;;;;;;;:35;;;18598:78;;;;18649:7;-1:-1:-1;;;;;18633:31:0;18642:5;-1:-1:-1;;;;;18633:31:0;;18658:5;18633:31;;;;1595:25:1;;1583:2;1568:18;;1449:177;18633:31:0;;;;;;;;18197:486;;;;:::o;50380:1873::-;50506:6;50516:1;50506:11;50502:91;;50534:26;50548:4;50554:2;50558:1;50534:13;:26::i;50502:91::-;50654:4;50605:28;11243:18;;;;;;;;;;;50712;;50688:42;;;;;;;50761:33;;-1:-1:-1;50786:8:0;;-1:-1:-1;;;50786:8:0;;;;50785:9;50761:33;:71;;;;-1:-1:-1;50819:13:0;;-1:-1:-1;;;;;50811:21:0;;;50819:13;;50811:21;;50761:71;:103;;;;-1:-1:-1;4444:6:0;;-1:-1:-1;;;;;50849:15:0;;;4444:6;;50849:15;;50761:103;:133;;;;-1:-1:-1;4444:6:0;;-1:-1:-1;;;;;50881:13:0;;;4444:6;;50881:13;;50761:133;50743:291;;;50921:8;:15;;-1:-1:-1;;;;50921:15:0;-1:-1:-1;;;50921:15:0;;;50953:36;50968:20;50953:14;:36::i;:::-;51006:8;:16;;-1:-1:-1;;;;51006:16:0;;;50743:291;51062:8;;-1:-1:-1;;;;;51357:25:0;;51046:12;51357:25;;;:19;:25;;;;;;51062:8;-1:-1:-1;;;51062:8:0;;;;;51061:9;;51357:25;;:52;;-1:-1:-1;;;;;;51386:23:0;;;;;;:19;:23;;;;;;;;51357:52;51353:100;;;-1:-1:-1;51436:5:0;51353:100;51469:7;51465:549;;;51581:13;;51493:12;;-1:-1:-1;;;;;51581:13:0;;;51573:21;;;;51569:123;;51652:6;:16;51633;;51673:3;;51633:35;;;:::i;:::-;51623:46;;:6;:46;:::i;:::-;51622:54;;;;:::i;:::-;51615:61;;51569:123;51748:13;;-1:-1:-1;;;;;51748:13:0;;;51742:19;;;;51738:123;;51820:7;:17;51800;;51842:3;;51800:37;;;:::i;:::-;51790:48;;:6;:48;:::i;:::-;51789:56;;;;:::i;:::-;51782:63;;51738:123;51886:13;51895:4;51886:6;:13;:::i;:::-;51877:22;-1:-1:-1;51918:8:0;;51914:89;;51947:40;51961:4;51975;51982;51947:13;:40::i;:::-;51478:536;51465:549;52026:31;52040:4;52046:2;52050:6;52026:13;:31::i;:::-;52087:15;;-1:-1:-1;;;;;52087:15:0;:26;52122:4;52129:15;52122:4;-1:-1:-1;;;;;11243:18:0;11216:7;11243:18;;;;;;;;;;;;11151:118;52129:15;52087:58;;-1:-1:-1;;;;;;52087:58:0;;;;;;;-1:-1:-1;;;;;7662:32:1;;;52087:58:0;;;7644:51:1;7711:18;;;7704:34;7617:18;;52087:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52070:96;52180:15;;-1:-1:-1;;;;;52180:15:0;:26;52215:2;52220:13;52215:2;-1:-1:-1;;;;;11243:18:0;11216:7;11243:18;;;;;;;;;;;;11151:118;52220:13;52180:54;;-1:-1:-1;;;;;;52180:54:0;;;;;;;-1:-1:-1;;;;;7662:32:1;;;52180:54:0;;;7644:51:1;7711:18;;;7704:34;7617:18;;52180:54:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52176:70;50491:1762;;;50380:1873;;;:::o;14355:1169::-;-1:-1:-1;;;;;14479:18:0;;14475:552;;14633:5;14617:12;;:21;;;;;;;:::i;:::-;;;;-1:-1:-1;14475:552:0;;-1:-1:-1;14475:552:0;;-1:-1:-1;;;;;14693:15:0;;14671:19;14693:15;;;;;;;;;;;14727:19;;;14723:117;;;14774:50;;-1:-1:-1;;;14774:50:0;;-1:-1:-1;;;;;6796:32:1;;14774:50:0;;;6778:51:1;6845:18;;;6838:34;;;6888:18;;;6881:34;;;6751:18;;14774:50:0;6576:345:1;14723:117:0;-1:-1:-1;;;;;14963:15:0;;:9;:15;;;;;;;;;;14981:19;;;;14963:37;;14475:552;-1:-1:-1;;;;;15043:16:0;;15039:435;;15209:12;:21;;;;;;;15039:435;;;-1:-1:-1;;;;;15425:13:0;;:9;:13;;;;;;;;;;:22;;;;;;15039:435;15506:2;-1:-1:-1;;;;;15491:25:0;15500:4;-1:-1:-1;;;;;15491:25:0;;15510:5;15491:25;;;;1595::1;;1583:2;1568:18;;1449:177;15491:25:0;;;;;;;;14355:1169;;;:::o;52377:1275::-;52461:21;52527:24;52544:6;52527:16;:24::i;:::-;52612:18;52633:38;52657:14;52633:21;:38;:::i;:::-;52799:7;:17;52766;;52734:6;:16;52702;;52612:59;;-1:-1:-1;52682:17:0;;52702:48;;52734:16;52702:48;:::i;:::-;:81;;;;:::i;:::-;:114;;;;:::i;:::-;52682:134;-1:-1:-1;52831:13:0;;52827:818;;52936:17;;52917:16;;52861:21;;52958:9;;52917:36;;52936:17;52917:36;:::i;:::-;52886:68;;:10;:68;:::i;:::-;52885:82;;;;:::i;:::-;53014:15;;52861:106;;-1:-1:-1;52983:9:0;;-1:-1:-1;;;;;53014:15:0;53062:26;52861:106;53062:10;:26;:::i;:::-;52998:109;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;53147:15:0;;53139:95;;52982:125;;-1:-1:-1;53123:10:0;;-1:-1:-1;;;;;53147:15:0;;;;53194:21;;53123:10;53139:95;53123:10;53139:95;53194:21;53147:15;53139:95;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53122:112;;;53253:4;:13;;;;53261:5;53253:13;53249:206;;;53292:147;53329:6;53358:13;53394:26;53358:13;53394:10;:26;:::i;:::-;53292:147;;;8161:25:1;;;8217:2;8202:18;;8195:34;;;;8245:18;;;8238:34;8149:2;8134:18;53292:147:0;;;;;;;53249:206;52846:620;;;52827:818;;;53532:15;;53516:104;;53488:6;;-1:-1:-1;;;;;53532:15:0;;53580:21;;53488:6;53516:104;53488:6;53516:104;53580:21;53532:15;53516:104;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;52425:1227:0;;;52377:1275;:::o;53701:848::-;53851:16;;;53865:1;53851:16;;;;;;;;53827:21;;53851:16;;;;;;;;;;-1:-1:-1;53851:16:0;53827:40;;53896:4;53878;53883:1;53878:7;;;;;;;;:::i;:::-;-1:-1:-1;;;;;53878:23:0;;;:7;;;;;;;;;;:23;;;;53922:15;;:22;;;-1:-1:-1;;;53922:22:0;;;;:15;;;;;:20;;:22;;;;;53878:7;;53922:22;;;;;:15;:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;53912:4;53917:1;53912:7;;;;;;;;:::i;:::-;-1:-1:-1;;;;;53912:32:0;;;:7;;;;;;;;;:32;53969:15;;:48;;-1:-1:-1;;;53969:48:0;;53955:11;;53969:15;;;;;:29;;:48;;53999:11;;54012:4;;53969:48;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;53969:48:0;;;;;;;;;;;;:::i;:::-;54018:1;53969:51;;;;;;;;:::i;:::-;;;;;;;53955:65;;54088:11;54035:50;54053:4;54068:15;;;;;;;;;-1:-1:-1;;;;;54068:15:0;54035:9;:50::i;:::-;:64;54031:231;;;54183:15;;54116:134;;54151:4;;-1:-1:-1;;;;;54183:15:0;-1:-1:-1;;54116:8:0;:134::i;:::-;54300:15;;-1:-1:-1;;;;;54300:15:0;:66;54381:11;54428:3;54408:16;:3;54415:8;54408:16;:::i;:::-;54407:24;;;;:::i;:::-;54462:4;54489;54509:21;:15;54527:3;54509:21;:::i;:::-;54300:241;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14:548:1;126:4;155:2;184;173:9;166:21;216:6;210:13;259:6;254:2;243:9;239:18;232:34;284:1;294:140;308:6;305:1;302:13;294:140;;;403:14;;;399:23;;393:30;369:17;;;388:2;365:26;358:66;323:10;;294:140;;;298:3;483:1;478:2;469:6;458:9;454:22;450:31;443:42;553:2;546;542:7;537:2;529:6;525:15;521:29;510:9;506:45;502:54;494:62;;;;14:548;;;;:::o;567:131::-;-1:-1:-1;;;;;642:31:1;;632:42;;622:70;;688:1;685;678:12;703:315;771:6;779;832:2;820:9;811:7;807:23;803:32;800:52;;;848:1;845;838:12;800:52;887:9;874:23;906:31;931:5;906:31;:::i;:::-;956:5;1008:2;993:18;;;;980:32;;-1:-1:-1;;;703:315:1:o;1631:456::-;1708:6;1716;1724;1777:2;1765:9;1756:7;1752:23;1748:32;1745:52;;;1793:1;1790;1783:12;1745:52;1832:9;1819:23;1851:31;1876:5;1851:31;:::i;:::-;1901:5;-1:-1:-1;1958:2:1;1943:18;;1930:32;1971:33;1930:32;1971:33;:::i;:::-;1631:456;;2023:7;;-1:-1:-1;;;2077:2:1;2062:18;;;;2049:32;;1631:456::o;2988:247::-;3047:6;3100:2;3088:9;3079:7;3075:23;3071:32;3068:52;;;3116:1;3113;3106:12;3068:52;3155:9;3142:23;3174:31;3199:5;3174:31;:::i;:::-;3224:5;2988:247;-1:-1:-1;;;2988:247:1:o;3240:248::-;3308:6;3316;3369:2;3357:9;3348:7;3344:23;3340:32;3337:52;;;3385:1;3382;3375:12;3337:52;-1:-1:-1;;3408:23:1;;;3478:2;3463:18;;;3450:32;;-1:-1:-1;3240:248:1:o;3889:388::-;3957:6;3965;4018:2;4006:9;3997:7;3993:23;3989:32;3986:52;;;4034:1;4031;4024:12;3986:52;4073:9;4060:23;4092:31;4117:5;4092:31;:::i;:::-;4142:5;-1:-1:-1;4199:2:1;4184:18;;4171:32;4212:33;4171:32;4212:33;:::i;:::-;4264:7;4254:17;;;3889:388;;;;;:::o;4282:180::-;4341:6;4394:2;4382:9;4373:7;4369:23;4365:32;4362:52;;;4410:1;4407;4400:12;4362:52;-1:-1:-1;4433:23:1;;4282:180;-1:-1:-1;4282:180:1:o;4467:380::-;4546:1;4542:12;;;;4589;;;4610:61;;4664:4;4656:6;4652:17;4642:27;;4610:61;4717:2;4709:6;4706:14;4686:18;4683:38;4680:161;;4763:10;4758:3;4754:20;4751:1;4744:31;4798:4;4795:1;4788:15;4826:4;4823:1;4816:15;4680:161;;4467:380;;;:::o;4852:184::-;4922:6;4975:2;4963:9;4954:7;4950:23;4946:32;4943:52;;;4991:1;4988;4981:12;4943:52;-1:-1:-1;5014:16:1;;4852:184;-1:-1:-1;4852:184:1:o;5041:127::-;5102:10;5097:3;5093:20;5090:1;5083:31;5133:4;5130:1;5123:15;5157:4;5154:1;5147:15;5173:125;5238:9;;;5259:10;;;5256:36;;;5272:18;;:::i;5303:681::-;5434:6;5442;5450;5458;5466;5474;5482;5490;5543:3;5531:9;5522:7;5518:23;5514:33;5511:53;;;5560:1;5557;5550:12;5511:53;5592:9;5586:16;5611:31;5636:5;5611:31;:::i;:::-;5661:5;5651:15;;;5706:2;5695:9;5691:18;5685:25;5675:35;;5750:2;5739:9;5735:18;5729:25;5719:35;;5794:2;5783:9;5779:18;5773:25;5763:35;;5838:3;5827:9;5823:19;5817:26;5807:36;;5883:3;5872:9;5868:19;5862:26;5852:36;;5928:3;5917:9;5913:19;5907:26;5897:36;;5973:3;5962:9;5958:19;5952:26;5942:36;;5303:681;;;;;;;;;;;:::o;6294:277::-;6361:6;6414:2;6402:9;6393:7;6389:23;6385:32;6382:52;;;6430:1;6427;6420:12;6382:52;6462:9;6456:16;6515:5;6508:13;6501:21;6494:5;6491:32;6481:60;;6537:1;6534;6527:12;6926:168;6999:9;;;7030;;7047:15;;;7041:22;;7027:37;7017:71;;7068:18;;:::i;7099:217::-;7139:1;7165;7155:132;;7209:10;7204:3;7200:20;7197:1;7190:31;7244:4;7241:1;7234:15;7272:4;7269:1;7262:15;7155:132;-1:-1:-1;7301:9:1;;7099:217::o;7321:128::-;7388:9;;;7409:11;;;7406:37;;;7423:18;;:::i;8283:127::-;8344:10;8339:3;8335:20;8332:1;8325:31;8375:4;8372:1;8365:15;8399:4;8396:1;8389:15;8415:127;8476:10;8471:3;8467:20;8464:1;8457:31;8507:4;8504:1;8497:15;8531:4;8528:1;8521:15;8547:251;8617:6;8670:2;8658:9;8649:7;8645:23;8641:32;8638:52;;;8686:1;8683;8676:12;8638:52;8718:9;8712:16;8737:31;8762:5;8737:31;:::i;8803:461::-;8856:3;8894:5;8888:12;8921:6;8916:3;8909:19;8947:4;8976:2;8971:3;8967:12;8960:19;;9013:2;9006:5;9002:14;9034:1;9044:195;9058:6;9055:1;9052:13;9044:195;;;9123:13;;-1:-1:-1;;;;;9119:39:1;9107:52;;9179:12;;;;9214:15;;;;9155:1;9073:9;9044:195;;;-1:-1:-1;9255:3:1;;8803:461;-1:-1:-1;;;;;8803:461:1:o;9269:332::-;9476:6;9465:9;9458:25;9519:2;9514;9503:9;9499:18;9492:30;9439:4;9539:56;9591:2;9580:9;9576:18;9568:6;9539:56;:::i;:::-;9531:64;9269:332;-1:-1:-1;;;;9269:332:1:o;9606:1105::-;9701:6;9732:2;9775;9763:9;9754:7;9750:23;9746:32;9743:52;;;9791:1;9788;9781:12;9743:52;9824:9;9818:16;9853:18;9894:2;9886:6;9883:14;9880:34;;;9910:1;9907;9900:12;9880:34;9948:6;9937:9;9933:22;9923:32;;9993:7;9986:4;9982:2;9978:13;9974:27;9964:55;;10015:1;10012;10005:12;9964:55;10044:2;10038:9;10066:2;10062;10059:10;10056:36;;;10072:18;;:::i;:::-;10118:2;10115:1;10111:10;10150:2;10144:9;10213:2;10209:7;10204:2;10200;10196:11;10192:25;10184:6;10180:38;10268:6;10256:10;10253:22;10248:2;10236:10;10233:18;10230:46;10227:72;;;10279:18;;:::i;:::-;10315:2;10308:22;10365:18;;;10399:15;;;;-1:-1:-1;10441:11:1;;;10437:20;;;10469:19;;;10466:39;;;10501:1;10498;10491:12;10466:39;10525:11;;;;10545:135;10561:6;10556:3;10553:15;10545:135;;;10627:10;;10615:23;;10578:12;;;;10658;;;;10545:135;;;10699:6;9606:1105;-1:-1:-1;;;;;;;;9606:1105:1:o;10716:574::-;11007:6;10996:9;10989:25;11050:6;11045:2;11034:9;11030:18;11023:34;11093:3;11088:2;11077:9;11073:18;11066:31;10970:4;11114:57;11166:3;11155:9;11151:19;11143:6;11114:57;:::i;:::-;-1:-1:-1;;;;;11207:32:1;;;;11202:2;11187:18;;11180:60;-1:-1:-1;11271:3:1;11256:19;11249:35;11106:65;10716:574;-1:-1:-1;;;10716:574:1:o

Swarm Source

ipfs://0589d0e5c32d8c73f9ad1e9b97102c0d9415a29951bd0fdaad32d6040b68e365
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.