ETH Price: $3,324.54 (+2.46%)

FED404 (FED404)
 

Overview

TokenID

965

Total Transfers

-

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

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:
FED

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 7 : FED.sol
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "./Interfaces.sol";
import "./ERC404.sol";

contract FED is ERC404, ReentrancyGuard {
    struct User {
        uint256 balance;
        uint256 lastClaim;
        uint256 rewards;
    }

    string public dataURI;
    string public baseTokenURI;

    address public routerAddress = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
    address public WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    address public pair;
    IUniswapV2Router02 public router;

    uint256 private divisor = 10_000;
    uint256 public fees = 500;

    bool public launched;
    bool public mintEnabled = true;

    uint256 public baseRewardRate = 1200;
    uint256 public rareRewardRate = 2000;

    mapping(address => User) public users;
    mapping(address => bool) public rewardsBlacklist;
    mapping(address => bool) public isFeesExempt;

    event ClaimedSale(address indexed account, uint256 amount);
    event ClaimedRewards(address indexed account, uint256 amount);
    event Launched(bool launched);
    event MintEnabled(bool mintEnabled);
    event DataURIUpdated(string dataURI);
    event BaseURIUpdated(string baseURI);
    event FeesUpdated(uint256 fees);
    event RewardRatesUpdated(uint256 baseRewardRate, uint256 rareRewardRate);
    event RewardsBlacklistUpdated(address account, bool value);
    event FeesExemptUpdated(address account, bool value);

    constructor() ERC404("FED404", "FED404", msg.sender) {
        router = IUniswapV2Router02(routerAddress);
        pair = IUniswapV2Factory(router.factory()).createPair(address(this), WETH);

        setDataURI("https://raw.githubusercontent.com/fed4O4/fed404_img/main/");

        setFeesExempt(msg.sender, true);
        setFeesExempt(address(this), true);
        setFeesExempt(routerAddress, true);
        setFeesExempt(address(0), true);
        setFeesExempt(address(this), true);

        setRewardsBlacklist(address(this), true);
        setRewardsBlacklist(routerAddress, true);
        setRewardsBlacklist(address(0), true);
        setRewardsBlacklist(router.factory(), true);
        setRewardsBlacklist(0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD, true);
        setRewardsBlacklist(address(pair), true);

        setWhitelist(msg.sender, true);
        setWhitelist(address(this), true);
        setWhitelist(routerAddress, true);
        setWhitelist(address(0), true);
        setWhitelist(router.factory(), true);
        setWhitelist(0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD, true);
        setWhitelist(address(pair), true);

        mint(msg.sender, 353.8 * 1e18);
    }

    mapping(address => uint256) public airdrop;

    function setAirdrop(address[] calldata _users, uint256[] calldata _amounts) external onlyOwner {
        require(_users.length == _amounts.length, "Invalid input");

        for (uint256 i = 0; i < _users.length; i++) {
            airdrop[_users[i]] = _amounts[i];
        }
    }

    function claimAirdrop() external {
        require(airdrop[msg.sender] > 0, "No airdrop to claim");
        uint256 amount = airdrop[msg.sender];
        airdrop[msg.sender] = 0;
        mint(msg.sender, amount);
    }

    // -- Owner functions -- //

    function setFeesExempt(address account, bool value) public onlyOwner {
        isFeesExempt[account] = value;
        emit FeesExemptUpdated(account, value);
    }

    function setRewardsBlacklist(address account, bool value) public onlyOwner {
        rewardsBlacklist[account] = value;
        emit RewardsBlacklistUpdated(account, value);
    }

    function setRewardRates(uint256 _baseRewardRate, uint256 _rareRewardRate) public onlyOwner {
        require(_baseRewardRate <= 5000, "Base reward rate too high");
        require(_rareRewardRate <= 10000, "Rare reward rate too high");
        baseRewardRate = _baseRewardRate;
        rareRewardRate = _rareRewardRate;
        emit RewardRatesUpdated(_baseRewardRate, _rareRewardRate);
    }

    function setFees(uint256 _fees) external onlyOwner {
        require(_fees <= 1000, "Fees too high");
        fees = _fees;
        emit FeesUpdated(_fees);
    }

    function launch() external onlyOwner {
        require(!launched, "Already launched");
        launched = true;
        emit Launched(launched);
    }

    function setMint(bool _mintEnabled) external onlyOwner {
        mintEnabled = _mintEnabled;
        emit MintEnabled(_mintEnabled);
    }

    function setDataURI(string memory _dataURI) public onlyOwner {
        dataURI = _dataURI;
        emit DataURIUpdated(_dataURI);
    }

    function setTokenURI(string memory _tokenURI) external onlyOwner {
        baseTokenURI = _tokenURI;
        emit BaseURIUpdated(_tokenURI);
    }

    // -- View functions -- //
    /// @dev rewards that can be claimed by user
    function claimableRewards(address account) public view returns (uint256) {
        uint256 pending = pendingRewards(account);
        return users[account].rewards + pending;
    }

    function feesValue(address from, address to, uint256 amount) public view returns (uint256) {
        if (isFeesExempt[from] || isFeesExempt[to]) return 0;
        uint256 f = (amount * fees) / divisor;
        return f;
    }

    /// @dev rewards accumalated between last claim and current block
    /// lastClaim 0 means users own less than 1 FED
    function pendingRewards(address account) public view returns (uint256) {
        if (!mintEnabled) return 0;

        if (users[account].lastClaim == 0) return 0;

        uint256 timeSinceLastClaim = block.timestamp - users[account].lastClaim;

        uint256 rareCount = rareOwned(account);

        uint256 claimable = 0;

        if (rareCount >= 1) {
            claimable += (balanceOf[account] * ((timeSinceLastClaim * rareRewardRate) / 1 days) / divisor);
        } else {
            claimable += (balanceOf[account] * ((timeSinceLastClaim * baseRewardRate) / 1 days) / divisor);
        }

        return claimable;
    }

    function tokenURI(uint256 id) public view override returns (string memory) {
        if (bytes(baseTokenURI).length > 0) {
            return string.concat(baseTokenURI, Strings.toString(id));
        } else {
            uint8 seed = uint8(bytes1(keccak256(abi.encodePacked(id))));
            string memory image;
            string memory rarity;

            if (seed <= 3) {
                image = getRareImage(id);
                rarity = "Rare";
                // Common
            } else if (seed <= 15) {
                image = "1.gif";
                rarity = "Common";
            } else if (seed <= 27) {
                image = "2.gif";
                rarity = "Common";
            } else if (seed <= 39) {
                image = "3.gif";
                rarity = "Common";
            } else if (seed <= 51) {
                image = "4.gif";
                rarity = "Common";
            } else if (seed <= 63) {
                image = "5.gif";
                rarity = "Common";
            } else if (seed <= 75) {
                image = "6.gif";
                rarity = "Common";
            } else if (seed <= 87) {
                image = "7.gif";
                rarity = "Common";
            } else if (seed <= 99) {
                image = "8.gif";
                rarity = "Common";
            } else if (seed <= 111) {
                image = "9.gif";
                rarity = "Common";
            } else if (seed <= 123) {
                image = "10.gif";
                rarity = "Common";
            } else if (seed <= 135) {
                image = "11.gif";
                rarity = "Common";
            } else if (seed <= 147) {
                image = "12.gif";
                rarity = "Common";
            } else if (seed <= 159) {
                image = "13.gif";
                rarity = "Common";
            } else if (seed <= 171) {
                image = "14.gif";
                rarity = "Common";
            } else if (seed <= 183) {
                image = "15.gif";
                rarity = "Common";
            } else if (seed <= 195) {
                image = "16.gif";
                rarity = "Common";
            } else if (seed <= 207) {
                image = "17.gif";
                rarity = "Common";
            } else if (seed <= 219) {
                image = "18.gif";
                rarity = "Common";
            } else if (seed <= 231) {
                image = "19.gif";
                rarity = "Common";
            } else if (seed <= 243) {
                image = "20.gif";
                rarity = "Common";
            } else if (seed <= 255) {
                image = "21.gif";
                rarity = "Common";
            }

            string memory jsonPreImage = string.concat(
                string.concat(
                    string.concat('{"name": "FED #', Strings.toString(id)),
                    '","description":"An experimental printer based on ERC404.","external_url":"https://fed404.xyz","image":"'
                ),
                string.concat(dataURI, image)
            );
            string memory jsonPostImage = string.concat('","attributes":[{"trait_type":"Rarity","value":"', rarity);
            string memory jsonPostTraits = '"}]}';

            return string.concat(
                "data:application/json;utf8,", string.concat(string.concat(jsonPreImage, jsonPostImage), jsonPostTraits)
            );
        }
    }

    function getIdsOwnedBy(address owner) public view returns (uint256[] memory) {
        return _owned[owner];
    }

    function rareOwned(address account) public view returns (uint256) {
        uint256[] memory ids = getIdsOwnedBy(account);
        uint256 rareCount = 0;
        for (uint256 i = 0; i < ids.length; i++) {
            if (isRare(ids[i])) rareCount++;
        }
        return rareCount;
    }

    function isRare(uint256 id) public pure returns (bool) {
        uint8 seed = uint8(bytes1(keccak256(abi.encodePacked(id))));
        return seed <= 3;
    }

    function getRareImage(uint256 id) public pure returns (string memory) {
        require(isRare(id), "Not rare");

        uint8 seed = uint8(bytes1(keccak256(abi.encodePacked(id))));
        uint8 seedOfSeed = uint8(bytes1(keccak256(abi.encodePacked(seed))));

        string memory image;

        if (seedOfSeed <= 85) {
            image = "rare/rare_1.gif";
        } else if (seedOfSeed <= 170) {
            image = "rare/rare_2.gif";
        } else if (seedOfSeed <= 255) {
            image = "rare/rare_3.gif";
        }

        return image;
    }

    // -- User functions -- //

    function claim() public nonReentrant {
        _update(msg.sender);
        require(users[msg.sender].rewards > 0, "No rewards to claim");
        uint256 claimable = users[msg.sender].rewards;
        users[msg.sender].rewards = 0;
        users[msg.sender].lastClaim = block.timestamp;

        mint(msg.sender, claimable);

        emit ClaimedRewards(msg.sender, claimable);
    }

    function transferFrom(address from, address to, uint256 amountOrId) public override {
        _beforeTokenTransfer(from, to, amountOrId);
        return super.transferFrom(from, to, amountOrId);
    }

    // -- Internal/private functions -- //

    /// @dev update lastClaim of from and to
    function _beforeTokenTransfer(address from, address to, uint256 amountOrId) internal {
        if (!rewardsBlacklist[from]) {
            _update(from);
            // If new balance of from is less than 1 FED, reset lastClaim to stop rewards
            if (balanceOf[from] - amountOrId < 1e18) users[from].lastClaim = 0;
        } else if (!rewardsBlacklist[to]) {
            _update(to);
            // If new balance of to is greater than or equal to 1 FED, start rewards
            if (balanceOf[to] + amountOrId >= 1e18) users[to].lastClaim = block.timestamp;
        }
    }

    /// @dev proccess minting to address(this), then transfer to user. Allowing conversion in ERC721 if possible through ERC404._transfer
    function mint(address to, uint256 amount) private {
        require(mintEnabled, "Minting is disabled");
        if (balanceOf[to] + amount >= 1e18) users[to].lastClaim = block.timestamp;

        balanceOf[address(this)] += amount;
        totalSupply += amount;

        _transfer(address(this), to, amount);
    }

    function _swap() internal {
        uint256 balance = balanceOf[address(this)];
        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = WETH;
        approve(address(router), balance);
        router.swapExactTokensForETHSupportingFeeOnTransferTokens(balance, 0, path, owner, block.timestamp + 1000);
    }

    /// @dev increment users[account].rewards by pendingReward
    function _update(address account) internal {
        if (rewardsBlacklist[account]) return;

        if (users[account].lastClaim != 0) {
            users[account].rewards += pendingRewards(account);
            users[account].lastClaim = block.timestamp;
        } else {
            return;
        }
    }

    function _transfer(address from, address to, uint256 amount) internal override returns (bool) {
        _beforeTokenTransfer(from, to, amount);

        if (isFeesExempt[from] || isFeesExempt[to]) return super._transfer(from, to, amount);

        /// @dev Only allow transfer after launch.
        require(launched, "Not launched yet");

        uint256 feesCharged;

        if (from == pair || to == pair) feesCharged = feesValue(from, to, amount);

        if (feesCharged > 0) super._transfer(from, address(this), feesCharged);

        if (from != pair) _swap();

        return super._transfer(from, to, amount - feesCharged);
    }

    receive() external payable {
        payable(owner).transfer(msg.value);
    }
}

File 2 of 7 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant HEX_DIGITS = "0123456789abcdef";
    uint8 private constant ADDRESS_LENGTH = 20;

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toStringSigned(int256 value) internal pure returns (string memory) {
        return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        uint256 localValue = value;
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = HEX_DIGITS[localValue & 0xf];
            localValue >>= 4;
        }
        if (localValue != 0) {
            revert StringsInsufficientHexLength(value, length);
        }
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
     * representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

File 3 of 7 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

File 4 of 7 : Interfaces.sol
/**
 * Submitted for verification at Etherscan.io on 2020-06-05
 */
pragma solidity ^0.8.0;

interface IUniswapV2Factory {
    event PairCreated(address indexed token0, address indexed token1, address pair, uint256);

    function feeTo() external view returns (address);
    function feeToSetter() external view returns (address);

    function getPair(address tokenA, address tokenB) external view returns (address pair);
    function allPairs(uint256) external view returns (address pair);
    function allPairsLength() external view returns (uint256);

    function createPair(address tokenA, address tokenB) external returns (address pair);

    function setFeeTo(address) external;
    function setFeeToSetter(address) external;
}

interface IUniswapV2Pair {
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event Transfer(address indexed from, address indexed to, uint256 value);

    function name() external pure returns (string memory);
    function symbol() external pure returns (string memory);
    function decimals() external pure returns (uint8);
    function totalSupply() external view returns (uint256);
    function balanceOf(address owner) external view returns (uint256);
    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 value) external returns (bool);
    function transfer(address to, uint256 value) external returns (bool);
    function transferFrom(address from, address to, uint256 value) external returns (bool);

    function DOMAIN_SEPARATOR() external view returns (bytes32);
    function PERMIT_TYPEHASH() external pure returns (bytes32);
    function nonces(address owner) external view returns (uint256);

    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
        external;

    event Mint(address indexed sender, uint256 amount0, uint256 amount1);
    event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);
    event Swap(
        address indexed sender,
        uint256 amount0In,
        uint256 amount1In,
        uint256 amount0Out,
        uint256 amount1Out,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

    function MINIMUM_LIQUIDITY() external pure returns (uint256);
    function factory() external view returns (address);
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
    function price0CumulativeLast() external view returns (uint256);
    function price1CumulativeLast() external view returns (uint256);
    function kLast() external view returns (uint256);

    function mint(address to) external returns (uint256 liquidity);
    function burn(address to) external returns (uint256 amount0, uint256 amount1);
    function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;
    function skim(address to) external;
    function sync() external;

    function initialize(address, address) external;
}

interface IUniswapV2Router01 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);
    function addLiquidityETH(
        address token,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB);
    function removeLiquidityETH(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountToken, uint256 amountETH);
    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountA, uint256 amountB);
    function removeLiquidityETHWithPermit(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountToken, uint256 amountETH);
    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);
    function swapTokensForExactTokens(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);
    function swapExactETHForTokens(uint256 amountOutMin, address[] calldata path, address to, uint256 deadline)
        external
        payable
        returns (uint256[] memory amounts);
    function swapTokensForExactETH(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);
    function swapExactTokensForETH(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);
    function swapETHForExactTokens(uint256 amountOut, address[] calldata path, address to, uint256 deadline)
        external
        payable
        returns (uint256[] memory amounts);

    function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB);
    function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut)
        external
        pure
        returns (uint256 amountOut);
    function getAmountIn(uint256 amountOut, uint256 reserveIn, uint256 reserveOut)
        external
        pure
        returns (uint256 amountIn);
    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);
}

interface IUniswapV2Router02 is IUniswapV2Router01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountETH);
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external;
    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;
}

interface IERC20 {
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event Transfer(address indexed from, address indexed to, uint256 value);

    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
    function totalSupply() external view returns (uint256);
    function balanceOf(address owner) external view returns (uint256);
    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 value) external returns (bool);
    function transfer(address to, uint256 value) external returns (bool);
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

interface IWETH {
    function deposit() external payable;
    function transfer(address to, uint256 value) external returns (bool);
    function withdraw(uint256) external;
}

File 5 of 7 : ERC404.sol
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

abstract contract Ownable {
    event OwnershipTransferred(address indexed user, address indexed newOwner);

    error Unauthorized();
    error InvalidOwner();

    address public owner;

    modifier onlyOwner() virtual {
        if (msg.sender != owner) revert Unauthorized();

        _;
    }

    constructor(address _owner) {
        if (_owner == address(0)) revert InvalidOwner();

        owner = _owner;

        emit OwnershipTransferred(address(0), _owner);
    }

    function transferOwnership(address _owner) public virtual onlyOwner {
        if (_owner == address(0)) revert InvalidOwner();

        owner = _owner;

        emit OwnershipTransferred(msg.sender, _owner);
    }

    function revokeOwnership() public virtual onlyOwner {
        owner = address(0);

        emit OwnershipTransferred(msg.sender, address(0));
    }
}

abstract contract ERC721Receiver {
    function onERC721Received(address, address, uint256, bytes calldata) external virtual returns (bytes4) {
        return ERC721Receiver.onERC721Received.selector;
    }
}

/// @notice ERC404
///         A gas-efficient, mixed ERC20 / ERC721 implementation
///         with native liquidity and fractionalization.
///
///         This is an experimental standard designed to integrate
///         with pre-existing ERC20 / ERC721 support as smoothly as
///         possible.
///
/// @dev    In order to support full functionality of ERC20 and ERC721
///         supply assumptions are made that slightly constraint usage.
///         Ensure decimals are sufficiently large (standard 18 recommended)
///         as ids are effectively encoded in the lowest range of amounts.
///
///         NFTs are spent on ERC20 functions in a FILO queue, this is by
///         design.
///
abstract contract ERC404 is Ownable {
    // Events
    event ERC20Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed spender, uint256 amount);
    event Transfer(address indexed from, address indexed to, uint256 indexed id);
    event ERC721Approval(address indexed owner, address indexed spender, uint256 indexed id);
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    // Errors
    error NotFound();
    error AlreadyExists();
    error InvalidRecipient();
    error InvalidSender();
    error UnsafeRecipient();

    // Metadata
    /// @dev Token name
    string public name;

    /// @dev Token symbol
    string public symbol;

    /// @dev Decimals for fractional representation
    uint8 public immutable decimals;

    /// @dev Total supply in fractionalized representation
    uint256 public totalSupply;

    /// @dev Current mint counter, monotonically increasing to ensure accurate ownership
    uint256 public minted;

    // Mappings
    /// @dev Balance of user in fractional representation
    mapping(address => uint256) public balanceOf;

    /// @dev Allowance of user in fractional representation
    mapping(address => mapping(address => uint256)) public allowance;

    /// @dev Approval in native representaion
    mapping(uint256 => address) public getApproved;

    /// @dev Approval for all in native representation
    mapping(address => mapping(address => bool)) public isApprovedForAll;

    /// @dev Owner of id in native representation
    mapping(uint256 => address) internal _ownerOf;

    /// @dev Array of owned ids in native representation
    mapping(address => uint256[]) public _owned;

    /// @dev Tracks indices for the _owned mapping
    mapping(uint256 => uint256) internal _ownedIndex;

    /// @dev Addresses whitelisted from minting / burning for gas savings (pairs, routers, etc)
    mapping(address => bool) public whitelist;

    // Constructor
    constructor(string memory _name, string memory _symbol, address _owner) Ownable(_owner) {
        name = _name;
        symbol = _symbol;
        decimals = 18;
    }

    /// @notice Initialization function to set pairs / etc
    ///         saving gas by avoiding mint / burn on unnecessary targets
    function setWhitelist(address target, bool state) public onlyOwner {
        whitelist[target] = state;
    }

    /// @notice Function to find owner of a given native token
    function ownerOf(uint256 id) public view virtual returns (address owner) {
        owner = _ownerOf[id];

        if (owner == address(0)) {
            revert NotFound();
        }
    }

    /// @notice tokenURI must be implemented by child contract
    function tokenURI(uint256 id) public view virtual returns (string memory);

    /// @notice Function for token approvals
    /// @dev This function assumes id / native if amount less than or equal to current max id
    function approve(address spender, uint256 amountOrId) public virtual returns (bool) {
        if (amountOrId <= minted && amountOrId > 0) {
            address owner = _ownerOf[amountOrId];

            if (msg.sender != owner && !isApprovedForAll[owner][msg.sender]) {
                revert Unauthorized();
            }

            getApproved[amountOrId] = spender;

            emit Approval(owner, spender, amountOrId);
        } else {
            allowance[msg.sender][spender] = amountOrId;

            emit Approval(msg.sender, spender, amountOrId);
        }

        return true;
    }

    /// @notice Function native approvals
    function setApprovalForAll(address operator, bool approved) public virtual {
        isApprovedForAll[msg.sender][operator] = approved;

        emit ApprovalForAll(msg.sender, operator, approved);
    }

    /// @notice Function for mixed transfers
    /// @dev This function assumes id / native if amount less than or equal to current max id
    function transferFrom(address from, address to, uint256 amountOrId) public virtual {
        if (from == address(this)) {
            _transfer(from, to, amountOrId);
            return;
        }
        if (amountOrId <= minted) {
            if (from != _ownerOf[amountOrId]) {
                revert InvalidSender();
            }

            if (to == address(0)) {
                revert InvalidRecipient();
            }

            if (msg.sender != from && !isApprovedForAll[from][msg.sender] && msg.sender != getApproved[amountOrId]) {
                revert Unauthorized();
            }

            balanceOf[from] -= _getUnit();

            unchecked {
                balanceOf[to] += _getUnit();
            }

            _ownerOf[amountOrId] = to;
            delete getApproved[amountOrId];

            // update _owned for sender
            uint256 updatedId = _owned[from][_owned[from].length - 1];
            _owned[from][_ownedIndex[amountOrId]] = updatedId;
            // pop
            _owned[from].pop();
            // update index for the moved id
            _ownedIndex[updatedId] = _ownedIndex[amountOrId];
            // push token to to owned
            _owned[to].push(amountOrId);
            // update index for to owned
            _ownedIndex[amountOrId] = _owned[to].length - 1;

            emit Transfer(from, to, amountOrId);
            emit ERC20Transfer(from, to, _getUnit());
        } else {
            uint256 allowed = allowance[from][msg.sender];

            if (allowed != type(uint256).max) {
                allowance[from][msg.sender] = allowed - amountOrId;
            }

            _transfer(from, to, amountOrId);
        }
    }

    /// @notice Function for fractional transfers
    function transfer(address to, uint256 amount) public virtual returns (bool) {
        return _transfer(msg.sender, to, amount);
    }

    /// @notice Function for native transfers with contract support
    function safeTransferFrom(address from, address to, uint256 id) public virtual {
        transferFrom(from, to, id);

        if (
            to.code.length != 0
                && ERC721Receiver(to).onERC721Received(msg.sender, from, id, "") != ERC721Receiver.onERC721Received.selector
        ) {
            revert UnsafeRecipient();
        }
    }

    /// @notice Function for native transfers with contract support and callback data
    function safeTransferFrom(address from, address to, uint256 id, bytes calldata data) public virtual {
        transferFrom(from, to, id);

        if (
            to.code.length != 0
                && ERC721Receiver(to).onERC721Received(msg.sender, from, id, data)
                    != ERC721Receiver.onERC721Received.selector
        ) {
            revert UnsafeRecipient();
        }
    }

    /// @notice Internal function for fractional transfers
    function _transfer(address from, address to, uint256 amount) internal virtual returns (bool) {
        uint256 unit = _getUnit();
        uint256 balanceBeforeSender = balanceOf[from];
        uint256 balanceBeforeReceiver = balanceOf[to];

        balanceOf[from] -= amount;

        unchecked {
            balanceOf[to] += amount;
        }

        // Skip burn for certain addresses to save gas
        if (!whitelist[from]) {
            uint256 tokens_to_burn = (balanceBeforeSender / unit) - (balanceOf[from] / unit);
            for (uint256 i = 0; i < tokens_to_burn; i++) {
                _burn(from);
            }
        }

        // Skip minting for certain addresses to save gas
        if (!whitelist[to]) {
            uint256 tokens_to_mint = (balanceOf[to] / unit) - (balanceBeforeReceiver / unit);
            for (uint256 i = 0; i < tokens_to_mint; i++) {
                _mint(to);
            }
        }

        emit ERC20Transfer(from, to, amount);
        return true;
    }

    // Internal utility logic
    function _getUnit() internal view returns (uint256) {
        return 10 ** decimals;
    }

    function _mint(address to) internal virtual {
        if (to == address(0)) {
            revert InvalidRecipient();
        }

        unchecked {
            minted++;
        }

        uint256 id = minted;

        if (_ownerOf[id] != address(0)) {
            revert AlreadyExists();
        }

        _ownerOf[id] = to;
        _owned[to].push(id);
        _ownedIndex[id] = _owned[to].length - 1;

        emit Transfer(address(0), to, id);
    }

    function _burn(address from) internal virtual {
        if (from == address(0)) {
            revert InvalidSender();
        }

        uint256 id = _owned[from][_owned[from].length - 1];
        _owned[from].pop();
        delete _ownedIndex[id];
        delete _ownerOf[id];
        delete getApproved[id];

        emit Transfer(from, address(0), id);
    }

    function _setNameSymbol(string memory _name, string memory _symbol) internal {
        name = _name;
        symbol = _symbol;
    }
}

File 6 of 7 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    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 subtraction of two unsigned integers, with an overflow flag.
     */
    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.
     */
    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.
     */
    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.
     */
    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 largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

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

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

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

File 7 of 7 : SignedMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

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

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

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

Settings
{
  "remappings": [
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyExists","type":"error"},{"inputs":[],"name":"InvalidOwner","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidSender","type":"error"},{"inputs":[],"name":"NotFound","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnsafeRecipient","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":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimedRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimedSale","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"dataURI","type":"string"}],"name":"DataURIUpdated","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":"amount","type":"uint256"}],"name":"ERC20Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"ERC721Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"value","type":"bool"}],"name":"FeesExemptUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"fees","type":"uint256"}],"name":"FeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"launched","type":"bool"}],"name":"Launched","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"mintEnabled","type":"bool"}],"name":"MintEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"baseRewardRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rareRewardRate","type":"uint256"}],"name":"RewardRatesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"value","type":"bool"}],"name":"RewardsBlacklistUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"_owned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"airdrop","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amountOrId","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseRewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseTokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimAirdrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"claimableRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dataURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"feesValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"getIdsOwnedBy","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getRareImage","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isFeesExempt","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"isRare","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"launch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"launched","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pair","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"pendingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"rareOwned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rareRewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"revokeOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardsBlacklist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"routerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_users","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"setAirdrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_dataURI","type":"string"}],"name":"setDataURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fees","type":"uint256"}],"name":"setFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"value","type":"bool"}],"name":"setFeesExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_mintEnabled","type":"bool"}],"name":"setMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_baseRewardRate","type":"uint256"},{"internalType":"uint256","name":"_rareRewardRate","type":"uint256"}],"name":"setRewardRates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"value","type":"bool"}],"name":"setRewardsBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_tokenURI","type":"string"}],"name":"setTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"setWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","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":"amount","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":"amountOrId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"users","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"lastClaim","type":"uint256"},{"internalType":"uint256","name":"rewards","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60a0604052601080546001600160a01b0319908116737a250d5630b4cf539739df2c5dacb4c659f2488d179091556011805490911673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21790556127106014556101f46015556016805461ff0019166101001790556104b06017556107d06018553480156200008057600080fd5b506040805180820182526006808252651191510d0c0d60d21b602080840182905284518086019095529184529083015290338080620000d2576040516349e27cff60e01b815260040160405180910390fd5b600080546001600160a01b0319166001600160a01b03831690811782556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506001620001298482620014a3565b506002620001388382620014a3565b5050601260805250506001600d55601054601380546001600160a01b0319166001600160a01b0390921691821790556040805163c45a015560e01b8152905163c45a0155916004808201926020929091908290030181865afa158015620001a3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001c991906200156f565b6011546040516364e329cb60e11b81523060048201526001600160a01b03918216602482015291169063c9c65396906044016020604051808303816000875af11580156200021b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200024191906200156f565b601260006101000a8154816001600160a01b0302191690836001600160a01b031602179055506200028b604051806060016040528060398152602001620055d860399139620004d3565b6200029833600162000549565b620002a530600162000549565b601054620002be906001600160a01b0316600162000549565b620002cc6000600162000549565b620002d930600162000549565b620002e6306001620005d8565b601054620002ff906001600160a01b03166001620005d8565b6200030d60006001620005d8565b6013546040805163c45a015560e01b8152905162000388926001600160a01b03169163c45a01559160048083019260209291908290030181865afa1580156200035a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200038091906200156f565b6001620005d8565b620003a9733fc91a3afd70395cd496c647d5a6cc9d4b2b7fad6001620005d8565b601254620003c2906001600160a01b03166001620005d8565b620003cf33600162000660565b620003dc30600162000660565b601054620003f5906001600160a01b0316600162000660565b620004036000600162000660565b6013546040805163c45a015560e01b815290516200047e926001600160a01b03169163c45a01559160048083019260209291908290030181865afa15801562000450573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200047691906200156f565b600162000660565b6200049f733fc91a3afd70395cd496c647d5a6cc9d4b2b7fad600162000660565b601254620004b8906001600160a01b0316600162000660565b620004cd3368132df6197cbd340000620006b6565b62001835565b6000546001600160a01b03163314620004fe576040516282b42960e81b815260040160405180910390fd5b600e6200050c8282620014a3565b507feb50f9d7f0688d61a30addf284a43b41d4d8ee48d62db879b73c94456f9ae448816040516200053e91906200159a565b60405180910390a150565b6000546001600160a01b0316331462000574576040516282b42960e81b815260040160405180910390fd5b6001600160a01b0382166000818152601b6020908152604091829020805460ff19168515159081179091558251938452908301527f97fbd1483a6efe6e69257041dce6f4ecd1245e16a3e0d7dd8f3b0eadc314632091015b60405180910390a15050565b6000546001600160a01b0316331462000603576040516282b42960e81b815260040160405180910390fd5b6001600160a01b0382166000818152601a6020908152604091829020805460ff19168515159081179091558251938452908301527f62aef6cfe747da9dad930168a06ca5fbd7bec773d77533802a5419fd0632f9da9101620005cc565b6000546001600160a01b031633146200068b576040516282b42960e81b815260040160405180910390fd5b6001600160a01b03919091166000908152600c60205260409020805460ff1916911515919091179055565b601654610100900460ff16620007135760405162461bcd60e51b815260206004820152601360248201527f4d696e74696e672069732064697361626c65640000000000000000000000000060448201526064015b60405180910390fd5b6001600160a01b038216600090815260056020526040902054670de0b6b3a7640000906200074390839062001601565b1062000769576001600160a01b0382166000908152601960205260409020426001909101555b30600090815260056020526040812080548392906200078a90849062001601565b925050819055508060036000828254620007a5919062001601565b90915550620007b89050308383620007bd565b505050565b6000620007cc8484846200090a565b6001600160a01b0384166000908152601b602052604090205460ff16806200080c57506001600160a01b0383166000908152601b602052604090205460ff165b1562000827576200081f84848462000a10565b905062000903565b60165460ff166200086e5760405162461bcd60e51b815260206004820152601060248201526f139bdd081b185d5b98da1959081e595d60821b60448201526064016200070a565b6012546000906001600160a01b03868116911614806200089b57506012546001600160a01b038581169116145b15620008b157620008ae85858562000bd9565b90505b8015620008c757620008c585308362000a10565b505b6012546001600160a01b03868116911614620008e757620008e762000c49565b620008ff8585620008f9848762001617565b62000a10565b9150505b9392505050565b6001600160a01b0383166000908152601a602052604090205460ff166200098c57620009368362000d77565b6001600160a01b038316600090815260056020526040902054670de0b6b3a7640000906200096690839062001617565b1015620007b85750506001600160a01b0316600090815260196020526040812060010155565b6001600160a01b0382166000908152601a602052604090205460ff16620007b857620009b88262000d77565b6001600160a01b038216600090815260056020526040902054670de0b6b3a764000090620009e890839062001601565b10620007b857506001600160a01b031660009081526019602052604090204260019091015550565b60008062000a1d62000e1e565b6001600160a01b038087166000818152600560205260408082208054948a168352908220549282529394509192909186919062000a5b838662001617565b90915550506001600160a01b03808716600090815260056020908152604080832080548a019055928a168252600c9052205460ff1662000af8576001600160a01b03871660009081526005602052604081205462000abb9085906200162d565b62000ac785856200162d565b62000ad3919062001617565b905060005b8181101562000af55762000aec8962000e36565b60010162000ad8565b50505b6001600160a01b0386166000908152600c602052604090205460ff1662000b7e57600062000b2784836200162d565b6001600160a01b03881660009081526005602052604090205462000b4d9086906200162d565b62000b59919062001617565b905060005b8181101562000b7b5762000b728862000f56565b60010162000b5e565b50505b856001600160a01b0316876001600160a01b03167fe59fdd36d0d223c0c7d996db7ad796880f45e1936cb0bb7ac102e7082e0314878760405162000bc491815260200190565b60405180910390a35060019695505050505050565b6001600160a01b0383166000908152601b602052604081205460ff168062000c1957506001600160a01b0383166000908152601b602052604090205460ff165b1562000c285750600062000903565b60006014546015548462000c3d919062001650565b620008ff91906200162d565b30600090815260056020526040808220548151600280825260608201909352909291816020016020820280368337019050509050308160008151811062000c945762000c946200166a565b6001600160a01b03928316602091820292909201015260115482519116908290600190811062000cc85762000cc86200166a565b6001600160a01b03928316602091820292909201015260135462000cee91168362001054565b50601354600080546001600160a01b039283169263791ac947928692909186911662000d1d426103e862001601565b6040518663ffffffff1660e01b815260040162000d3f95949392919062001680565b600060405180830381600087803b15801562000d5a57600080fd5b505af115801562000d6f573d6000803e3d6000fd5b505050505050565b6001600160a01b0381166000908152601a602052604090205460ff161562000d9c5750565b6001600160a01b0381166000908152601960205260409020600101541562000e1b5762000dc98162001188565b6001600160a01b0382166000908152601960205260408120600201805490919062000df690849062001601565b90915550506001600160a01b0316600090815260196020526040902042600190910155565b50565b6000608051600a62000e319190620017f2565b905090565b6001600160a01b03811662000e5e57604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b0381166000908152600a60205260408120805462000e869060019062001617565b8154811062000e995762000e996200166a565b90600052602060002001549050600a6000836001600160a01b03166001600160a01b0316815260200190815260200160002080548062000edd5762000edd62001803565b600082815260208082208301600019908101839055909201909255828252600b815260408083208390556009825280832080546001600160a01b031990811690915560079092528083208054909216909155518291906001600160a01b0385169060008051602062005611833981519152908390a45050565b6001600160a01b03811662000f7e57604051634e46966960e11b815260040160405180910390fd5b60048054600101908190556000818152600960205260409020546001600160a01b03161562000fc05760405163119b4fd360e11b815260040160405180910390fd5b600081815260096020908152604080832080546001600160a01b0319166001600160a01b038716908117909155808452600a835290832080546001818101835582865293852001859055925290546200101a919062001617565b6000828152600b602052604080822092909255905182916001600160a01b0385169160008051602062005611833981519152908290a45050565b60006004548211158015620010695750600082115b1562001133576000828152600960205260409020546001600160a01b0316338114801590620010bc57506001600160a01b038116600090815260086020908152604080832033845290915290205460ff16155b15620010da576040516282b42960e81b815260040160405180910390fd5b60008381526007602090815260409182902080546001600160a01b0319166001600160a01b0388811691821790925592518681529084169160008051602062005631833981519152910160405180910390a3506200117e565b3360008181526006602090815260408083206001600160a01b038816808552908352928190208690555185815291929160008051602062005631833981519152910160405180910390a35b5060015b92915050565b601654600090610100900460ff16620011a357506000919050565b6001600160a01b0382166000908152601960205260408120600101549003620011ce57506000919050565b6001600160a01b038216600090815260196020526040812060010154620011f6904262001617565b905060006200120584620012e5565b90506000600182106200127a57601454620151806018548562001229919062001650565b6200123591906200162d565b6001600160a01b0387166000908152600560205260409020546200125a919062001650565b6200126691906200162d565b62001272908262001601565b9050620012dd565b601454620151806017548562001291919062001650565b6200129d91906200162d565b6001600160a01b038716600090815260056020526040902054620012c2919062001650565b620012ce91906200162d565b620012da908262001601565b90505b949350505050565b600080620012f38362001357565b90506000805b82518110156200134f57620013308382815181106200131c576200131c6200166a565b6020026020010151620013c560201b60201c565b15620013465781620013428162001819565b9250505b600101620012f9565b509392505050565b6001600160a01b0381166000908152600a6020908152604091829020805483518184028101840190945280845260609392830182828015620013b957602002820191906000526020600020905b815481526020019060010190808311620013a4575b50505050509050919050565b60008082604051602001620013dc91815260200190565b60408051601f198184030181529190528051602090910120600360f89190911c11159392505050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200143057607f821691505b6020821081036200145157634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620007b8576000816000526020600020601f850160051c81016020861015620014825750805b601f850160051c820191505b8181101562000d6f578281556001016200148e565b81516001600160401b03811115620014bf57620014bf62001405565b620014d781620014d084546200141b565b8462001457565b602080601f8311600181146200150f5760008415620014f65750858301515b600019600386901b1c1916600185901b17855562000d6f565b600085815260208120601f198616915b8281101562001540578886015182559484019460019091019084016200151f565b50858210156200155f5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200158257600080fd5b81516001600160a01b03811681146200090357600080fd5b60006020808352835180602085015260005b81811015620015ca57858101830151858201604001528201620015ac565b506000604082860101526040601f19601f8301168501019250505092915050565b634e487b7160e01b600052601160045260246000fd5b80820180821115620011825762001182620015eb565b81810381811115620011825762001182620015eb565b6000826200164b57634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417620011825762001182620015eb565b634e487b7160e01b600052603260045260246000fd5b600060a08201878352602087602085015260a0604085015281875180845260c08601915060208901935060005b81811015620016d45784516001600160a01b031683529383019391830191600101620016ad565b50506001600160a01b03969096166060850152505050608001529392505050565b600181815b80851115620017365781600019048211156200171a576200171a620015eb565b808516156200172857918102915b93841c9390800290620016fa565b509250929050565b6000826200174f5750600162001182565b816200175e5750600062001182565b81600181146200177757600281146200178257620017a2565b600191505062001182565b60ff841115620017965762001796620015eb565b50506001821b62001182565b5060208310610133831016604e8410600b8410161715620017c7575081810a62001182565b620017d38383620016f5565b8060001904821115620017ea57620017ea620015eb565b029392505050565b60006200090360ff8416836200173e565b634e487b7160e01b600052603160045260246000fd5b6000600182016200182e576200182e620015eb565b5060010190565b608051613d80620018586000396000818161056b0152612d300152613d806000f3fe60806040526004361061036f5760003560e01c80638091f3bf116101c6578063b88d4fde116100f7578063dd62ed3e11610095578063f28ca1dd1161006f578063f28ca1dd14610ae8578063f2fde38b14610afd578063f887ea4014610b1d578063feae2d9f14610b3d57600080fd5b8063dd62ed3e14610a55578063e0df5b6f14610a8d578063e985e9c514610aad57600080fd5b8063c87b56dd116100d1578063c87b56dd146109e1578063d123973014610a01578063d547cfb714610a20578063dc01f60d14610a3557600080fd5b8063b88d4fde14610971578063c34eb1c414610991578063c40d24b2146109b157600080fd5b8063a22cb46511610164578063a9059cbb1161013e578063a9059cbb146108fb578063ad5c46481461091b578063afbf34401461093b578063b43761071461095157600080fd5b8063a22cb46514610864578063a87430ba14610884578063a8aa1b31146108db57600080fd5b806395d89b41116101a057806395d89b41146107dc5780639af1d35a146107f15780639b19251a14610807578063a0369a071461083757600080fd5b80638091f3bf1461078257806383f6491e1461079c5780638da5cb5b146107bc57600080fd5b806337ba04a0116102a057806351a4b5961161023e5780636352211e116102185780636352211e146106f557806365bae49e1461071557806370a08231146107355780637d7780031461076257600080fd5b806351a4b596146106aa57806353d6fd59146106c05780635b88349d146106e057600080fd5b8063429ff28d1161027a578063429ff28d1461063f5780634c8905281461065f5780634e71d92d1461067f5780634f02c4201461069457600080fd5b806337ba04a0146105df5780633d18678e146105ff57806342842e0e1461061f57600080fd5b80631fe09da31161030d5780632b968958116102e75780632b96895814610544578063313ce5671461055957806331d7a2621461059f5780633268cc56146105bf57600080fd5b80631fe09da3146104d757806321860a05146104f757806323b872dd1461052457600080fd5b8063095ea7b311610349578063095ea7b31461044357806318160ddd1461047357806318d217c3146104975780631b0c18ed146104b757600080fd5b806301339c21146103b557806306fdde03146103ca578063081812fc146103f557600080fd5b366103b057600080546040516001600160a01b03909116913480156108fc02929091818181858888f193505050501580156103ae573d6000803e3d6000fd5b005b600080fd5b3480156103c157600080fd5b506103ae610b6d565b3480156103d657600080fd5b506103df610c27565b6040516103ec9190613358565b60405180910390f35b34801561040157600080fd5b5061042b61041036600461338b565b6007602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020016103ec565b34801561044f57600080fd5b5061046361045e3660046133bb565b610cb5565b60405190151581526020016103ec565b34801561047f57600080fd5b5061048960035481565b6040519081526020016103ec565b3480156104a357600080fd5b506103ae6104b23660046133fb565b610e06565b3480156104c357600080fd5b506103ae6104d23660046134bc565b610e77565b3480156104e357600080fd5b506104636104f236600461338b565b610f05565b34801561050357600080fd5b506104896105123660046134ef565b601c6020526000908152604090205481565b34801561053057600080fd5b506103ae61053f36600461350a565b610f44565b34801561055057600080fd5b506103ae610f5f565b34801561056557600080fd5b5061058d7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016103ec565b3480156105ab57600080fd5b506104896105ba3660046134ef565b610fc5565b3480156105cb57600080fd5b5060105461042b906001600160a01b031681565b3480156105eb57600080fd5b506103ae6105fa366004613546565b611106565b34801561060b57600080fd5b506103ae61061a36600461338b565b611214565b34801561062b57600080fd5b506103ae61063a36600461350a565b6112b5565b34801561064b57600080fd5b506103ae61065a366004613568565b61138a565b34801561066b57600080fd5b5061048961067a36600461350a565b6113fd565b34801561068b57600080fd5b506103ae611471565b3480156106a057600080fd5b5061048960045481565b3480156106b657600080fd5b5061048960185481565b3480156106cc57600080fd5b506103ae6106db3660046134bc565b611543565b3480156106ec57600080fd5b506103ae611598565b34801561070157600080fd5b5061042b61071036600461338b565b61160c565b34801561072157600080fd5b506103ae6107303660046135cf565b611647565b34801561074157600080fd5b506104896107503660046134ef565b60056020526000908152604090205481565b34801561076e57600080fd5b506103df61077d36600461338b565b611728565b34801561078e57600080fd5b506016546104639060ff1681565b3480156107a857600080fd5b506104896107b73660046134ef565b611870565b3480156107c857600080fd5b5060005461042b906001600160a01b031681565b3480156107e857600080fd5b506103df6118d0565b3480156107fd57600080fd5b5061048960155481565b34801561081357600080fd5b506104636108223660046134ef565b600c6020526000908152604090205460ff1681565b34801561084357600080fd5b506108576108523660046134ef565b6118dd565b6040516103ec919061363b565b34801561087057600080fd5b506103ae61087f3660046134bc565b611949565b34801561089057600080fd5b506108c061089f3660046134ef565b60196020526000908152604090208054600182015460029092015490919083565b604080519384526020840192909252908201526060016103ec565b3480156108e757600080fd5b5060125461042b906001600160a01b031681565b34801561090757600080fd5b506104636109163660046133bb565b6119b5565b34801561092757600080fd5b5060115461042b906001600160a01b031681565b34801561094757600080fd5b5061048960175481565b34801561095d57600080fd5b506103ae61096c3660046134bc565b6119c2565b34801561097d57600080fd5b506103ae61098c36600461367f565b611a48565b34801561099d57600080fd5b506104896109ac3660046133bb565b611b0b565b3480156109bd57600080fd5b506104636109cc3660046134ef565b601b6020526000908152604090205460ff1681565b3480156109ed57600080fd5b506103df6109fc36600461338b565b611b3c565b348015610a0d57600080fd5b5060165461046390610100900460ff1681565b348015610a2c57600080fd5b506103df6123d0565b348015610a4157600080fd5b50610489610a503660046134ef565b6123dd565b348015610a6157600080fd5b50610489610a7036600461371a565b600660209081526000928352604080842090915290825290205481565b348015610a9957600080fd5b506103ae610aa83660046133fb565b612413565b348015610ab957600080fd5b50610463610ac836600461371a565b600860209081526000928352604080842090915290825290205460ff1681565b348015610af457600080fd5b506103df612479565b348015610b0957600080fd5b506103ae610b183660046134ef565b612486565b348015610b2957600080fd5b5060135461042b906001600160a01b031681565b348015610b4957600080fd5b50610463610b583660046134ef565b601a6020526000908152604090205460ff1681565b6000546001600160a01b03163314610b97576040516282b42960e81b815260040160405180910390fd5b60165460ff1615610be25760405162461bcd60e51b815260206004820152601060248201526f105b1c9958591e481b185d5b98da195960821b60448201526064015b60405180910390fd5b6016805460ff191660019081179091556040519081527f329b2d9780190712e4dce1df3d73ad5288c4ea1718736d9cfda28915f59043929060200160405180910390a1565b60018054610c3490613744565b80601f0160208091040260200160405190810160405280929190818152602001828054610c6090613744565b8015610cad5780601f10610c8257610100808354040283529160200191610cad565b820191906000526020600020905b815481529060010190602001808311610c9057829003601f168201915b505050505081565b60006004548211158015610cc95750600082115b15610da0576000828152600960205260409020546001600160a01b0316338114801590610d1a57506001600160a01b038116600090815260086020908152604080832033845290915290205460ff16155b15610d37576040516282b42960e81b815260040160405180910390fd5b60008381526007602090815260409182902080546001600160a01b0319166001600160a01b038881169182179092559251868152908416917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350610dfc565b3360008181526006602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a35b5060015b92915050565b6000546001600160a01b03163314610e30576040516282b42960e81b815260040160405180910390fd5b600e610e3c82826137c6565b507feb50f9d7f0688d61a30addf284a43b41d4d8ee48d62db879b73c94456f9ae44881604051610e6c9190613358565b60405180910390a150565b6000546001600160a01b03163314610ea1576040516282b42960e81b815260040160405180910390fd5b6001600160a01b0382166000818152601a6020908152604091829020805460ff19168515159081179091558251938452908301527f62aef6cfe747da9dad930168a06ca5fbd7bec773d77533802a5419fd0632f9da91015b60405180910390a15050565b60008082604051602001610f1b91815260200190565b60408051601f198184030181529190528051602090910120600360f89190911c11159392505050565b610f4f838383612522565b610f5a83838361261c565b505050565b6000546001600160a01b03163314610f89576040516282b42960e81b815260040160405180910390fd5b600080546001600160a01b031916815560405133907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3565b601654600090610100900460ff16610fdf57506000919050565b6001600160a01b038216600090815260196020526040812060010154900361100957506000919050565b6001600160a01b03821660009081526019602052604081206001015461102f904261389c565b9050600061103c84611870565b90506000600182106110a557601454620151806018548561105d91906138af565b61106791906138c6565b6001600160a01b03871660009081526005602052604090205461108a91906138af565b61109491906138c6565b61109e90826138e8565b90506110fe565b60145462015180601754856110ba91906138af565b6110c491906138c6565b6001600160a01b0387166000908152600560205260409020546110e791906138af565b6110f191906138c6565b6110fb90826138e8565b90505b949350505050565b6000546001600160a01b03163314611130576040516282b42960e81b815260040160405180910390fd5b6113888211156111825760405162461bcd60e51b815260206004820152601960248201527f4261736520726577617264207261746520746f6f2068696768000000000000006044820152606401610bd9565b6127108111156111d45760405162461bcd60e51b815260206004820152601960248201527f5261726520726577617264207261746520746f6f2068696768000000000000006044820152606401610bd9565b6017829055601881905560408051838152602081018390527f3a5eba49eecf60fc53c136ba452bd9d855af074ee84a8e7d8e7b2070c3e756fa9101610ef9565b6000546001600160a01b0316331461123e576040516282b42960e81b815260040160405180910390fd5b6103e88111156112805760405162461bcd60e51b815260206004820152600d60248201526c08ccacae640e8dede40d0d2ced609b1b6044820152606401610bd9565b60158190556040518181527f9fe6eeb0f0541c644a56c67efeb872dbadd803a60b909d7dde1b35a3fe230b0e90602001610e6c565b6112c0838383610f44565b6001600160a01b0382163b1580159061136c5750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af115801561133b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061135f91906138fb565b6001600160e01b03191614155b15610f5a57604051633da6393160e01b815260040160405180910390fd5b6000546001600160a01b031633146113b4576040516282b42960e81b815260040160405180910390fd5b601680548215156101000261ff00199091161790556040517f30d46918504e7d4aa88713881c9c85ce8224770ba203947f54b221f303b6581e90610e6c90831515815260200190565b6001600160a01b0383166000908152601b602052604081205460ff168061143c57506001600160a01b0383166000908152601b602052604090205460ff165b156114495750600061146a565b60006014546015548461145c91906138af565b61146691906138c6565b9150505b9392505050565b6114796129be565b611482336129e8565b336000908152601960205260409020600201546114d75760405162461bcd60e51b81526020600482015260136024820152724e6f207265776172647320746f20636c61696d60681b6044820152606401610bd9565b33600081815260196020526040812060028101805492905542600190910155906115019082612a86565b60405181815233907f2d5429efdeca7741a8cd94067b18d988bc4e5f1d5b8272c37b7bfc31e9bfa32c9060200160405180910390a2506115416001600d55565b565b6000546001600160a01b0316331461156d576040516282b42960e81b815260040160405180910390fd5b6001600160a01b03919091166000908152600c60205260409020805460ff1916911515919091179055565b336000908152601c60205260409020546115ea5760405162461bcd60e51b81526020600482015260136024820152724e6f2061697264726f7020746f20636c61696d60681b6044820152606401610bd9565b336000818152601c602052604081208054919055906116099082612a86565b50565b6000818152600960205260409020546001600160a01b0316806116425760405163c5723b5160e01b815260040160405180910390fd5b919050565b6000546001600160a01b03163314611671576040516282b42960e81b815260040160405180910390fd5b8281146116b05760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081a5b9c1d5d609a1b6044820152606401610bd9565b60005b83811015611721578282828181106116cd576116cd613925565b90506020020135601c60008787858181106116ea576116ea613925565b90506020020160208101906116ff91906134ef565b6001600160a01b031681526020810191909152604001600020556001016116b3565b5050505050565b606061173382610f05565b61176a5760405162461bcd60e51b81526020600482015260086024820152674e6f74207261726560c01b6044820152606401610bd9565b60008260405160200161177f91815260200190565b60408051808303601f1901815282825280516020918201206001600160f81b0319811682850152825160018186030181526021909401909252825192019190912060f891821c9250901c6060605582116117ff575060408051808201909152600f81526e3930b93297b930b932af989733b4b360891b60208201526110fe565b60aa8260ff1611611836575060408051808201909152600f81526e3930b93297b930b932af991733b4b360891b60208201526110fe565b60ff8260ff16116110fe575060408051808201909152600f81526e3930b93297b930b932af999733b4b360891b6020820152949350505050565b60008061187c836118dd565b90506000805b82518110156118c8576118ad8382815181106118a0576118a0613925565b6020026020010151610f05565b156118c057816118bc8161393b565b9250505b600101611882565b509392505050565b60028054610c3490613744565b6001600160a01b0381166000908152600a602090815260409182902080548351818402810184019094528084526060939283018282801561193d57602002820191906000526020600020905b815481526020019060010190808311611929575b50505050509050919050565b3360008181526008602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b600061146a338484612b6b565b6000546001600160a01b031633146119ec576040516282b42960e81b815260040160405180910390fd5b6001600160a01b0382166000818152601b6020908152604091829020805460ff19168515159081179091558251938452908301527f97fbd1483a6efe6e69257041dce6f4ecd1245e16a3e0d7dd8f3b0eadc31463209101610ef9565b611a53858585610f44565b6001600160a01b0384163b15801590611aed5750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a0290611a9d9033908a90899089908990600401613954565b6020604051808303816000875af1158015611abc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae091906138fb565b6001600160e01b03191614155b1561172157604051633da6393160e01b815260040160405180910390fd5b600a6020528160005260406000208181548110611b2757600080fd5b90600052602060002001600091509150505481565b60606000600f8054611b4d90613744565b90501115611b8757600f611b6083612c96565b604051602001611b719291906139a8565b6040516020818303038152906040529050919050565b600082604051602001611b9c91815260200190565b6040516020818303038152906040528051906020012060f81c905060608060038360ff1611611bf457611bce85611728565b9150604051806040016040528060048152602001635261726560e01b81525090506122a1565b600f8360ff1611611c455760405180604001604052806005815260200164189733b4b360d91b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b601b8360ff1611611c965760405180604001604052806005815260200164191733b4b360d91b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60278360ff1611611ce75760405180604001604052806005815260200164199733b4b360d91b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60338360ff1611611d3857604051806040016040528060058152602001641a1733b4b360d91b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b603f8360ff1611611d8957604051806040016040528060058152602001641a9733b4b360d91b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b604b8360ff1611611dda57604051806040016040528060058152602001641b1733b4b360d91b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60578360ff1611611e2b57604051806040016040528060058152602001641b9733b4b360d91b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60638360ff1611611e7c57604051806040016040528060058152602001641c1733b4b360d91b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b606f8360ff1611611ecd57604051806040016040528060058152602001641c9733b4b360d91b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b607b8360ff1611611f1f576040518060400160405280600681526020016518981733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60878360ff1611611f71576040518060400160405280600681526020016518989733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60938360ff1611611fc3576040518060400160405280600681526020016518991733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b609f8360ff1611612015576040518060400160405280600681526020016518999733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60ab8360ff16116120675760405180604001604052806006815260200165189a1733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60b78360ff16116120b95760405180604001604052806006815260200165189a9733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60c38360ff161161210b5760405180604001604052806006815260200165189b1733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60cf8360ff161161215d5760405180604001604052806006815260200165189b9733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60db8360ff16116121af5760405180604001604052806006815260200165189c1733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60e78360ff16116122015760405180604001604052806006815260200165189c9733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60f38360ff1611612253576040518060400160405280600681526020016519181733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60ff8360ff16116122a1576040518060400160405280600681526020016519189733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090505b60006122ac86612c96565b6040516020016122bc9190613a2f565b60408051601f19818403018152908290526122d991602001613a67565b604051602081830303815290604052600e846040516020016122fc9291906139a8565b60408051601f198184030181529082905261231a9291602001613b05565b604051602081830303815290604052905060008260405160200161233e9190613b2b565b60408051601f1981840301815282820182526004835263227d5d7d60e01b6020848101919091529151909350612378918591859101613b05565b60408051601f1981840301815290829052612397918390602001613b05565b60408051601f19818403018152908290526123b491602001613b89565b6040516020818303038152906040529650505050505050919050565b600f8054610c3490613744565b6000806123e983610fc5565b6001600160a01b03841660009081526019602052604090206002015490915061146a9082906138e8565b6000546001600160a01b0316331461243d576040516282b42960e81b815260040160405180910390fd5b600f61244982826137c6565b507f6741b2fc379fad678116fe3d4d4b9a1a184ab53ba36b86ad0fa66340b1ab41ad81604051610e6c9190613358565b600e8054610c3490613744565b6000546001600160a01b031633146124b0576040516282b42960e81b815260040160405180910390fd5b6001600160a01b0381166124d7576040516349e27cff60e01b815260040160405180910390fd5b600080546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b6001600160a01b0383166000908152601a602052604090205460ff1661259e5761254b836129e8565b6001600160a01b038316600090815260056020526040902054670de0b6b3a76400009061257990839061389c565b1015610f5a5750506001600160a01b0316600090815260196020526040812060010155565b6001600160a01b0382166000908152601a602052604090205460ff16610f5a576125c7826129e8565b6001600160a01b038216600090815260056020526040902054670de0b6b3a7640000906125f59083906138e8565b10610f5a57506001600160a01b031660009081526019602052604090204260019091015550565b306001600160a01b0384160361263d57612637838383612b6b565b50505050565b6004548111612957576000818152600960205260409020546001600160a01b0384811691161461268057604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b0382166126a757604051634e46966960e11b815260040160405180910390fd5b336001600160a01b038416148015906126e457506001600160a01b038316600090815260086020908152604080832033845290915290205460ff16155b801561270757506000818152600760205260409020546001600160a01b03163314155b15612724576040516282b42960e81b815260040160405180910390fd5b61272c612d29565b6001600160a01b0384166000908152600560205260408120805490919061275490849061389c565b909155506127629050612d29565b6001600160a01b03808416600081815260056020908152604080832080549096019095558582526009815284822080546001600160a01b031990811690941790556007815284822080549093169092559186168252600a905290812080546127cc9060019061389c565b815481106127dc576127dc613925565b60009182526020808320909101546001600160a01b0387168352600a82526040808420868552600b9093529092205481549293508392811061282057612820613925565b60009182526020808320909101929092556001600160a01b0386168152600a9091526040902080548061285557612855613bce565b600082815260208082208301600019908101839055909201909255838252600b8152604080832054848452818420556001600160a01b038616808452600a835290832080546001818101835582865293852001869055925290546128b9919061389c565b6000838152600b602052604080822092909255905183916001600160a01b0380871692908816917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4826001600160a01b0316846001600160a01b03167fe59fdd36d0d223c0c7d996db7ad796880f45e1936cb0bb7ac102e7082e031487612940612d29565b60405190815260200160405180910390a350505050565b6001600160a01b038316600090815260066020908152604080832033845290915290205460001981146129b35761298e828261389c565b6001600160a01b03851660009081526006602090815260408083203384529091529020555b611721848484612b6b565b6002600d54036129e157604051633ee5aeb560e01b815260040160405180910390fd5b6002600d55565b6001600160a01b0381166000908152601a602052604090205460ff1615612a0c5750565b6001600160a01b0381166000908152601960205260409020600101541561160957612a3681610fc5565b6001600160a01b03821660009081526019602052604081206002018054909190612a619084906138e8565b90915550506001600160a01b0316600090815260196020526040902042600190910155565b601654610100900460ff16612ad35760405162461bcd60e51b8152602060048201526013602482015272135a5b9d1a5b99c81a5cc8191a5cd8589b1959606a1b6044820152606401610bd9565b6001600160a01b038216600090815260056020526040902054670de0b6b3a764000090612b019083906138e8565b10612b26576001600160a01b0382166000908152601960205260409020426001909101555b3060009081526005602052604081208054839290612b459084906138e8565b925050819055508060036000828254612b5e91906138e8565b90915550610f5a90503083835b6000612b78848484612522565b6001600160a01b0384166000908152601b602052604090205460ff1680612bb757506001600160a01b0383166000908152601b602052604090205460ff165b15612bce57612bc7848484612d5b565b905061146a565b60165460ff16612c135760405162461bcd60e51b815260206004820152601060248201526f139bdd081b185d5b98da1959081e595d60821b6044820152606401610bd9565b6012546000906001600160a01b0386811691161480612c3f57506012546001600160a01b038581169116145b15612c5257612c4f8585856113fd565b90505b8015612c6557612c63853083612d5b565b505b6012546001600160a01b03868116911614612c8257612c82612f09565b6114668585612c91848761389c565b612d5b565b60606000612ca383613029565b600101905060008167ffffffffffffffff811115612cc357612cc36133e5565b6040519080825280601f01601f191660200182016040528015612ced576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612cf757509392505050565b6000612d567f0000000000000000000000000000000000000000000000000000000000000000600a613cc8565b905090565b600080612d66612d29565b6001600160a01b038087166000818152600560205260408082208054948a1683529082205492825293945091929091869190612da2838661389c565b90915550506001600160a01b03808716600090815260056020908152604080832080548a019055928a168252600c9052205460ff16612e34576001600160a01b038716600090815260056020526040812054612dff9085906138c6565b612e0985856138c6565b612e13919061389c565b905060005b81811015612e3157612e2989613101565b600101612e18565b50505b6001600160a01b0386166000908152600c602052604090205460ff16612eaf576000612e6084836138c6565b6001600160a01b038816600090815260056020526040902054612e849086906138c6565b612e8e919061389c565b905060005b81811015612eac57612ea488613229565b600101612e93565b50505b856001600160a01b0316876001600160a01b03167fe59fdd36d0d223c0c7d996db7ad796880f45e1936cb0bb7ac102e7082e03148787604051612ef491815260200190565b60405180910390a35060019695505050505050565b306000908152600560205260408082205481516002808252606082019093529092918160200160208202803683370190505090503081600081518110612f5157612f51613925565b6001600160a01b039283166020918202929092010152601154825191169082906001908110612f8257612f82613925565b6001600160a01b039283166020918202929092010152601354612fa6911683610cb5565b50601354600080546001600160a01b039283169263791ac9479286929091869116612fd3426103e86138e8565b6040518663ffffffff1660e01b8152600401612ff3959493929190613cd7565b600060405180830381600087803b15801561300d57600080fd5b505af1158015613021573d6000803e3d6000fd5b505050505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106130685772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310613094576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106130b257662386f26fc10000830492506010015b6305f5e10083106130ca576305f5e100830492506008015b61271083106130de57612710830492506004015b606483106130f0576064830492506002015b600a8310610e005760010192915050565b6001600160a01b03811661312857604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b0381166000908152600a60205260408120805461314e9060019061389c565b8154811061315e5761315e613925565b90600052602060002001549050600a6000836001600160a01b03166001600160a01b0316815260200190815260200160002080548061319f5761319f613bce565b600082815260208082208301600019908101839055909201909255828252600b815260408083208390556009825280832080546001600160a01b031990811690915560079092528083208054909216909155518291906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6001600160a01b03811661325057604051634e46966960e11b815260040160405180910390fd5b60048054600101908190556000818152600960205260409020546001600160a01b0316156132915760405163119b4fd360e11b815260040160405180910390fd5b600081815260096020908152604080832080546001600160a01b0319166001600160a01b038716908117909155808452600a835290832080546001818101835582865293852001859055925290546132e9919061389c565b6000828152600b602052604080822092909255905182916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60005b8381101561334f578181015183820152602001613337565b50506000910152565b6020815260008251806020840152613377816040850160208701613334565b601f01601f19169190910160400192915050565b60006020828403121561339d57600080fd5b5035919050565b80356001600160a01b038116811461164257600080fd5b600080604083850312156133ce57600080fd5b6133d7836133a4565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561340d57600080fd5b813567ffffffffffffffff8082111561342557600080fd5b818401915084601f83011261343957600080fd5b81358181111561344b5761344b6133e5565b604051601f8201601f19908116603f01168101908382118183101715613473576134736133e5565b8160405282815287602084870101111561348c57600080fd5b826020860160208301376000928101602001929092525095945050505050565b8035801515811461164257600080fd5b600080604083850312156134cf57600080fd5b6134d8836133a4565b91506134e6602084016134ac565b90509250929050565b60006020828403121561350157600080fd5b61146a826133a4565b60008060006060848603121561351f57600080fd5b613528846133a4565b9250613536602085016133a4565b9150604084013590509250925092565b6000806040838503121561355957600080fd5b50508035926020909101359150565b60006020828403121561357a57600080fd5b61146a826134ac565b60008083601f84011261359557600080fd5b50813567ffffffffffffffff8111156135ad57600080fd5b6020830191508360208260051b85010111156135c857600080fd5b9250929050565b600080600080604085870312156135e557600080fd5b843567ffffffffffffffff808211156135fd57600080fd5b61360988838901613583565b9096509450602087013591508082111561362257600080fd5b5061362f87828801613583565b95989497509550505050565b6020808252825182820181905260009190848201906040850190845b8181101561367357835183529284019291840191600101613657565b50909695505050505050565b60008060008060006080868803121561369757600080fd5b6136a0866133a4565b94506136ae602087016133a4565b935060408601359250606086013567ffffffffffffffff808211156136d257600080fd5b818801915088601f8301126136e657600080fd5b8135818111156136f557600080fd5b89602082850101111561370757600080fd5b9699959850939650602001949392505050565b6000806040838503121561372d57600080fd5b613736836133a4565b91506134e6602084016133a4565b600181811c9082168061375857607f821691505b60208210810361377857634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610f5a576000816000526020600020601f850160051c810160208610156137a75750805b601f850160051c820191505b81811015613021578281556001016137b3565b815167ffffffffffffffff8111156137e0576137e06133e5565b6137f4816137ee8454613744565b8461377e565b602080601f83116001811461382957600084156138115750858301515b600019600386901b1c1916600185901b178555613021565b600085815260208120601f198616915b8281101561385857888601518255948401946001909101908401613839565b50858210156138765787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601160045260246000fd5b81810381811115610e0057610e00613886565b8082028115828204841417610e0057610e00613886565b6000826138e357634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115610e0057610e00613886565b60006020828403121561390d57600080fd5b81516001600160e01b03198116811461146a57600080fd5b634e487b7160e01b600052603260045260246000fd5b60006001820161394d5761394d613886565b5060010190565b6001600160a01b038681168252851660208201526040810184905260806060820181905281018290526000828460a0840137600060a0848401015260a0601f19601f85011683010190509695505050505050565b60008084546139b681613744565b600182811680156139ce57600181146139e357613a12565b60ff1984168752821515830287019450613a12565b8860005260208060002060005b85811015613a095781548a8201529084019082016139f0565b50505082870194505b505050508351613a26818360208801613334565b01949350505050565b6e7b226e616d65223a2022464544202360881b81528151600090613a5a81600f850160208701613334565b91909101600f0192915050565b60008251613a79818460208701613334565b7f222c226465736372697074696f6e223a22416e206578706572696d656e74616c9201918252507f207072696e746572206261736564206f6e204552433430342e222c226578746560208201527f726e616c5f75726c223a2268747470733a2f2f6665643430342e78797a222c2260408201526734b6b0b3b2911d1160c11b6060820152606801919050565b60008351613b17818460208801613334565b835190830190613a26818360208801613334565b7f222c2261747472696275746573223a5b7b2274726169745f74797065223a225281526f30b934ba3c9116113b30b63ab2911d1160811b602082015260008251613b7c816030850160208701613334565b9190910160300192915050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b757466382c0000000000815260008251613bc181601b850160208701613334565b91909101601b0192915050565b634e487b7160e01b600052603160045260246000fd5b600181815b80851115613c1f578160001904821115613c0557613c05613886565b80851615613c1257918102915b93841c9390800290613be9565b509250929050565b600082613c3657506001610e00565b81613c4357506000610e00565b8160018114613c595760028114613c6357613c7f565b6001915050610e00565b60ff841115613c7457613c74613886565b50506001821b610e00565b5060208310610133831016604e8410600b8410161715613ca2575081810a610e00565b613cac8383613be4565b8060001904821115613cc057613cc0613886565b029392505050565b600061146a60ff841683613c27565b600060a08201878352602087602085015260a0604085015281875180845260c08601915060208901935060005b81811015613d295784516001600160a01b031683529383019391830191600101613d04565b50506001600160a01b0396909616606085015250505060800152939250505056fea26469706673582212206cb406acb4c40d964ed59409732d62e777df56318a3c2ce7891c9500990c811364736f6c6343000817003368747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f666564344f342f6665643430345f696d672f6d61696e2fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925

Deployed Bytecode

0x60806040526004361061036f5760003560e01c80638091f3bf116101c6578063b88d4fde116100f7578063dd62ed3e11610095578063f28ca1dd1161006f578063f28ca1dd14610ae8578063f2fde38b14610afd578063f887ea4014610b1d578063feae2d9f14610b3d57600080fd5b8063dd62ed3e14610a55578063e0df5b6f14610a8d578063e985e9c514610aad57600080fd5b8063c87b56dd116100d1578063c87b56dd146109e1578063d123973014610a01578063d547cfb714610a20578063dc01f60d14610a3557600080fd5b8063b88d4fde14610971578063c34eb1c414610991578063c40d24b2146109b157600080fd5b8063a22cb46511610164578063a9059cbb1161013e578063a9059cbb146108fb578063ad5c46481461091b578063afbf34401461093b578063b43761071461095157600080fd5b8063a22cb46514610864578063a87430ba14610884578063a8aa1b31146108db57600080fd5b806395d89b41116101a057806395d89b41146107dc5780639af1d35a146107f15780639b19251a14610807578063a0369a071461083757600080fd5b80638091f3bf1461078257806383f6491e1461079c5780638da5cb5b146107bc57600080fd5b806337ba04a0116102a057806351a4b5961161023e5780636352211e116102185780636352211e146106f557806365bae49e1461071557806370a08231146107355780637d7780031461076257600080fd5b806351a4b596146106aa57806353d6fd59146106c05780635b88349d146106e057600080fd5b8063429ff28d1161027a578063429ff28d1461063f5780634c8905281461065f5780634e71d92d1461067f5780634f02c4201461069457600080fd5b806337ba04a0146105df5780633d18678e146105ff57806342842e0e1461061f57600080fd5b80631fe09da31161030d5780632b968958116102e75780632b96895814610544578063313ce5671461055957806331d7a2621461059f5780633268cc56146105bf57600080fd5b80631fe09da3146104d757806321860a05146104f757806323b872dd1461052457600080fd5b8063095ea7b311610349578063095ea7b31461044357806318160ddd1461047357806318d217c3146104975780631b0c18ed146104b757600080fd5b806301339c21146103b557806306fdde03146103ca578063081812fc146103f557600080fd5b366103b057600080546040516001600160a01b03909116913480156108fc02929091818181858888f193505050501580156103ae573d6000803e3d6000fd5b005b600080fd5b3480156103c157600080fd5b506103ae610b6d565b3480156103d657600080fd5b506103df610c27565b6040516103ec9190613358565b60405180910390f35b34801561040157600080fd5b5061042b61041036600461338b565b6007602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020016103ec565b34801561044f57600080fd5b5061046361045e3660046133bb565b610cb5565b60405190151581526020016103ec565b34801561047f57600080fd5b5061048960035481565b6040519081526020016103ec565b3480156104a357600080fd5b506103ae6104b23660046133fb565b610e06565b3480156104c357600080fd5b506103ae6104d23660046134bc565b610e77565b3480156104e357600080fd5b506104636104f236600461338b565b610f05565b34801561050357600080fd5b506104896105123660046134ef565b601c6020526000908152604090205481565b34801561053057600080fd5b506103ae61053f36600461350a565b610f44565b34801561055057600080fd5b506103ae610f5f565b34801561056557600080fd5b5061058d7f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff90911681526020016103ec565b3480156105ab57600080fd5b506104896105ba3660046134ef565b610fc5565b3480156105cb57600080fd5b5060105461042b906001600160a01b031681565b3480156105eb57600080fd5b506103ae6105fa366004613546565b611106565b34801561060b57600080fd5b506103ae61061a36600461338b565b611214565b34801561062b57600080fd5b506103ae61063a36600461350a565b6112b5565b34801561064b57600080fd5b506103ae61065a366004613568565b61138a565b34801561066b57600080fd5b5061048961067a36600461350a565b6113fd565b34801561068b57600080fd5b506103ae611471565b3480156106a057600080fd5b5061048960045481565b3480156106b657600080fd5b5061048960185481565b3480156106cc57600080fd5b506103ae6106db3660046134bc565b611543565b3480156106ec57600080fd5b506103ae611598565b34801561070157600080fd5b5061042b61071036600461338b565b61160c565b34801561072157600080fd5b506103ae6107303660046135cf565b611647565b34801561074157600080fd5b506104896107503660046134ef565b60056020526000908152604090205481565b34801561076e57600080fd5b506103df61077d36600461338b565b611728565b34801561078e57600080fd5b506016546104639060ff1681565b3480156107a857600080fd5b506104896107b73660046134ef565b611870565b3480156107c857600080fd5b5060005461042b906001600160a01b031681565b3480156107e857600080fd5b506103df6118d0565b3480156107fd57600080fd5b5061048960155481565b34801561081357600080fd5b506104636108223660046134ef565b600c6020526000908152604090205460ff1681565b34801561084357600080fd5b506108576108523660046134ef565b6118dd565b6040516103ec919061363b565b34801561087057600080fd5b506103ae61087f3660046134bc565b611949565b34801561089057600080fd5b506108c061089f3660046134ef565b60196020526000908152604090208054600182015460029092015490919083565b604080519384526020840192909252908201526060016103ec565b3480156108e757600080fd5b5060125461042b906001600160a01b031681565b34801561090757600080fd5b506104636109163660046133bb565b6119b5565b34801561092757600080fd5b5060115461042b906001600160a01b031681565b34801561094757600080fd5b5061048960175481565b34801561095d57600080fd5b506103ae61096c3660046134bc565b6119c2565b34801561097d57600080fd5b506103ae61098c36600461367f565b611a48565b34801561099d57600080fd5b506104896109ac3660046133bb565b611b0b565b3480156109bd57600080fd5b506104636109cc3660046134ef565b601b6020526000908152604090205460ff1681565b3480156109ed57600080fd5b506103df6109fc36600461338b565b611b3c565b348015610a0d57600080fd5b5060165461046390610100900460ff1681565b348015610a2c57600080fd5b506103df6123d0565b348015610a4157600080fd5b50610489610a503660046134ef565b6123dd565b348015610a6157600080fd5b50610489610a7036600461371a565b600660209081526000928352604080842090915290825290205481565b348015610a9957600080fd5b506103ae610aa83660046133fb565b612413565b348015610ab957600080fd5b50610463610ac836600461371a565b600860209081526000928352604080842090915290825290205460ff1681565b348015610af457600080fd5b506103df612479565b348015610b0957600080fd5b506103ae610b183660046134ef565b612486565b348015610b2957600080fd5b5060135461042b906001600160a01b031681565b348015610b4957600080fd5b50610463610b583660046134ef565b601a6020526000908152604090205460ff1681565b6000546001600160a01b03163314610b97576040516282b42960e81b815260040160405180910390fd5b60165460ff1615610be25760405162461bcd60e51b815260206004820152601060248201526f105b1c9958591e481b185d5b98da195960821b60448201526064015b60405180910390fd5b6016805460ff191660019081179091556040519081527f329b2d9780190712e4dce1df3d73ad5288c4ea1718736d9cfda28915f59043929060200160405180910390a1565b60018054610c3490613744565b80601f0160208091040260200160405190810160405280929190818152602001828054610c6090613744565b8015610cad5780601f10610c8257610100808354040283529160200191610cad565b820191906000526020600020905b815481529060010190602001808311610c9057829003601f168201915b505050505081565b60006004548211158015610cc95750600082115b15610da0576000828152600960205260409020546001600160a01b0316338114801590610d1a57506001600160a01b038116600090815260086020908152604080832033845290915290205460ff16155b15610d37576040516282b42960e81b815260040160405180910390fd5b60008381526007602090815260409182902080546001600160a01b0319166001600160a01b038881169182179092559251868152908416917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350610dfc565b3360008181526006602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a35b5060015b92915050565b6000546001600160a01b03163314610e30576040516282b42960e81b815260040160405180910390fd5b600e610e3c82826137c6565b507feb50f9d7f0688d61a30addf284a43b41d4d8ee48d62db879b73c94456f9ae44881604051610e6c9190613358565b60405180910390a150565b6000546001600160a01b03163314610ea1576040516282b42960e81b815260040160405180910390fd5b6001600160a01b0382166000818152601a6020908152604091829020805460ff19168515159081179091558251938452908301527f62aef6cfe747da9dad930168a06ca5fbd7bec773d77533802a5419fd0632f9da91015b60405180910390a15050565b60008082604051602001610f1b91815260200190565b60408051601f198184030181529190528051602090910120600360f89190911c11159392505050565b610f4f838383612522565b610f5a83838361261c565b505050565b6000546001600160a01b03163314610f89576040516282b42960e81b815260040160405180910390fd5b600080546001600160a01b031916815560405133907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3565b601654600090610100900460ff16610fdf57506000919050565b6001600160a01b038216600090815260196020526040812060010154900361100957506000919050565b6001600160a01b03821660009081526019602052604081206001015461102f904261389c565b9050600061103c84611870565b90506000600182106110a557601454620151806018548561105d91906138af565b61106791906138c6565b6001600160a01b03871660009081526005602052604090205461108a91906138af565b61109491906138c6565b61109e90826138e8565b90506110fe565b60145462015180601754856110ba91906138af565b6110c491906138c6565b6001600160a01b0387166000908152600560205260409020546110e791906138af565b6110f191906138c6565b6110fb90826138e8565b90505b949350505050565b6000546001600160a01b03163314611130576040516282b42960e81b815260040160405180910390fd5b6113888211156111825760405162461bcd60e51b815260206004820152601960248201527f4261736520726577617264207261746520746f6f2068696768000000000000006044820152606401610bd9565b6127108111156111d45760405162461bcd60e51b815260206004820152601960248201527f5261726520726577617264207261746520746f6f2068696768000000000000006044820152606401610bd9565b6017829055601881905560408051838152602081018390527f3a5eba49eecf60fc53c136ba452bd9d855af074ee84a8e7d8e7b2070c3e756fa9101610ef9565b6000546001600160a01b0316331461123e576040516282b42960e81b815260040160405180910390fd5b6103e88111156112805760405162461bcd60e51b815260206004820152600d60248201526c08ccacae640e8dede40d0d2ced609b1b6044820152606401610bd9565b60158190556040518181527f9fe6eeb0f0541c644a56c67efeb872dbadd803a60b909d7dde1b35a3fe230b0e90602001610e6c565b6112c0838383610f44565b6001600160a01b0382163b1580159061136c5750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af115801561133b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061135f91906138fb565b6001600160e01b03191614155b15610f5a57604051633da6393160e01b815260040160405180910390fd5b6000546001600160a01b031633146113b4576040516282b42960e81b815260040160405180910390fd5b601680548215156101000261ff00199091161790556040517f30d46918504e7d4aa88713881c9c85ce8224770ba203947f54b221f303b6581e90610e6c90831515815260200190565b6001600160a01b0383166000908152601b602052604081205460ff168061143c57506001600160a01b0383166000908152601b602052604090205460ff165b156114495750600061146a565b60006014546015548461145c91906138af565b61146691906138c6565b9150505b9392505050565b6114796129be565b611482336129e8565b336000908152601960205260409020600201546114d75760405162461bcd60e51b81526020600482015260136024820152724e6f207265776172647320746f20636c61696d60681b6044820152606401610bd9565b33600081815260196020526040812060028101805492905542600190910155906115019082612a86565b60405181815233907f2d5429efdeca7741a8cd94067b18d988bc4e5f1d5b8272c37b7bfc31e9bfa32c9060200160405180910390a2506115416001600d55565b565b6000546001600160a01b0316331461156d576040516282b42960e81b815260040160405180910390fd5b6001600160a01b03919091166000908152600c60205260409020805460ff1916911515919091179055565b336000908152601c60205260409020546115ea5760405162461bcd60e51b81526020600482015260136024820152724e6f2061697264726f7020746f20636c61696d60681b6044820152606401610bd9565b336000818152601c602052604081208054919055906116099082612a86565b50565b6000818152600960205260409020546001600160a01b0316806116425760405163c5723b5160e01b815260040160405180910390fd5b919050565b6000546001600160a01b03163314611671576040516282b42960e81b815260040160405180910390fd5b8281146116b05760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081a5b9c1d5d609a1b6044820152606401610bd9565b60005b83811015611721578282828181106116cd576116cd613925565b90506020020135601c60008787858181106116ea576116ea613925565b90506020020160208101906116ff91906134ef565b6001600160a01b031681526020810191909152604001600020556001016116b3565b5050505050565b606061173382610f05565b61176a5760405162461bcd60e51b81526020600482015260086024820152674e6f74207261726560c01b6044820152606401610bd9565b60008260405160200161177f91815260200190565b60408051808303601f1901815282825280516020918201206001600160f81b0319811682850152825160018186030181526021909401909252825192019190912060f891821c9250901c6060605582116117ff575060408051808201909152600f81526e3930b93297b930b932af989733b4b360891b60208201526110fe565b60aa8260ff1611611836575060408051808201909152600f81526e3930b93297b930b932af991733b4b360891b60208201526110fe565b60ff8260ff16116110fe575060408051808201909152600f81526e3930b93297b930b932af999733b4b360891b6020820152949350505050565b60008061187c836118dd565b90506000805b82518110156118c8576118ad8382815181106118a0576118a0613925565b6020026020010151610f05565b156118c057816118bc8161393b565b9250505b600101611882565b509392505050565b60028054610c3490613744565b6001600160a01b0381166000908152600a602090815260409182902080548351818402810184019094528084526060939283018282801561193d57602002820191906000526020600020905b815481526020019060010190808311611929575b50505050509050919050565b3360008181526008602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b600061146a338484612b6b565b6000546001600160a01b031633146119ec576040516282b42960e81b815260040160405180910390fd5b6001600160a01b0382166000818152601b6020908152604091829020805460ff19168515159081179091558251938452908301527f97fbd1483a6efe6e69257041dce6f4ecd1245e16a3e0d7dd8f3b0eadc31463209101610ef9565b611a53858585610f44565b6001600160a01b0384163b15801590611aed5750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a0290611a9d9033908a90899089908990600401613954565b6020604051808303816000875af1158015611abc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae091906138fb565b6001600160e01b03191614155b1561172157604051633da6393160e01b815260040160405180910390fd5b600a6020528160005260406000208181548110611b2757600080fd5b90600052602060002001600091509150505481565b60606000600f8054611b4d90613744565b90501115611b8757600f611b6083612c96565b604051602001611b719291906139a8565b6040516020818303038152906040529050919050565b600082604051602001611b9c91815260200190565b6040516020818303038152906040528051906020012060f81c905060608060038360ff1611611bf457611bce85611728565b9150604051806040016040528060048152602001635261726560e01b81525090506122a1565b600f8360ff1611611c455760405180604001604052806005815260200164189733b4b360d91b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b601b8360ff1611611c965760405180604001604052806005815260200164191733b4b360d91b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60278360ff1611611ce75760405180604001604052806005815260200164199733b4b360d91b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60338360ff1611611d3857604051806040016040528060058152602001641a1733b4b360d91b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b603f8360ff1611611d8957604051806040016040528060058152602001641a9733b4b360d91b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b604b8360ff1611611dda57604051806040016040528060058152602001641b1733b4b360d91b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60578360ff1611611e2b57604051806040016040528060058152602001641b9733b4b360d91b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60638360ff1611611e7c57604051806040016040528060058152602001641c1733b4b360d91b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b606f8360ff1611611ecd57604051806040016040528060058152602001641c9733b4b360d91b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b607b8360ff1611611f1f576040518060400160405280600681526020016518981733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60878360ff1611611f71576040518060400160405280600681526020016518989733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60938360ff1611611fc3576040518060400160405280600681526020016518991733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b609f8360ff1611612015576040518060400160405280600681526020016518999733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60ab8360ff16116120675760405180604001604052806006815260200165189a1733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60b78360ff16116120b95760405180604001604052806006815260200165189a9733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60c38360ff161161210b5760405180604001604052806006815260200165189b1733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60cf8360ff161161215d5760405180604001604052806006815260200165189b9733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60db8360ff16116121af5760405180604001604052806006815260200165189c1733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60e78360ff16116122015760405180604001604052806006815260200165189c9733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60f38360ff1611612253576040518060400160405280600681526020016519181733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090506122a1565b60ff8360ff16116122a1576040518060400160405280600681526020016519189733b4b360d11b81525091506040518060400160405280600681526020016521b7b6b6b7b760d11b81525090505b60006122ac86612c96565b6040516020016122bc9190613a2f565b60408051601f19818403018152908290526122d991602001613a67565b604051602081830303815290604052600e846040516020016122fc9291906139a8565b60408051601f198184030181529082905261231a9291602001613b05565b604051602081830303815290604052905060008260405160200161233e9190613b2b565b60408051601f1981840301815282820182526004835263227d5d7d60e01b6020848101919091529151909350612378918591859101613b05565b60408051601f1981840301815290829052612397918390602001613b05565b60408051601f19818403018152908290526123b491602001613b89565b6040516020818303038152906040529650505050505050919050565b600f8054610c3490613744565b6000806123e983610fc5565b6001600160a01b03841660009081526019602052604090206002015490915061146a9082906138e8565b6000546001600160a01b0316331461243d576040516282b42960e81b815260040160405180910390fd5b600f61244982826137c6565b507f6741b2fc379fad678116fe3d4d4b9a1a184ab53ba36b86ad0fa66340b1ab41ad81604051610e6c9190613358565b600e8054610c3490613744565b6000546001600160a01b031633146124b0576040516282b42960e81b815260040160405180910390fd5b6001600160a01b0381166124d7576040516349e27cff60e01b815260040160405180910390fd5b600080546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b6001600160a01b0383166000908152601a602052604090205460ff1661259e5761254b836129e8565b6001600160a01b038316600090815260056020526040902054670de0b6b3a76400009061257990839061389c565b1015610f5a5750506001600160a01b0316600090815260196020526040812060010155565b6001600160a01b0382166000908152601a602052604090205460ff16610f5a576125c7826129e8565b6001600160a01b038216600090815260056020526040902054670de0b6b3a7640000906125f59083906138e8565b10610f5a57506001600160a01b031660009081526019602052604090204260019091015550565b306001600160a01b0384160361263d57612637838383612b6b565b50505050565b6004548111612957576000818152600960205260409020546001600160a01b0384811691161461268057604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b0382166126a757604051634e46966960e11b815260040160405180910390fd5b336001600160a01b038416148015906126e457506001600160a01b038316600090815260086020908152604080832033845290915290205460ff16155b801561270757506000818152600760205260409020546001600160a01b03163314155b15612724576040516282b42960e81b815260040160405180910390fd5b61272c612d29565b6001600160a01b0384166000908152600560205260408120805490919061275490849061389c565b909155506127629050612d29565b6001600160a01b03808416600081815260056020908152604080832080549096019095558582526009815284822080546001600160a01b031990811690941790556007815284822080549093169092559186168252600a905290812080546127cc9060019061389c565b815481106127dc576127dc613925565b60009182526020808320909101546001600160a01b0387168352600a82526040808420868552600b9093529092205481549293508392811061282057612820613925565b60009182526020808320909101929092556001600160a01b0386168152600a9091526040902080548061285557612855613bce565b600082815260208082208301600019908101839055909201909255838252600b8152604080832054848452818420556001600160a01b038616808452600a835290832080546001818101835582865293852001869055925290546128b9919061389c565b6000838152600b602052604080822092909255905183916001600160a01b0380871692908816917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4826001600160a01b0316846001600160a01b03167fe59fdd36d0d223c0c7d996db7ad796880f45e1936cb0bb7ac102e7082e031487612940612d29565b60405190815260200160405180910390a350505050565b6001600160a01b038316600090815260066020908152604080832033845290915290205460001981146129b35761298e828261389c565b6001600160a01b03851660009081526006602090815260408083203384529091529020555b611721848484612b6b565b6002600d54036129e157604051633ee5aeb560e01b815260040160405180910390fd5b6002600d55565b6001600160a01b0381166000908152601a602052604090205460ff1615612a0c5750565b6001600160a01b0381166000908152601960205260409020600101541561160957612a3681610fc5565b6001600160a01b03821660009081526019602052604081206002018054909190612a619084906138e8565b90915550506001600160a01b0316600090815260196020526040902042600190910155565b601654610100900460ff16612ad35760405162461bcd60e51b8152602060048201526013602482015272135a5b9d1a5b99c81a5cc8191a5cd8589b1959606a1b6044820152606401610bd9565b6001600160a01b038216600090815260056020526040902054670de0b6b3a764000090612b019083906138e8565b10612b26576001600160a01b0382166000908152601960205260409020426001909101555b3060009081526005602052604081208054839290612b459084906138e8565b925050819055508060036000828254612b5e91906138e8565b90915550610f5a90503083835b6000612b78848484612522565b6001600160a01b0384166000908152601b602052604090205460ff1680612bb757506001600160a01b0383166000908152601b602052604090205460ff165b15612bce57612bc7848484612d5b565b905061146a565b60165460ff16612c135760405162461bcd60e51b815260206004820152601060248201526f139bdd081b185d5b98da1959081e595d60821b6044820152606401610bd9565b6012546000906001600160a01b0386811691161480612c3f57506012546001600160a01b038581169116145b15612c5257612c4f8585856113fd565b90505b8015612c6557612c63853083612d5b565b505b6012546001600160a01b03868116911614612c8257612c82612f09565b6114668585612c91848761389c565b612d5b565b60606000612ca383613029565b600101905060008167ffffffffffffffff811115612cc357612cc36133e5565b6040519080825280601f01601f191660200182016040528015612ced576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612cf757509392505050565b6000612d567f0000000000000000000000000000000000000000000000000000000000000012600a613cc8565b905090565b600080612d66612d29565b6001600160a01b038087166000818152600560205260408082208054948a1683529082205492825293945091929091869190612da2838661389c565b90915550506001600160a01b03808716600090815260056020908152604080832080548a019055928a168252600c9052205460ff16612e34576001600160a01b038716600090815260056020526040812054612dff9085906138c6565b612e0985856138c6565b612e13919061389c565b905060005b81811015612e3157612e2989613101565b600101612e18565b50505b6001600160a01b0386166000908152600c602052604090205460ff16612eaf576000612e6084836138c6565b6001600160a01b038816600090815260056020526040902054612e849086906138c6565b612e8e919061389c565b905060005b81811015612eac57612ea488613229565b600101612e93565b50505b856001600160a01b0316876001600160a01b03167fe59fdd36d0d223c0c7d996db7ad796880f45e1936cb0bb7ac102e7082e03148787604051612ef491815260200190565b60405180910390a35060019695505050505050565b306000908152600560205260408082205481516002808252606082019093529092918160200160208202803683370190505090503081600081518110612f5157612f51613925565b6001600160a01b039283166020918202929092010152601154825191169082906001908110612f8257612f82613925565b6001600160a01b039283166020918202929092010152601354612fa6911683610cb5565b50601354600080546001600160a01b039283169263791ac9479286929091869116612fd3426103e86138e8565b6040518663ffffffff1660e01b8152600401612ff3959493929190613cd7565b600060405180830381600087803b15801561300d57600080fd5b505af1158015613021573d6000803e3d6000fd5b505050505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106130685772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310613094576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106130b257662386f26fc10000830492506010015b6305f5e10083106130ca576305f5e100830492506008015b61271083106130de57612710830492506004015b606483106130f0576064830492506002015b600a8310610e005760010192915050565b6001600160a01b03811661312857604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b0381166000908152600a60205260408120805461314e9060019061389c565b8154811061315e5761315e613925565b90600052602060002001549050600a6000836001600160a01b03166001600160a01b0316815260200190815260200160002080548061319f5761319f613bce565b600082815260208082208301600019908101839055909201909255828252600b815260408083208390556009825280832080546001600160a01b031990811690915560079092528083208054909216909155518291906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6001600160a01b03811661325057604051634e46966960e11b815260040160405180910390fd5b60048054600101908190556000818152600960205260409020546001600160a01b0316156132915760405163119b4fd360e11b815260040160405180910390fd5b600081815260096020908152604080832080546001600160a01b0319166001600160a01b038716908117909155808452600a835290832080546001818101835582865293852001859055925290546132e9919061389c565b6000828152600b602052604080822092909255905182916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60005b8381101561334f578181015183820152602001613337565b50506000910152565b6020815260008251806020840152613377816040850160208701613334565b601f01601f19169190910160400192915050565b60006020828403121561339d57600080fd5b5035919050565b80356001600160a01b038116811461164257600080fd5b600080604083850312156133ce57600080fd5b6133d7836133a4565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561340d57600080fd5b813567ffffffffffffffff8082111561342557600080fd5b818401915084601f83011261343957600080fd5b81358181111561344b5761344b6133e5565b604051601f8201601f19908116603f01168101908382118183101715613473576134736133e5565b8160405282815287602084870101111561348c57600080fd5b826020860160208301376000928101602001929092525095945050505050565b8035801515811461164257600080fd5b600080604083850312156134cf57600080fd5b6134d8836133a4565b91506134e6602084016134ac565b90509250929050565b60006020828403121561350157600080fd5b61146a826133a4565b60008060006060848603121561351f57600080fd5b613528846133a4565b9250613536602085016133a4565b9150604084013590509250925092565b6000806040838503121561355957600080fd5b50508035926020909101359150565b60006020828403121561357a57600080fd5b61146a826134ac565b60008083601f84011261359557600080fd5b50813567ffffffffffffffff8111156135ad57600080fd5b6020830191508360208260051b85010111156135c857600080fd5b9250929050565b600080600080604085870312156135e557600080fd5b843567ffffffffffffffff808211156135fd57600080fd5b61360988838901613583565b9096509450602087013591508082111561362257600080fd5b5061362f87828801613583565b95989497509550505050565b6020808252825182820181905260009190848201906040850190845b8181101561367357835183529284019291840191600101613657565b50909695505050505050565b60008060008060006080868803121561369757600080fd5b6136a0866133a4565b94506136ae602087016133a4565b935060408601359250606086013567ffffffffffffffff808211156136d257600080fd5b818801915088601f8301126136e657600080fd5b8135818111156136f557600080fd5b89602082850101111561370757600080fd5b9699959850939650602001949392505050565b6000806040838503121561372d57600080fd5b613736836133a4565b91506134e6602084016133a4565b600181811c9082168061375857607f821691505b60208210810361377857634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610f5a576000816000526020600020601f850160051c810160208610156137a75750805b601f850160051c820191505b81811015613021578281556001016137b3565b815167ffffffffffffffff8111156137e0576137e06133e5565b6137f4816137ee8454613744565b8461377e565b602080601f83116001811461382957600084156138115750858301515b600019600386901b1c1916600185901b178555613021565b600085815260208120601f198616915b8281101561385857888601518255948401946001909101908401613839565b50858210156138765787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601160045260246000fd5b81810381811115610e0057610e00613886565b8082028115828204841417610e0057610e00613886565b6000826138e357634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115610e0057610e00613886565b60006020828403121561390d57600080fd5b81516001600160e01b03198116811461146a57600080fd5b634e487b7160e01b600052603260045260246000fd5b60006001820161394d5761394d613886565b5060010190565b6001600160a01b038681168252851660208201526040810184905260806060820181905281018290526000828460a0840137600060a0848401015260a0601f19601f85011683010190509695505050505050565b60008084546139b681613744565b600182811680156139ce57600181146139e357613a12565b60ff1984168752821515830287019450613a12565b8860005260208060002060005b85811015613a095781548a8201529084019082016139f0565b50505082870194505b505050508351613a26818360208801613334565b01949350505050565b6e7b226e616d65223a2022464544202360881b81528151600090613a5a81600f850160208701613334565b91909101600f0192915050565b60008251613a79818460208701613334565b7f222c226465736372697074696f6e223a22416e206578706572696d656e74616c9201918252507f207072696e746572206261736564206f6e204552433430342e222c226578746560208201527f726e616c5f75726c223a2268747470733a2f2f6665643430342e78797a222c2260408201526734b6b0b3b2911d1160c11b6060820152606801919050565b60008351613b17818460208801613334565b835190830190613a26818360208801613334565b7f222c2261747472696275746573223a5b7b2274726169745f74797065223a225281526f30b934ba3c9116113b30b63ab2911d1160811b602082015260008251613b7c816030850160208701613334565b9190910160300192915050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b757466382c0000000000815260008251613bc181601b850160208701613334565b91909101601b0192915050565b634e487b7160e01b600052603160045260246000fd5b600181815b80851115613c1f578160001904821115613c0557613c05613886565b80851615613c1257918102915b93841c9390800290613be9565b509250929050565b600082613c3657506001610e00565b81613c4357506000610e00565b8160018114613c595760028114613c6357613c7f565b6001915050610e00565b60ff841115613c7457613c74613886565b50506001821b610e00565b5060208310610133831016604e8410600b8410161715613ca2575081810a610e00565b613cac8383613be4565b8060001904821115613cc057613cc0613886565b029392505050565b600061146a60ff841683613c27565b600060a08201878352602087602085015260a0604085015281875180845260c08601915060208901935060005b81811015613d295784516001600160a01b031683529383019391830191600101613d04565b50506001600160a01b0396909616606085015250505060800152939250505056fea26469706673582212206cb406acb4c40d964ed59409732d62e777df56318a3c2ce7891c9500990c811364736f6c63430008170033

Loading...
Loading
Loading...
Loading
[ 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.