ETH Price: $3,441.82 (+1.48%)
Gas: 4 Gwei

Token

StakeStone Ether (STONE)
 

Overview

Max Total Supply

161,522.986969628983120382 STONE

Holders

6,000 ( -0.217%)

Market

Price

$3,509.42 @ 1.019641 ETH (+1.42%)

Onchain Market Cap

$566,852,000.93

Circulating Supply Market Cap

$0.00

Other Info

Token Contract (WITH 18 Decimals)

Balance
0.004008534 STONE

Value
$14.07 ( ~0.004087956352696 Eth) [0.0000%]
0x9d028D94F984A81Df53764a2E7387db85e2f00C2
Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW

STONE aims to be one of the the best yield-bearing ETH with a decentralized yield optimizing service ready for mass adoption on layer2s.

# Exchange Pair Price  24H Volume % Volume
1
Uniswap V3 (Ethereum)
0X7122985656E38BDC0302DB86685BB972B145BD3C-0XC02AAA39B223FE8D0A0E5C4F27EAD9083C756CC2$3,441.28
0.9999395 Eth
$337,080.00
97.238 0X7122985656E38BDC0302DB86685BB972B145BD3C
0.1054%
2
Lynex
0X93F4D0AB6A8B4271F4A28DB399B5E30612D21116-0XE5D7C2A44FFDDF6B295A15C148167DAAAF5CF34F$3,511.19
1.0204010 Eth
$239,071.00
68.069 0X93F4D0AB6A8B4271F4A28DB399B5E30612D21116
0.0738%
3
Oku Trade (Manta Pacific)
0XEC901DA9C68E90798BBBB74C11406A32A70652C3-0X0DC808ADCE2099A9F62AA87D9670745ABA741746$3,509.41
1.0196180 Eth
$226,642.00
64.592 0XEC901DA9C68E90798BBBB74C11406A32A70652C3
0.0700%
4
Quickswap V3 (Manta Pacific)
0XEC901DA9C68E90798BBBB74C11406A32A70652C3-0X0DC808ADCE2099A9F62AA87D9670745ABA741746$3,505.36
1.0184410 Eth
$222,037.00
63.319 0XEC901DA9C68E90798BBBB74C11406A32A70652C3
0.0686%
5
Uniswap V3 (Ethereum)
0X7122985656E38BDC0302DB86685BB972B145BD3C-0XE5018913F2FDF33971864804DDB5FCA25C539032$3,472.80
1.0090980 Eth
$55,670.00
15.417 0X7122985656E38BDC0302DB86685BB972B145BD3C
0.0167%
6
ApertureSwap
0XEC901DA9C68E90798BBBB74C11406A32A70652C3-0X0DC808ADCE2099A9F62AA87D9670745ABA741746$3,507.52
1.0193340 Eth
$51,363.00
14.636 0XEC901DA9C68E90798BBBB74C11406A32A70652C3
0.0159%
7
Quickswap V3 (Manta Pacific)
0X95CEF13441BE50D20CA4558CC0A27B601AC544E5-0XEC901DA9C68E90798BBBB74C11406A32A70652C3$3,509.31
1.0195880 Eth
$37,524.00
34,733.614 0X95CEF13441BE50D20CA4558CC0A27B601AC544E5
37.6509%
8
Quickswap V3 (Manta Pacific)
0X95CEF13441BE50D20CA4558CC0A27B601AC544E5-0XEC901DA9C68E90798BBBB74C11406A32A70652C3$3,509.31
1.0195880 Eth
$15,925.12
14,482.979 0X95CEF13441BE50D20CA4558CC0A27B601AC544E5
15.6994%
9
Quickswap V3 (Manta Pacific)
0XEC901DA9C68E90798BBBB74C11406A32A70652C3-0X0DC808ADCE2099A9F62AA87D9670745ABA741746$3,505.77
1.0185610 Eth
$14,634.89
4.174 0XEC901DA9C68E90798BBBB74C11406A32A70652C3
0.0045%
10
SyncSwap V2.1 (Linea)
0X93F4D0AB6A8B4271F4A28DB399B5E30612D21116-0XE5D7C2A44FFDDF6B295A15C148167DAAAF5CF34F$3,511.05
1.0200930 Eth
$12,926.29
3.663 0X93F4D0AB6A8B4271F4A28DB399B5E30612D21116
0.0040%
11
Quickswap V3 (Manta Pacific)
0XBDAD407F77F44F7DA6684B416B1951ECA461FB07-0XEC901DA9C68E90798BBBB74C11406A32A70652C3$3,504.92
1.0200740 Eth
$11,516.94
11,165.754 0XBDAD407F77F44F7DA6684B416B1951ECA461FB07
12.1036%
12
PacificSwap
0XEC901DA9C68E90798BBBB74C11406A32A70652C3-0X0DC808ADCE2099A9F62AA87D9670745ABA741746$3,505.31
1.0201880 Eth
$11,411.76
3.261 0XEC901DA9C68E90798BBBB74C11406A32A70652C3
0.0035%
13
iZiSwap (Manta Pacific)
0XB73603C5D87FA094B7314C74ACE2E64D165016FB-0XEC901DA9C68E90798BBBB74C11406A32A70652C3$3,448.94
1.0020490 Eth
$9,008.30
9,157.550 0XB73603C5D87FA094B7314C74ACE2E64D165016FB
9.9267%
14
iZiSwap (Manta Pacific)
0XBDAD407F77F44F7DA6684B416B1951ECA461FB07-0XEC901DA9C68E90798BBBB74C11406A32A70652C3$3,448.94
1.0020490 Eth
$5,069.32
4,994.523 0XBDAD407F77F44F7DA6684B416B1951ECA461FB07
5.4140%
15
Quickswap V3 (Manta Pacific)
0XBDAD407F77F44F7DA6684B416B1951ECA461FB07-0XEC901DA9C68E90798BBBB74C11406A32A70652C3$3,509.31
1.0195880 Eth
$4,933.89
4,775.015 0XBDAD407F77F44F7DA6684B416B1951ECA461FB07
5.1761%
16
Lynex
0X1A51B19CE03DBE0CB44C1528E34A7EDD7771E9AF-0X93F4D0AB6A8B4271F4A28DB399B5E30612D21116$3,511.82
1.0207120 Eth
$2,515.23
22,483.935 0X1A51B19CE03DBE0CB44C1528E34A7EDD7771E9AF
24.3724%
17
iZiSwap (Manta Pacific)
0XEC901DA9C68E90798BBBB74C11406A32A70652C3-0X0DC808ADCE2099A9F62AA87D9670745ABA741746$3,510.72
1.0199990 Eth
$1,986.96
0.568 0XEC901DA9C68E90798BBBB74C11406A32A70652C3
0.0006%
18
Matcha (Ethereum)
0X7122985656E38BDC0302DB86685BB972B145BD3C-0XC02AAA39B223FE8D0A0E5C4F27EAD9083C756CC2$3,539.22
1.0221360 Eth
$1,849.31
0.533 0X7122985656E38BDC0302DB86685BB972B145BD3C
0.0006%
19
Quickswap V3 (Manta Pacific)
0XE22E3D44EA9FB0A87EA3F7A8F41D869C677F0020-0XEC901DA9C68E90798BBBB74C11406A32A70652C3$3,504.92
1.0200740 Eth
$1,156.17
25,732.771 0XE22E3D44EA9FB0A87EA3F7A8F41D869C677F0020
27.8941%
20
Firefly
0X95CEF13441BE50D20CA4558CC0A27B601AC544E5-0XEC901DA9C68E90798BBBB74C11406A32A70652C3$3,502.59
1.0206840 Eth
$1,100.11
1,004.522 0X95CEF13441BE50D20CA4558CC0A27B601AC544E5
1.0889%
21
Gull Network
0X95CEF13441BE50D20CA4558CC0A27B601AC544E5-0XEC901DA9C68E90798BBBB74C11406A32A70652C3$3,498.19
1.0190320 Eth
$804.54
739.387 0X95CEF13441BE50D20CA4558CC0A27B601AC544E5
0.8015%
22
Lynex V2 (Linea)
0X93F4D0AB6A8B4271F4A28DB399B5E30612D21116-0XE5D7C2A44FFDDF6B295A15C148167DAAAF5CF34F$3,513.27
1.0205120 Eth
$376.91
0.107 0X93F4D0AB6A8B4271F4A28DB399B5E30612D21116
0.0001%
23
ApertureSwap
0XBDAD407F77F44F7DA6684B416B1951ECA461FB07-0XEC901DA9C68E90798BBBB74C11406A32A70652C3$3,510.90
1.0203160 Eth
$360.45
348.783 0XBDAD407F77F44F7DA6684B416B1951ECA461FB07
0.3781%
24
iZiSwap (Manta Pacific)
0XEC901DA9C68E90798BBBB74C11406A32A70652C3-0X0DC808ADCE2099A9F62AA87D9670745ABA741746$3,518.62
1.0222930 Eth
$268.96
0.077 0XEC901DA9C68E90798BBBB74C11406A32A70652C3
0.0001%
25
PacificSwap
0XB73603C5D87FA094B7314C74ACE2E64D165016FB-0XEC901DA9C68E90798BBBB74C11406A32A70652C3$3,510.62
1.0199140 Eth
$260.20
255.060 0XB73603C5D87FA094B7314C74ACE2E64D165016FB
0.2765%
26
Lynex
0X93F4D0AB6A8B4271F4A28DB399B5E30612D21116-0X176211869CA2B568F2A7D4EE941E073A821EE1FF$3,511.61
1.0265130 Eth
$218.76
0.063 0X93F4D0AB6A8B4271F4A28DB399B5E30612D21116
0.0001%
27
Gull Network
0XEC901DA9C68E90798BBBB74C11406A32A70652C3-0X0DC808ADCE2099A9F62AA87D9670745ABA741746$3,505.80
1.0185670 Eth
$209.15
0.060 0XEC901DA9C68E90798BBBB74C11406A32A70652C3
0.0001%
28
ApertureSwap
0XEC901DA9C68E90798BBBB74C11406A32A70652C3-0X0DC808ADCE2099A9F62AA87D9670745ABA741746$3,441.06
1.0191890 Eth
$145.90
0.042 0XEC901DA9C68E90798BBBB74C11406A32A70652C3
0.0000%
29
Quickswap V3 (Manta Pacific)
0XCD5D6DE3FDBCE1895F0DAC13A065673599ED6806-0XEC901DA9C68E90798BBBB74C11406A32A70652C3$3,508.58
1.0194630 Eth
$102.41
1,394.037 0XCD5D6DE3FDBCE1895F0DAC13A065673599ED6806
1.5111%
30
Quickswap V3 (Manta Pacific)
0XEC901DA9C68E90798BBBB74C11406A32A70652C3-0X0DC808ADCE2099A9F62AA87D9670745ABA741746$3,509.37
1.0190190 Eth
$33.79
0.010 0XEC901DA9C68E90798BBBB74C11406A32A70652C3
0.0000%
31
Firefly
0XEC901DA9C68E90798BBBB74C11406A32A70652C3-0X0DC808ADCE2099A9F62AA87D9670745ABA741746$3,510.14
1.0198290 Eth
$30.44
0.009 0XEC901DA9C68E90798BBBB74C11406A32A70652C3
0.0000%
32
Gull Network
0XCD5D6DE3FDBCE1895F0DAC13A065673599ED6806-0XEC901DA9C68E90798BBBB74C11406A32A70652C3$3,509.51
1.0189210 Eth
$29.61
396.684 0XCD5D6DE3FDBCE1895F0DAC13A065673599ED6806
0.4300%
33
Cetoswap (Manta Pacific)
0XEC901DA9C68E90798BBBB74C11406A32A70652C3-0X0DC808ADCE2099A9F62AA87D9670745ABA741746$3,522.37
1.0233910 Eth
$28.69
0.008 0XEC901DA9C68E90798BBBB74C11406A32A70652C3
0.0000%
34
PacificSwap
0XBDAD407F77F44F7DA6684B416B1951ECA461FB07-0XEC901DA9C68E90798BBBB74C11406A32A70652C3$3,504.97
1.0199380 Eth
$28.50
27.417 0XBDAD407F77F44F7DA6684B416B1951ECA461FB07
0.0297%
35
ApertureSwap
0XB73603C5D87FA094B7314C74ACE2E64D165016FB-0XEC901DA9C68E90798BBBB74C11406A32A70652C3$3,505.82
1.0187440 Eth
$28.05
27.986 0XB73603C5D87FA094B7314C74ACE2E64D165016FB
0.0303%
36
PacificSwap
0XEC901DA9C68E90798BBBB74C11406A32A70652C3-0X0DC808ADCE2099A9F62AA87D9670745ABA741746$3,508.18
1.0200120 Eth
$16.29
0.005 0XEC901DA9C68E90798BBBB74C11406A32A70652C3
0.0000%
37
PacificSwap
0XEC901DA9C68E90798BBBB74C11406A32A70652C3-0X0DC808ADCE2099A9F62AA87D9670745ABA741746$3,453.84
1.0232990 Eth
$11.05
0.003 0XEC901DA9C68E90798BBBB74C11406A32A70652C3
0.0000%
38
iZiSwap (Manta Pacific)
0XCD5D6DE3FDBCE1895F0DAC13A065673599ED6806-0XEC901DA9C68E90798BBBB74C11406A32A70652C3$3,450.69
1.0023590 Eth
$5.97
81.229 0XCD5D6DE3FDBCE1895F0DAC13A065673599ED6806
0.0881%
39
ApertureSwap
0XEC901DA9C68E90798BBBB74C11406A32A70652C3-0X0DC808ADCE2099A9F62AA87D9670745ABA741746$3,369.51
1.0012900 Eth
$5.60
0.002 0XEC901DA9C68E90798BBBB74C11406A32A70652C3
0.0000%
40
SyncSwap (Linea)
0X93F4D0AB6A8B4271F4A28DB399B5E30612D21116-0XE5D7C2A44FFDDF6B295A15C148167DAAAF5CF34F$3,480.58
1.0106590 Eth
$2.00
0.001 0X93F4D0AB6A8B4271F4A28DB399B5E30612D21116
0.0000%

Contract Source Code Verified (Exact Match)

Contract Name:
Stone

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 10 runs

Other Settings:
shanghai EvmVersion
File 1 of 29 : Stone.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import "@layerzerolabs/solidity-examples/contracts/token/oft/extension/BasedOFT.sol";

import {Minter} from "./Minter.sol";

contract Stone is BasedOFT {
    uint256 public constant DAY_INTERVAL = 24 * 60 * 60;

    address public minter;

    uint16 public constant PT_FEED = 1;
    uint16 public constant PT_SET_ENABLE = 2;
    uint16 public constant PT_SET_CAP = 3;

    uint256 public cap;
    bool public enable = true;

    mapping(uint256 => uint256) public quota;

    event FeedToChain(
        uint16 indexed dstChainId,
        address indexed from,
        bytes toAddress,
        uint price
    );
    event SetCapFor(uint16 indexed dstChainId, bytes toAddress, uint cap);
    event SetEnableFor(uint16 indexed dstChainId, bytes toAddress, bool flag);

    constructor(
        address _minter,
        address _layerZeroEndpoint,
        uint256 _cap
    ) BasedOFT("StakeStone Ether", "STONE", _layerZeroEndpoint) {
        minter = _minter;
        cap = _cap;
    }

    modifier onlyMinter() {
        require(msg.sender == minter, "NM");
        _;
    }

    function mint(address _to, uint256 _amount) external onlyMinter {
        _mint(_to, _amount);
    }

    function burn(address _from, uint256 _amount) external onlyMinter {
        _burn(_from, _amount);
    }

    function sendFrom(
        address _from,
        uint16 _dstChainId,
        bytes calldata _toAddress,
        uint _amount,
        address payable _refundAddress,
        address _zroPaymentAddress,
        bytes calldata _adapterParams
    ) public payable override(IOFTCore, OFTCore) {
        require(enable, "invalid");

        uint256 id;
        assembly {
            id := chainid()
        }
        require(id != _dstChainId, "same chain");

        uint256 day = block.timestamp / DAY_INTERVAL;
        require(_amount + quota[day] <= cap, "Exceed cap");

        quota[day] = quota[day] + _amount;

        super.sendFrom(
            _from,
            _dstChainId,
            _toAddress,
            _amount,
            _refundAddress,
            _zroPaymentAddress,
            _adapterParams
        );
    }

    function updatePrice(
        uint16 _dstChainId,
        bytes memory _toAddress
    ) external payable returns (uint256 price) {
        require(enable, "invalid");

        uint256 id;
        assembly {
            id := chainid()
        }
        require(id != _dstChainId, "same chain");

        price = tokenPrice();

        bytes memory lzPayload = abi.encode(
            PT_FEED,
            _toAddress,
            price,
            block.timestamp
        );

        _lzSend(
            _dstChainId,
            lzPayload,
            payable(msg.sender),
            address(0),
            bytes(""),
            msg.value
        );

        emit FeedToChain(_dstChainId, msg.sender, _toAddress, price);
    }

    function setEnableFor(
        uint16 _dstChainId,
        bool _flag,
        bytes memory _toAddress
    ) external payable onlyOwner {
        uint256 id;
        assembly {
            id := chainid()
        }

        if (_dstChainId == id) {
            enable = _flag;

            emit SetEnableFor(
                _dstChainId,
                abi.encodePacked(address(this)),
                enable
            );
            return;
        }

        bytes memory lzPayload = abi.encode(PT_SET_ENABLE, _toAddress, _flag);
        _lzSend(
            _dstChainId,
            lzPayload,
            payable(msg.sender),
            address(0),
            bytes(""),
            msg.value
        );

        emit SetEnableFor(_dstChainId, _toAddress, _flag);
    }

    function setCapFor(
        uint16 _dstChainId,
        uint256 _cap,
        bytes memory _toAddress
    ) external payable onlyOwner {
        uint256 id;
        assembly {
            id := chainid()
        }

        if (_dstChainId == id) {
            cap = _cap;

            emit SetCapFor(_dstChainId, abi.encodePacked(address(this)), cap);
            return;
        }

        bytes memory lzPayload = abi.encode(PT_SET_CAP, _toAddress, _cap);
        _lzSend(
            _dstChainId,
            lzPayload,
            payable(msg.sender),
            address(0),
            bytes(""),
            msg.value
        );

        emit SetCapFor(_dstChainId, _toAddress, _cap);
    }

    function tokenPrice() public returns (uint256 price) {
        price = Minter(minter).getTokenPrice();
    }

    function getQuota() external view returns (uint256) {
        uint256 amount = quota[block.timestamp / DAY_INTERVAL];
        if (cap > amount && enable) {
            return cap - amount;
        }
    }
}

File 2 of 29 : Minter.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import {Stone} from "./Stone.sol";
import {StoneVault} from "../StoneVault.sol";

contract Minter {
    // TODO: governable upgrade
    address public stone;
    address payable public vault;

    modifier onlyVault() {
        require(msg.sender == vault, "not vault");
        _;
    }

    constructor(address _stone, address payable _vault) {
        stone = _stone;
        vault = _vault;
    }

    function mint(address _to, uint256 _amount) external onlyVault {
        Stone(stone).mint(_to, _amount);
    }

    function burn(address _from, uint256 _amount) external onlyVault {
        Stone(stone).burn(_from, _amount);
    }

    function setNewVault(address _vault) external onlyVault {
        vault = payable(_vault);
    }

    function getTokenPrice() public returns (uint256 price) {
        price = StoneVault(vault).currentSharePrice();
    }
}

File 3 of 29 : StrategyController.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {TransferHelper} from "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";

import {Strategy} from "./Strategy.sol";
import {AssetsVault} from "../AssetsVault.sol";

contract StrategyController {
    using EnumerableSet for EnumerableSet.AddressSet;

    uint256 internal constant ONE_HUNDRED_PERCENT = 1e6;

    address public stoneVault;
    address payable public immutable assetsVault;

    EnumerableSet.AddressSet private strategies;

    mapping(address => uint256) public ratios;

    struct StrategyDiff {
        address strategy;
        bool isDeposit;
        uint256 amount;
    }

    modifier onlyVault() {
        require(stoneVault == msg.sender, "not vault");
        _;
    }

    constructor(
        address payable _assetsVault,
        address[] memory _strategies,
        uint256[] memory _ratios
    ) {
        require(_assetsVault != address(0), "ZERO ADDRESS");

        uint256 length = _strategies.length;
        for (uint256 i; i < length; i++) {
            require(_strategies[i] != address(0), "ZERO ADDRESS");
        }

        stoneVault = msg.sender;
        assetsVault = _assetsVault;

        _initStrategies(_strategies, _ratios);
    }

    function onlyRebaseStrategies() external {
        _rebase(0, 0);
    }

    function forceWithdraw(
        uint256 _amount
    ) external onlyVault returns (uint256 actualAmount) {
        uint256 balanceBeforeRepay = address(this).balance;

        if (balanceBeforeRepay >= _amount) {
            _repayToVault();

            actualAmount = balanceBeforeRepay;
        } else {
            actualAmount =
                _forceWithdraw(_amount - balanceBeforeRepay) +
                balanceBeforeRepay;
        }
    }

    function setStrategies(
        address[] memory _strategies,
        uint256[] memory _ratios
    ) external onlyVault {
        _setStrategies(_strategies, _ratios);
    }

    function addStrategy(address _strategy) external onlyVault {
        require(!strategies.contains(_strategy), "already exist");

        strategies.add(_strategy);
    }

    function rebaseStrategies(
        uint256 _in,
        uint256 _out
    ) external payable onlyVault {
        _rebase(_in, _out);
    }

    function destroyStrategy(address _strategy) external onlyVault {
        _destoryStrategy(_strategy);
    }

    function _rebase(uint256 _in, uint256 _out) internal {
        require(_in == 0 || _out == 0, "only deposit or withdraw");

        if (_in != 0) {
            AssetsVault(assetsVault).withdraw(address(this), _in);
        }
        uint256 total = getAllStrategyValidValue();
        if (total < _out) {
            total = 0;
        } else {
            total = total + _in - _out;
        }

        uint256 length = strategies.length();
        StrategyDiff[] memory diffs = new StrategyDiff[](length);
        uint256 head;
        uint256 tail = length - 1;
        for (uint i; i < length; i++) {
            address strategy = strategies.at(i);
            if (ratios[strategy] == 0) {
                _clearStrategy(strategy, true);
                continue;
            }
            uint256 newPosition = (total * ratios[strategy]) /
                ONE_HUNDRED_PERCENT;
            uint256 position = getStrategyValidValue(strategy);

            if (newPosition < position) {
                diffs[head] = StrategyDiff(
                    strategy,
                    false,
                    position - newPosition
                );
                head++;
            } else if (newPosition > position) {
                diffs[tail] = StrategyDiff(
                    strategy,
                    true,
                    newPosition - position
                );
                if (tail != 0) {
                    tail--;
                }
            }
        }

        length = diffs.length;
        for (uint256 i; i < length; i++) {
            StrategyDiff memory diff = diffs[i];

            if (diff.amount == 0) {
                continue;
            }

            if (diff.isDeposit) {
                if (address(this).balance < diff.amount) {
                    diff.amount = address(this).balance;
                }
                _depositToStrategy(diff.strategy, diff.amount);
            } else {
                _withdrawFromStrategy(diff.strategy, diff.amount);
            }
        }

        _repayToVault();
    }

    function _repayToVault() internal {
        if (address(this).balance != 0) {
            TransferHelper.safeTransferETH(assetsVault, address(this).balance);
        }
    }

    function _depositToStrategy(address _strategy, uint256 _amount) internal {
        Strategy(_strategy).deposit{value: _amount}();
    }

    function _withdrawFromStrategy(
        address _strategy,
        uint256 _amount
    ) internal {
        Strategy(_strategy).withdraw(_amount);
    }

    function _forceWithdraw(
        uint256 _amount
    ) internal returns (uint256 actualAmount) {
        uint256 length = strategies.length();
        for (uint i; i < length; i++) {
            address strategy = strategies.at(i);

            uint256 withAmount = (_amount * ratios[strategy]) /
                ONE_HUNDRED_PERCENT;

            if (withAmount != 0) {
                actualAmount =
                    Strategy(strategy).instantWithdraw(withAmount) +
                    actualAmount;
            }
        }

        _repayToVault();
    }

    function getStrategyValue(
        address _strategy
    ) public returns (uint256 _value) {
        return Strategy(_strategy).getAllValue();
    }

    function getStrategyValidValue(
        address _strategy
    ) public returns (uint256 _value) {
        return Strategy(_strategy).getInvestedValue();
    }

    function getStrategyPendingValue(
        address _strategy
    ) public returns (uint256 _value) {
        return Strategy(_strategy).getPendingValue();
    }

    function getAllStrategiesValue() public returns (uint256 _value) {
        uint256 length = strategies.length();
        for (uint i; i < length; i++) {
            _value = _value + getStrategyValue(strategies.at(i));
        }
    }

    function getAllStrategyValidValue() public returns (uint256 _value) {
        uint256 length = strategies.length();
        for (uint i; i < length; i++) {
            _value = _value + getStrategyValidValue(strategies.at(i));
        }
    }

    function getAllStrategyPendingValue() public returns (uint256 _value) {
        uint256 length = strategies.length();
        for (uint i; i < length; i++) {
            _value = _value + getStrategyPendingValue(strategies.at(i));
        }
    }

    function getStrategies()
        public
        view
        returns (address[] memory addrs, uint256[] memory portions)
    {
        uint256 length = strategies.length();

        addrs = new address[](length);
        portions = new uint256[](length);

        for (uint256 i; i < length; i++) {
            address addr = strategies.at(i);
            addrs[i] = addr;
            portions[i] = ratios[addr];
        }
    }

    function _initStrategies(
        address[] memory _strategies,
        uint256[] memory _ratios
    ) internal {
        require(_strategies.length == _ratios.length, "invalid length");

        uint256 totalRatio;
        uint256 length = _strategies.length;
        for (uint i; i < length; i++) {
            strategies.add(_strategies[i]);
            ratios[_strategies[i]] = _ratios[i];
            totalRatio = totalRatio + _ratios[i];
        }
        require(totalRatio <= ONE_HUNDRED_PERCENT, "exceed 100%");
    }

    function _setStrategies(
        address[] memory _strategies,
        uint256[] memory _ratios
    ) internal {
        uint256 length = _strategies.length;
        require(length == _ratios.length, "invalid length");

        uint256 oldLength = strategies.length();
        for (uint i; i < oldLength; i++) {
            ratios[strategies.at(i)] = 0;
        }
        uint256 totalRatio;
        for (uint i; i < length; i++) {
            require(
                Strategy(_strategies[i]).controller() == address(this),
                "controller mismatch"
            );
            strategies.add(_strategies[i]);
            ratios[_strategies[i]] = _ratios[i];
            totalRatio = totalRatio + _ratios[i];
        }
        require(totalRatio <= ONE_HUNDRED_PERCENT, "exceed 100%");
    }

    function clearStrategy(address _strategy) public onlyVault {
        _clearStrategy(_strategy, false);
    }

    function _clearStrategy(address _strategy, bool _isRebase) internal {
        Strategy(_strategy).clear();

        if (!_isRebase) {
            _repayToVault();
        }
    }

    function _destoryStrategy(address _strategy) internal {
        require(_couldDestroyStrategy(_strategy), "still active");

        strategies.remove(_strategy);

        _repayToVault();
    }

    function _couldDestroyStrategy(
        address _strategy
    ) internal returns (bool status) {
        return
            ratios[_strategy] == 0 && Strategy(_strategy).getAllValue() < 1e4;
    }

    function setNewVault(address _vault) external onlyVault {
        stoneVault = _vault;
    }

    receive() external payable {}
}

File 4 of 29 : Strategy.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import {StrategyController} from "../strategies/StrategyController.sol";

abstract contract Strategy {
    address payable public immutable controller;

    address public governance;

    string public name;

    modifier onlyGovernance() {
        require(governance == msg.sender, "not governace");
        _;
    }

    event TransferGovernance(address oldOwner, address newOwner);

    constructor(address payable _controller, string memory _name) {
        require(_controller != address(0), "ZERO ADDRESS");

        governance = msg.sender;
        controller = _controller;
        name = _name;
    }

    modifier onlyController() {
        require(controller == msg.sender, "not controller");
        _;
    }

    function deposit() public payable virtual onlyController {}

    function withdraw(
        uint256 _amount
    ) public virtual onlyController returns (uint256 actualAmount) {}

    function instantWithdraw(
        uint256 _amount
    ) public virtual onlyController returns (uint256 actualAmount) {}

    function clear() public virtual onlyController returns (uint256 amount) {}

    function execPendingRequest(
        uint256 _amount
    ) public virtual returns (uint256 amount) {}

    function getAllValue() public virtual returns (uint256 value) {}

    function getPendingValue() public virtual returns (uint256 value) {}

    function getInvestedValue() public virtual returns (uint256 value) {}

    function checkPendingStatus()
        public
        virtual
        returns (uint256 pending, uint256 executable)
    {}

    function setGovernance(address governance_) external onlyGovernance {
        emit TransferGovernance(governance, governance_);
        governance = governance_;
    }
}

File 5 of 29 : VaultMath.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

library VaultMath {
    uint256 internal constant DECIMALS = 18;

    function assetToShares(
        uint256 _assetAmount,
        uint256 _assetPerShare
    ) internal pure returns (uint256) {
        require(_assetPerShare > 1, "Vault Lib: invalid assetPerShare");
        return (_assetAmount * (10 ** DECIMALS)) / _assetPerShare;
    }

    function sharesToAsset(
        uint256 _shares,
        uint256 _assetPerShare
    ) internal pure returns (uint256) {
        require(_assetPerShare > 1, "Vault Lib: invalid assetPerShare");
        return (_shares * _assetPerShare) / (10 ** DECIMALS);
    }
}

File 6 of 29 : StoneVault.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {TransferHelper} from "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";

import {Minter} from "./token/Minter.sol";
import {Stone} from "./token/Stone.sol";
import {AssetsVault} from "./AssetsVault.sol";
import {StrategyController} from "./strategies/StrategyController.sol";

import {VaultMath} from "./libraries/VaultMath.sol";

contract StoneVault is ReentrancyGuard, Ownable {
    uint256 internal constant MULTIPLIER = 1e18;
    uint256 internal constant ONE_HUNDRED_PERCENT = 1e6;
    uint256 internal constant MAXMIUM_FEE_RATE = ONE_HUNDRED_PERCENT / 100; // 1%
    uint256 internal constant MINIMUM_REBASE_INTERVAL = 7 * 24 * 60 * 60;

    uint256 public constant VERSION = 1;

    uint256 public rebaseTimeInterval = 24 * 60 * 60;

    address public immutable minter;
    address public immutable stone;
    address payable public immutable strategyController;
    address payable public immutable assetsVault;

    address public proposal;

    address public feeRecipient;

    uint256 public latestRoundID;

    uint256 public withdrawableAmountInPast;
    uint256 public withdrawingSharesInPast;
    uint256 public withdrawingSharesInRound;

    uint256 public withdrawFeeRate;

    uint256 public rebaseTime;

    mapping(uint256 => uint256) public roundPricePerShare;
    mapping(uint256 => uint256) public settlementTime;

    mapping(address => UserReceipt) public userReceipts;

    struct UserReceipt {
        uint256 withdrawRound;
        uint256 withdrawShares;
        uint256 withdrawableAmount;
    }

    event Deposit(
        address indexed account,
        uint256 amount,
        uint256 mint,
        uint256 round
    );
    event InitiateWithdraw(
        address indexed account,
        uint256 shares,
        uint256 round
    );
    event CancelWithdraw(
        address indexed account,
        uint256 amount,
        uint256 round
    );
    event Withdrawn(address indexed account, uint256 amount, uint256 round);
    event WithdrawnFromStrategy(
        address indexed account,
        uint256 amount,
        uint256 actualAmount,
        uint256 round
    );
    event RollToNextRound(
        uint256 round,
        uint256 vaultIn,
        uint256 vaultOut,
        uint256 sharePrice
    );
    event StragetyAdded(address strategy);
    event StragetyDestroyed(address strategy);
    event StragetyCleared(address strategy);
    event PortfolioConfigUpdated(address[] strategies, uint256[] ratios);
    event FeeCharged(address indexed account, uint256 amount);
    event SetWithdrawFeeRate(uint256 oldRate, uint256 newRate);
    event SetFeeRecipient(address oldAddr, address newAddr);
    event SetRebaseInterval(uint256 interval);

    modifier onlyProposal() {
        require(proposal == msg.sender, "not proposal");
        _;
    }

    constructor(
        address _minter,
        address _proposal,
        address payable _assetsVault,
        address[] memory _strategies,
        uint256[] memory _ratios
    ) {
        require(
            _minter != address(0) &&
                _proposal != address(0) &&
                _assetsVault != address(0),
            "ZERO ADDRESS"
        );

        uint256 length = _strategies.length;
        for (uint256 i; i < length; i++) {
            require(_strategies[i] != address(0), "ZERO ADDRESS");
        }

        minter = _minter;
        proposal = _proposal;
        assetsVault = _assetsVault;

        feeRecipient = msg.sender;

        StrategyController controller = new StrategyController(
            _assetsVault,
            _strategies,
            _ratios
        );
        strategyController = payable(address(controller));
        stone = Minter(_minter).stone();

        roundPricePerShare[0] = MULTIPLIER;
        latestRoundID = 0;
    }

    function deposit()
        external
        payable
        nonReentrant
        returns (uint256 mintAmount)
    {
        mintAmount = _depositFor(msg.value, msg.sender);
    }

    function depositFor(
        address _user
    ) external payable nonReentrant returns (uint256 mintAmount) {
        mintAmount = _depositFor(msg.value, _user);
    }

    function _depositFor(
        uint256 _amount,
        address _user
    ) internal returns (uint256 mintAmount) {
        require(_amount != 0, "too small");

        uint256 sharePrice;
        uint256 currSharePrice = currentSharePrice();
        if (latestRoundID == 0) {
            sharePrice = MULTIPLIER;
        } else {
            uint256 latestSharePrice = roundPricePerShare[latestRoundID - 1];
            sharePrice = latestSharePrice > currSharePrice
                ? latestSharePrice
                : currSharePrice;
        }

        mintAmount = (_amount * MULTIPLIER) / sharePrice;

        AssetsVault(assetsVault).deposit{value: address(this).balance}();
        Minter(minter).mint(_user, mintAmount);

        emit Deposit(_user, _amount, mintAmount, latestRoundID);
    }

    function requestWithdraw(uint256 _shares) external nonReentrant {
        require(_shares != 0, "too small");
        require(latestRoundID != 0, "should withdraw instantly");
        Stone stoneToken = Stone(stone);
        Minter stoneMinter = Minter(minter);

        require(stoneToken.balanceOf(msg.sender) >= _shares, "exceed balance");

        TransferHelper.safeTransferFrom(
            stone,
            msg.sender,
            address(this),
            _shares
        );

        withdrawingSharesInRound = withdrawingSharesInRound + _shares;

        UserReceipt storage receipt = userReceipts[msg.sender];

        if (receipt.withdrawRound == latestRoundID) {
            receipt.withdrawShares = receipt.withdrawShares + _shares;
        } else if (receipt.withdrawRound == 0) {
            receipt.withdrawShares = _shares;
            receipt.withdrawRound = latestRoundID;
        } else {
            // Withdraw previous round share first
            uint256 withdrawAmount = VaultMath.sharesToAsset(
                receipt.withdrawShares,
                roundPricePerShare[receipt.withdrawRound]
            );

            stoneMinter.burn(address(this), receipt.withdrawShares);
            withdrawingSharesInPast =
                withdrawingSharesInPast -
                receipt.withdrawShares;

            receipt.withdrawShares = _shares;
            receipt.withdrawableAmount =
                receipt.withdrawableAmount +
                withdrawAmount;
            receipt.withdrawRound = latestRoundID;
        }

        emit InitiateWithdraw(msg.sender, _shares, latestRoundID);
    }

    function cancelWithdraw(uint256 _shares) external nonReentrant {
        require(_shares != 0, "too small");

        UserReceipt storage receipt = userReceipts[msg.sender];
        require(receipt.withdrawRound == latestRoundID, "no pending withdraw");
        require(receipt.withdrawShares >= _shares, "exceed pending withdraw");

        receipt.withdrawShares = receipt.withdrawShares - _shares;

        TransferHelper.safeTransfer(stone, msg.sender, _shares);

        if (receipt.withdrawShares == 0) {
            receipt.withdrawRound = 0;
        }

        withdrawingSharesInRound = withdrawingSharesInRound - _shares;

        emit CancelWithdraw(msg.sender, _shares, latestRoundID);
    }

    function instantWithdraw(
        uint256 _amount,
        uint256 _shares
    ) external nonReentrant returns (uint256 actualWithdrawn) {
        require(_amount != 0 || _shares != 0, "too small");

        AssetsVault aVault = AssetsVault(assetsVault);
        Minter stoneMinter = Minter(minter);

        (uint256 idleAmount, ) = getVaultAvailableAmount();

        if (_amount != 0) {
            UserReceipt storage receipt = userReceipts[msg.sender];

            if (
                receipt.withdrawRound != latestRoundID &&
                receipt.withdrawRound != 0
            ) {
                // Withdraw previous round share first
                uint256 withdrawAmount = VaultMath.sharesToAsset(
                    receipt.withdrawShares,
                    roundPricePerShare[receipt.withdrawRound]
                );

                stoneMinter.burn(address(this), receipt.withdrawShares);

                withdrawingSharesInPast =
                    withdrawingSharesInPast -
                    receipt.withdrawShares;
                receipt.withdrawShares = 0;
                receipt.withdrawableAmount =
                    receipt.withdrawableAmount +
                    withdrawAmount;
                receipt.withdrawRound = 0;
            }

            require(
                receipt.withdrawableAmount >= _amount,
                "exceed withdrawable"
            );

            receipt.withdrawableAmount = receipt.withdrawableAmount - _amount;
            withdrawableAmountInPast = withdrawableAmountInPast - _amount;
            actualWithdrawn = _amount;

            emit Withdrawn(msg.sender, _amount, latestRoundID);
        }

        if (_shares != 0) {
            uint256 sharePrice;

            if (latestRoundID == 0) {
                sharePrice = MULTIPLIER;
            } else {
                uint256 currSharePrice = currentSharePrice();
                uint256 latestSharePrice = roundPricePerShare[
                    latestRoundID - 1
                ];

                sharePrice = latestSharePrice < currSharePrice
                    ? latestSharePrice
                    : currSharePrice;
            }

            uint256 ethAmount = VaultMath.sharesToAsset(_shares, sharePrice);

            stoneMinter.burn(msg.sender, _shares);

            if (ethAmount <= idleAmount) {
                actualWithdrawn = actualWithdrawn + ethAmount;

                emit Withdrawn(msg.sender, ethAmount, latestRoundID);
            } else {
                actualWithdrawn = actualWithdrawn + idleAmount;
                ethAmount = ethAmount - idleAmount;

                StrategyController controller = StrategyController(
                    strategyController
                );
                uint256 actualAmount = controller.forceWithdraw(ethAmount);

                actualWithdrawn = actualWithdrawn + actualAmount;

                emit WithdrawnFromStrategy(
                    msg.sender,
                    ethAmount,
                    actualAmount,
                    latestRoundID
                );
            }
        }

        require(aVault.getBalance() >= actualWithdrawn, "still need wait");

        uint256 withFee;
        if (withdrawFeeRate != 0) {
            withFee = (actualWithdrawn * withdrawFeeRate) / ONE_HUNDRED_PERCENT;
            aVault.withdraw(feeRecipient, withFee);

            emit FeeCharged(msg.sender, withFee);
        }
        aVault.withdraw(msg.sender, actualWithdrawn - withFee);
    }

    function rollToNextRound() external {
        require(
            block.timestamp > rebaseTime + rebaseTimeInterval,
            "already rebased"
        );

        StrategyController controller = StrategyController(strategyController);
        AssetsVault aVault = AssetsVault(assetsVault);
        uint256 previewSharePrice = currentSharePrice();

        uint256 vaultBalance = aVault.getBalance();
        uint256 amountToWithdraw = VaultMath.sharesToAsset(
            withdrawingSharesInRound,
            previewSharePrice
        );
        uint256 amountVaultNeed = withdrawableAmountInPast + amountToWithdraw;
        uint256 allPendingValue = controller.getAllStrategyPendingValue();

        uint256 vaultIn;
        uint256 vaultOut;

        if (vaultBalance > amountVaultNeed) {
            vaultIn = vaultBalance - amountVaultNeed;
        } else if (vaultBalance + allPendingValue < amountVaultNeed) {
            vaultOut = amountVaultNeed - vaultBalance - allPendingValue;
        }

        controller.rebaseStrategies(vaultIn, vaultOut);

        uint256 newSharePrice = currentSharePrice();
        roundPricePerShare[latestRoundID] = previewSharePrice < newSharePrice
            ? previewSharePrice
            : newSharePrice;

        settlementTime[latestRoundID] = block.timestamp;
        latestRoundID = latestRoundID + 1;

        withdrawingSharesInPast =
            withdrawingSharesInPast +
            withdrawingSharesInRound;
        withdrawableAmountInPast =
            withdrawableAmountInPast +
            VaultMath.sharesToAsset(withdrawingSharesInRound, newSharePrice);
        withdrawingSharesInRound = 0;
        rebaseTime = block.timestamp;

        emit RollToNextRound(latestRoundID, vaultIn, vaultOut, newSharePrice);
    }

    function addStrategy(address _strategy) external onlyProposal {
        StrategyController controller = StrategyController(strategyController);

        controller.addStrategy(_strategy);
        emit StragetyAdded(_strategy);
    }

    function destroyStrategy(address _strategy) external onlyOwner {
        StrategyController controller = StrategyController(strategyController);

        controller.destroyStrategy(_strategy);
        emit StragetyDestroyed(_strategy);
    }

    function clearStrategy(address _strategy) external onlyOwner {
        StrategyController controller = StrategyController(strategyController);

        controller.clearStrategy(_strategy);
        emit StragetyCleared(_strategy);
    }

    function updatePortfolioConfig(
        address[] memory _strategies,
        uint256[] memory _ratios
    ) external onlyProposal {
        StrategyController controller = StrategyController(strategyController);

        controller.setStrategies(_strategies, _ratios);

        emit PortfolioConfigUpdated(_strategies, _ratios);
    }

    function updateProposal(address _proposal) external onlyProposal {
        proposal = _proposal;
    }

    function migrateVault(address _vault) external onlyProposal {
        Minter(minter).setNewVault(_vault);
        AssetsVault(assetsVault).setNewVault(_vault);
        StrategyController(strategyController).setNewVault(_vault);
    }

    function currentSharePrice() public returns (uint256 price) {
        Stone stoneToken = Stone(stone);
        uint256 totalStone = stoneToken.totalSupply();
        if (
            latestRoundID == 0 ||
            totalStone == 0 ||
            totalStone == withdrawingSharesInPast
        ) {
            return MULTIPLIER;
        }

        uint256 etherAmount = AssetsVault(assetsVault).getBalance() +
            StrategyController(strategyController).getAllStrategiesValue() -
            withdrawableAmountInPast;
        uint256 activeShare = totalStone - withdrawingSharesInPast;

        return (etherAmount * MULTIPLIER) / activeShare;
    }

    function getVaultAvailableAmount()
        public
        returns (uint256 idleAmount, uint256 investedAmount)
    {
        AssetsVault vault = AssetsVault(assetsVault);

        if (vault.getBalance() > withdrawableAmountInPast) {
            idleAmount = vault.getBalance() - withdrawableAmountInPast;
        }

        investedAmount = StrategyController(strategyController)
            .getAllStrategyValidValue();
    }

    function setWithdrawFeeRate(uint256 _withdrawFeeRate) external onlyOwner {
        require(_withdrawFeeRate <= MAXMIUM_FEE_RATE, "exceed maximum");

        emit SetWithdrawFeeRate(withdrawFeeRate, _withdrawFeeRate);

        withdrawFeeRate = _withdrawFeeRate;
    }

    function setFeeRecipient(address _feeRecipient) external onlyOwner {
        require(_feeRecipient != address(0), "zero address");

        emit SetFeeRecipient(feeRecipient, _feeRecipient);

        feeRecipient = _feeRecipient;
    }

    function setRebaseInterval(uint256 _interval) external onlyOwner {
        require(_interval <= MINIMUM_REBASE_INTERVAL, "invalid");

        rebaseTimeInterval = _interval;
        emit SetRebaseInterval(rebaseTimeInterval);
    }

    receive() external payable {}
}

File 7 of 29 : AssetsVault.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import {TransferHelper} from "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";

contract AssetsVault {
    address public stoneVault;
    address public strategyController;

    modifier onlyPermit() {
        require(
            stoneVault == msg.sender || strategyController == msg.sender,
            "not permit"
        );
        _;
    }

    constructor(address _stoneVault, address _strategyController) {
        require(
            _stoneVault != address(0) && _strategyController != address(0),
            "ZERO ADDRESS"
        );
        stoneVault = _stoneVault;
        strategyController = _strategyController;
    }

    function deposit() external payable {
        require(msg.value != 0, "too small");
    }

    function withdraw(address _to, uint256 _amount) external onlyPermit {
        TransferHelper.safeTransferETH(_to, _amount);
    }

    function setNewVault(address _vault) external onlyPermit {
        stoneVault = _vault;
    }

    function getBalance() external view returns (uint256 amount) {
        amount = address(this).balance;
    }

    receive() external payable {}
}

File 8 of 29 : TransferHelper.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.6.0;

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';

library TransferHelper {
    /// @notice Transfers tokens from the targeted address to the given destination
    /// @notice Errors with 'STF' if transfer fails
    /// @param token The contract address of the token to be transferred
    /// @param from The originating address from which the tokens will be transferred
    /// @param to The destination address of the transfer
    /// @param value The amount to be transferred
    function safeTransferFrom(
        address token,
        address from,
        address to,
        uint256 value
    ) internal {
        (bool success, bytes memory data) =
            token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF');
    }

    /// @notice Transfers tokens from msg.sender to a recipient
    /// @dev Errors with ST if transfer fails
    /// @param token The contract address of the token which will be transferred
    /// @param to The recipient of the transfer
    /// @param value The value of the transfer
    function safeTransfer(
        address token,
        address to,
        uint256 value
    ) internal {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST');
    }

    /// @notice Approves the stipulated contract to spend the given allowance in the given token
    /// @dev Errors with 'SA' if transfer fails
    /// @param token The contract address of the token to be approved
    /// @param to The target of the approval
    /// @param value The amount of the given token the target will be allowed to spend
    function safeApprove(
        address token,
        address to,
        uint256 value
    ) internal {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'SA');
    }

    /// @notice Transfers ETH to the recipient address
    /// @dev Fails with `STE`
    /// @param to The destination of the transfer
    /// @param value The value to be transferred
    function safeTransferETH(address to, uint256 value) internal {
        (bool success, ) = to.call{value: value}(new bytes(0));
        require(success, 'STE');
    }
}

File 9 of 29 : EnumerableSet.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}

File 10 of 29 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 11 of 29 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 12 of 29 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

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

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

File 13 of 29 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

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

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

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

File 14 of 29 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

File 15 of 29 : ERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

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

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

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

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

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

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

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

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

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

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

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

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

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

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

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

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
            // decrementing then incrementing.
            _balances[to] += amount;
        }

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

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

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

        _totalSupply += amount;
        unchecked {
            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
            _balances[account] += amount;
        }
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

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

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

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
            // Overflow not possible: amount <= accountBalance <= totalSupply.
            _totalSupply -= amount;
        }

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

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

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

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

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

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

File 16 of 29 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @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;

    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
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // 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 17 of 29 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

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

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

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

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

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

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

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

File 18 of 29 : ExcessivelySafeCall.sol
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.7.6;

library ExcessivelySafeCall {
    uint256 constant LOW_28_MASK =
    0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff;

    /// @notice Use when you _really_ really _really_ don't trust the called
    /// contract. This prevents the called contract from causing reversion of
    /// the caller in as many ways as we can.
    /// @dev The main difference between this and a solidity low-level call is
    /// that we limit the number of bytes that the callee can cause to be
    /// copied to caller memory. This prevents stupid things like malicious
    /// contracts returning 10,000,000 bytes causing a local OOG when copying
    /// to memory.
    /// @param _target The address to call
    /// @param _gas The amount of gas to forward to the remote contract
    /// @param _maxCopy The maximum number of bytes of returndata to copy
    /// to memory.
    /// @param _calldata The data to send to the remote contract
    /// @return success and returndata, as `.call()`. Returndata is capped to
    /// `_maxCopy` bytes.
    function excessivelySafeCall(
        address _target,
        uint256 _gas,
        uint16 _maxCopy,
        bytes memory _calldata
    ) internal returns (bool, bytes memory) {
        // set up for assembly call
        uint256 _toCopy;
        bool _success;
        bytes memory _returnData = new bytes(_maxCopy);
        // dispatch message to recipient
        // by assembly calling "handle" function
        // we call via assembly to avoid memcopying a very large returndata
        // returned by a malicious contract
        assembly {
            _success := call(
            _gas, // gas
            _target, // recipient
            0, // ether value
            add(_calldata, 0x20), // inloc
            mload(_calldata), // inlen
            0, // outloc
            0 // outlen
            )
        // limit our copy to 256 bytes
            _toCopy := returndatasize()
            if gt(_toCopy, _maxCopy) {
                _toCopy := _maxCopy
            }
        // Store the length of the copied bytes
            mstore(_returnData, _toCopy)
        // copy the bytes from returndata[0:_toCopy]
            returndatacopy(add(_returnData, 0x20), 0, _toCopy)
        }
        return (_success, _returnData);
    }

    /// @notice Use when you _really_ really _really_ don't trust the called
    /// contract. This prevents the called contract from causing reversion of
    /// the caller in as many ways as we can.
    /// @dev The main difference between this and a solidity low-level call is
    /// that we limit the number of bytes that the callee can cause to be
    /// copied to caller memory. This prevents stupid things like malicious
    /// contracts returning 10,000,000 bytes causing a local OOG when copying
    /// to memory.
    /// @param _target The address to call
    /// @param _gas The amount of gas to forward to the remote contract
    /// @param _maxCopy The maximum number of bytes of returndata to copy
    /// to memory.
    /// @param _calldata The data to send to the remote contract
    /// @return success and returndata, as `.call()`. Returndata is capped to
    /// `_maxCopy` bytes.
    function excessivelySafeStaticCall(
        address _target,
        uint256 _gas,
        uint16 _maxCopy,
        bytes memory _calldata
    ) internal view returns (bool, bytes memory) {
        // set up for assembly call
        uint256 _toCopy;
        bool _success;
        bytes memory _returnData = new bytes(_maxCopy);
        // dispatch message to recipient
        // by assembly calling "handle" function
        // we call via assembly to avoid memcopying a very large returndata
        // returned by a malicious contract
        assembly {
            _success := staticcall(
            _gas, // gas
            _target, // recipient
            add(_calldata, 0x20), // inloc
            mload(_calldata), // inlen
            0, // outloc
            0 // outlen
            )
        // limit our copy to 256 bytes
            _toCopy := returndatasize()
            if gt(_toCopy, _maxCopy) {
                _toCopy := _maxCopy
            }
        // Store the length of the copied bytes
            mstore(_returnData, _toCopy)
        // copy the bytes from returndata[0:_toCopy]
            returndatacopy(add(_returnData, 0x20), 0, _toCopy)
        }
        return (_success, _returnData);
    }

    /**
     * @notice Swaps function selectors in encoded contract calls
     * @dev Allows reuse of encoded calldata for functions with identical
     * argument types but different names. It simply swaps out the first 4 bytes
     * for the new selector. This function modifies memory in place, and should
     * only be used with caution.
     * @param _newSelector The new 4-byte selector
     * @param _buf The encoded contract args
     */
    function swapSelector(bytes4 _newSelector, bytes memory _buf)
    internal
    pure
    {
        require(_buf.length >= 4);
        uint256 _mask = LOW_28_MASK;
        assembly {
        // load the first word of
            let _word := mload(add(_buf, 0x20))
        // mask out the top 4 bytes
        // /x
            _word := and(_word, _mask)
            _word := or(_newSelector, _word)
            mstore(add(_buf, 0x20), _word)
        }
    }
}

File 19 of 29 : BytesLib.sol
// SPDX-License-Identifier: Unlicense
/*
 * @title Solidity Bytes Arrays Utils
 * @author Gonçalo Sá <[email protected]>
 *
 * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
 *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
 */
pragma solidity >=0.8.0 <0.9.0;


library BytesLib {
    function concat(
        bytes memory _preBytes,
        bytes memory _postBytes
    )
    internal
    pure
    returns (bytes memory)
    {
        bytes memory tempBytes;

        assembly {
        // Get a location of some free memory and store it in tempBytes as
        // Solidity does for memory variables.
            tempBytes := mload(0x40)

        // Store the length of the first bytes array at the beginning of
        // the memory for tempBytes.
            let length := mload(_preBytes)
            mstore(tempBytes, length)

        // Maintain a memory counter for the current write location in the
        // temp bytes array by adding the 32 bytes for the array length to
        // the starting location.
            let mc := add(tempBytes, 0x20)
        // Stop copying when the memory counter reaches the length of the
        // first bytes array.
            let end := add(mc, length)

            for {
            // Initialize a copy counter to the start of the _preBytes data,
            // 32 bytes into its memory.
                let cc := add(_preBytes, 0x20)
            } lt(mc, end) {
            // Increase both counters by 32 bytes each iteration.
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
            // Write the _preBytes data into the tempBytes memory 32 bytes
            // at a time.
                mstore(mc, mload(cc))
            }

        // Add the length of _postBytes to the current length of tempBytes
        // and store it as the new length in the first 32 bytes of the
        // tempBytes memory.
            length := mload(_postBytes)
            mstore(tempBytes, add(length, mload(tempBytes)))

        // Move the memory counter back from a multiple of 0x20 to the
        // actual end of the _preBytes data.
            mc := end
        // Stop copying when the memory counter reaches the new combined
        // length of the arrays.
            end := add(mc, length)

            for {
                let cc := add(_postBytes, 0x20)
            } lt(mc, end) {
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                mstore(mc, mload(cc))
            }

        // Update the free-memory pointer by padding our last write location
        // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
        // next 32 byte block, then round down to the nearest multiple of
        // 32. If the sum of the length of the two arrays is zero then add
        // one before rounding down to leave a blank 32 bytes (the length block with 0).
            mstore(0x40, and(
            add(add(end, iszero(add(length, mload(_preBytes)))), 31),
            not(31) // Round down to the nearest 32 bytes.
            ))
        }

        return tempBytes;
    }

    function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
        assembly {
        // Read the first 32 bytes of _preBytes storage, which is the length
        // of the array. (We don't need to use the offset into the slot
        // because arrays use the entire slot.)
            let fslot := sload(_preBytes.slot)
        // Arrays of 31 bytes or less have an even value in their slot,
        // while longer arrays have an odd value. The actual length is
        // the slot divided by two for odd values, and the lowest order
        // byte divided by two for even values.
        // If the slot is even, bitwise and the slot with 255 and divide by
        // two to get the length. If the slot is odd, bitwise and the slot
        // with -1 and divide by two.
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)
            let newlength := add(slength, mlength)
        // slength can contain both the length and contents of the array
        // if length < 32 bytes so let's prepare for that
        // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
            switch add(lt(slength, 32), lt(newlength, 32))
            case 2 {
            // Since the new array still fits in the slot, we just need to
            // update the contents of the slot.
            // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
                sstore(
                _preBytes.slot,
                // all the modifications to the slot are inside this
                // next block
                add(
                // we can just add to the slot contents because the
                // bytes we want to change are the LSBs
                fslot,
                add(
                mul(
                div(
                // load the bytes from memory
                mload(add(_postBytes, 0x20)),
                // zero all bytes to the right
                exp(0x100, sub(32, mlength))
                ),
                // and now shift left the number of bytes to
                // leave space for the length in the slot
                exp(0x100, sub(32, newlength))
                ),
                // increase length by the double of the memory
                // bytes length
                mul(mlength, 2)
                )
                )
                )
            }
            case 1 {
            // The stored value fits in the slot, but the combined value
            // will exceed it.
            // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes.slot)
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

            // save new length
                sstore(_preBytes.slot, add(mul(newlength, 2), 1))

            // The contents of the _postBytes array start 32 bytes into
            // the structure. Our first read should obtain the `submod`
            // bytes that can fit into the unused space in the last word
            // of the stored array. To get this, we read 32 bytes starting
            // from `submod`, so the data we read overlaps with the array
            // contents by `submod` bytes. Masking the lowest-order
            // `submod` bytes allows us to add that value directly to the
            // stored value.

                let submod := sub(32, slength)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(
                sc,
                add(
                and(
                fslot,
                0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
                ),
                and(mload(mc), mask)
                )
                )

                for {
                    mc := add(mc, 0x20)
                    sc := add(sc, 1)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } {
                    sstore(sc, mload(mc))
                }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
            default {
            // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes.slot)
            // Start copying to the last used word of the stored array.
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

            // save new length
                sstore(_preBytes.slot, add(mul(newlength, 2), 1))

            // Copy over the first `submod` bytes of the new data as in
            // case 1 above.
                let slengthmod := mod(slength, 32)
                let mlengthmod := mod(mlength, 32)
                let submod := sub(32, slengthmod)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(sc, add(sload(sc), and(mload(mc), mask)))

                for {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } {
                    sstore(sc, mload(mc))
                }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
        }
    }

    function slice(
        bytes memory _bytes,
        uint256 _start,
        uint256 _length
    )
    internal
    pure
    returns (bytes memory)
    {
        require(_length + 31 >= _length, "slice_overflow");
        require(_bytes.length >= _start + _length, "slice_outOfBounds");

        bytes memory tempBytes;

        assembly {
            switch iszero(_length)
            case 0 {
            // Get a location of some free memory and store it in tempBytes as
            // Solidity does for memory variables.
                tempBytes := mload(0x40)

            // The first word of the slice result is potentially a partial
            // word read from the original array. To read it, we calculate
            // the length of that partial word and start copying that many
            // bytes into the array. The first word we copy will start with
            // data we don't care about, but the last `lengthmod` bytes will
            // land at the beginning of the contents of the new array. When
            // we're done copying, we overwrite the full first word with
            // the actual length of the slice.
                let lengthmod := and(_length, 31)

            // The multiplication in the next line is necessary
            // because when slicing multiples of 32 bytes (lengthmod == 0)
            // the following copy loop was copying the origin's length
            // and then ending prematurely not copying everything it should.
                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                let end := add(mc, _length)

                for {
                // The multiplication in the next line has the same exact purpose
                // as the one above.
                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                } lt(mc, end) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    mstore(mc, mload(cc))
                }

                mstore(tempBytes, _length)

            //update free-memory pointer
            //allocating the array padded to 32 bytes like the compiler does now
                mstore(0x40, and(add(mc, 31), not(31)))
            }
            //if we want a zero-length slice let's just return a zero-length array
            default {
                tempBytes := mload(0x40)
            //zero out the 32 bytes slice we are about to return
            //we need to do it because Solidity does not garbage collect
                mstore(tempBytes, 0)

                mstore(0x40, add(tempBytes, 0x20))
            }
        }

        return tempBytes;
    }

    function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
        require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
        address tempAddress;

        assembly {
            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
        }

        return tempAddress;
    }

    function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
        require(_bytes.length >= _start + 1 , "toUint8_outOfBounds");
        uint8 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x1), _start))
        }

        return tempUint;
    }

    function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
        require(_bytes.length >= _start + 2, "toUint16_outOfBounds");
        uint16 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x2), _start))
        }

        return tempUint;
    }

    function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
        require(_bytes.length >= _start + 4, "toUint32_outOfBounds");
        uint32 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x4), _start))
        }

        return tempUint;
    }

    function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
        require(_bytes.length >= _start + 8, "toUint64_outOfBounds");
        uint64 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x8), _start))
        }

        return tempUint;
    }

    function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {
        require(_bytes.length >= _start + 12, "toUint96_outOfBounds");
        uint96 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0xc), _start))
        }

        return tempUint;
    }

    function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
        require(_bytes.length >= _start + 16, "toUint128_outOfBounds");
        uint128 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x10), _start))
        }

        return tempUint;
    }

    function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
        require(_bytes.length >= _start + 32, "toUint256_outOfBounds");
        uint256 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x20), _start))
        }

        return tempUint;
    }

    function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
        require(_bytes.length >= _start + 32, "toBytes32_outOfBounds");
        bytes32 tempBytes32;

        assembly {
            tempBytes32 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes32;
    }

    function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
        bool success = true;

        assembly {
            let length := mload(_preBytes)

        // if lengths don't match the arrays are not equal
            switch eq(length, mload(_postBytes))
            case 1 {
            // cb is a circuit breaker in the for loop since there's
            //  no said feature for inline assembly loops
            // cb = 1 - don't breaker
            // cb = 0 - break
                let cb := 1

                let mc := add(_preBytes, 0x20)
                let end := add(mc, length)

                for {
                    let cc := add(_postBytes, 0x20)
                // the next line is the loop condition:
                // while(uint256(mc < end) + cb == 2)
                } eq(add(lt(mc, end), cb), 2) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                // if any of these checks fails then arrays are not equal
                    if iszero(eq(mload(mc), mload(cc))) {
                    // unsuccess:
                        success := 0
                        cb := 0
                    }
                }
            }
            default {
            // unsuccess:
                success := 0
            }
        }

        return success;
    }

    function equalStorage(
        bytes storage _preBytes,
        bytes memory _postBytes
    )
    internal
    view
    returns (bool)
    {
        bool success = true;

        assembly {
        // we know _preBytes_offset is 0
            let fslot := sload(_preBytes.slot)
        // Decode the length of the stored array like in concatStorage().
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)

        // if lengths don't match the arrays are not equal
            switch eq(slength, mlength)
            case 1 {
            // slength can contain both the length and contents of the array
            // if length < 32 bytes so let's prepare for that
            // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                if iszero(iszero(slength)) {
                    switch lt(slength, 32)
                    case 1 {
                    // blank the last byte which is the length
                        fslot := mul(div(fslot, 0x100), 0x100)

                        if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
                        // unsuccess:
                            success := 0
                        }
                    }
                    default {
                    // cb is a circuit breaker in the for loop since there's
                    //  no said feature for inline assembly loops
                    // cb = 1 - don't breaker
                    // cb = 0 - break
                        let cb := 1

                    // get the keccak hash to get the contents of the array
                        mstore(0x0, _preBytes.slot)
                        let sc := keccak256(0x0, 0x20)

                        let mc := add(_postBytes, 0x20)
                        let end := add(mc, mlength)

                    // the next line is the loop condition:
                    // while(uint256(mc < end) + cb == 2)
                        for {} eq(add(lt(mc, end), cb), 2) {
                            sc := add(sc, 1)
                            mc := add(mc, 0x20)
                        } {
                            if iszero(eq(sload(sc), mload(mc))) {
                            // unsuccess:
                                success := 0
                                cb := 0
                            }
                        }
                    }
                }
            }
            default {
            // unsuccess:
                success := 0
            }
        }

        return success;
    }
}

File 20 of 29 : BasedOFT.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../OFT.sol";

contract BasedOFT is OFT {
    constructor(string memory _name, string memory _symbol, address _lzEndpoint) OFT(_name, _symbol, _lzEndpoint) {}

    function circulatingSupply() public view virtual override returns (uint) {
        unchecked {
            return totalSupply() - balanceOf(address(this));
        }
    }

    function _debitFrom(address _from, uint16, bytes memory, uint _amount) internal virtual override returns(uint) {
        address spender = _msgSender();
        if (_from != spender) _spendAllowance(_from, spender, _amount);
        _transfer(_from, address(this), _amount);
        return _amount;
    }

    function _creditTo(uint16, address _toAddress, uint _amount) internal virtual override returns(uint) {
        _transfer(address(this), _toAddress, _amount);
        return _amount;
    }
}

File 21 of 29 : OFTCore.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../../lzApp/NonblockingLzApp.sol";
import "./IOFTCore.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";

abstract contract OFTCore is NonblockingLzApp, ERC165, IOFTCore {
    using BytesLib for bytes;

    uint public constant NO_EXTRA_GAS = 0;

    // packet type
    uint16 public constant PT_SEND = 0;

    bool public useCustomAdapterParams;

    constructor(address _lzEndpoint) NonblockingLzApp(_lzEndpoint) {}

    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return interfaceId == type(IOFTCore).interfaceId || super.supportsInterface(interfaceId);
    }

    function estimateSendFee(uint16 _dstChainId, bytes calldata _toAddress, uint _amount, bool _useZro, bytes calldata _adapterParams) public view virtual override returns (uint nativeFee, uint zroFee) {
        // mock the payload for sendFrom()
        bytes memory payload = abi.encode(PT_SEND, _toAddress, _amount);
        return lzEndpoint.estimateFees(_dstChainId, address(this), payload, _useZro, _adapterParams);
    }

    function sendFrom(address _from, uint16 _dstChainId, bytes calldata _toAddress, uint _amount, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) public payable virtual override {
        _send(_from, _dstChainId, _toAddress, _amount, _refundAddress, _zroPaymentAddress, _adapterParams);
    }

    function setUseCustomAdapterParams(bool _useCustomAdapterParams) public virtual onlyOwner {
        useCustomAdapterParams = _useCustomAdapterParams;
        emit SetUseCustomAdapterParams(_useCustomAdapterParams);
    }

    function _nonblockingLzReceive(uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload) internal virtual override {
        uint16 packetType;
        assembly {
            packetType := mload(add(_payload, 32))
        }

        if (packetType == PT_SEND) {
            _sendAck(_srcChainId, _srcAddress, _nonce, _payload);
        } else {
            revert("OFTCore: unknown packet type");
        }
    }

    function _send(address _from, uint16 _dstChainId, bytes memory _toAddress, uint _amount, address payable _refundAddress, address _zroPaymentAddress, bytes memory _adapterParams) internal virtual {
        _checkAdapterParams(_dstChainId, PT_SEND, _adapterParams, NO_EXTRA_GAS);

        uint amount = _debitFrom(_from, _dstChainId, _toAddress, _amount);

        bytes memory lzPayload = abi.encode(PT_SEND, _toAddress, amount);
        _lzSend(_dstChainId, lzPayload, _refundAddress, _zroPaymentAddress, _adapterParams, msg.value);

        emit SendToChain(_dstChainId, _from, _toAddress, amount);
    }

    function _sendAck(uint16 _srcChainId, bytes memory, uint64, bytes memory _payload) internal virtual {
        (, bytes memory toAddressBytes, uint amount) = abi.decode(_payload, (uint16, bytes, uint));

        address to = toAddressBytes.toAddress(0);

        amount = _creditTo(_srcChainId, to, amount);
        emit ReceiveFromChain(_srcChainId, to, amount);
    }

    function _checkAdapterParams(uint16 _dstChainId, uint16 _pkType, bytes memory _adapterParams, uint _extraGas) internal virtual {
        if (useCustomAdapterParams) {
            _checkGasLimit(_dstChainId, _pkType, _adapterParams, _extraGas);
        } else {
            require(_adapterParams.length == 0, "OFTCore: _adapterParams must be empty.");
        }
    }

    function _debitFrom(address _from, uint16 _dstChainId, bytes memory _toAddress, uint _amount) internal virtual returns(uint);

    function _creditTo(uint16 _srcChainId, address _toAddress, uint _amount) internal virtual returns(uint);
}

File 22 of 29 : OFT.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "./IOFT.sol";
import "./OFTCore.sol";

// override decimal() function is needed
contract OFT is OFTCore, ERC20, IOFT {
    constructor(string memory _name, string memory _symbol, address _lzEndpoint) ERC20(_name, _symbol) OFTCore(_lzEndpoint) {}

    function supportsInterface(bytes4 interfaceId) public view virtual override(OFTCore, IERC165) returns (bool) {
        return interfaceId == type(IOFT).interfaceId || interfaceId == type(IERC20).interfaceId || super.supportsInterface(interfaceId);
    }

    function token() public view virtual override returns (address) {
        return address(this);
    }

    function circulatingSupply() public view virtual override returns (uint) {
        return totalSupply();
    }

    function _debitFrom(address _from, uint16, bytes memory, uint _amount) internal virtual override returns(uint) {
        address spender = _msgSender();
        if (_from != spender) _spendAllowance(_from, spender, _amount);
        _burn(_from, _amount);
        return _amount;
    }

    function _creditTo(uint16, address _toAddress, uint _amount) internal virtual override returns(uint) {
        _mint(_toAddress, _amount);
        return _amount;
    }
}

File 23 of 29 : IOFTCore.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.5.0;

import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

/**
 * @dev Interface of the IOFT core standard
 */
interface IOFTCore is IERC165 {
    /**
     * @dev estimate send token `_tokenId` to (`_dstChainId`, `_toAddress`)
     * _dstChainId - L0 defined chain id to send tokens too
     * _toAddress - dynamic bytes array which contains the address to whom you are sending tokens to on the dstChain
     * _amount - amount of the tokens to transfer
     * _useZro - indicates to use zro to pay L0 fees
     * _adapterParam - flexible bytes array to indicate messaging adapter services in L0
     */
    function estimateSendFee(uint16 _dstChainId, bytes calldata _toAddress, uint _amount, bool _useZro, bytes calldata _adapterParams) external view returns (uint nativeFee, uint zroFee);

    /**
     * @dev send `_amount` amount of token to (`_dstChainId`, `_toAddress`) from `_from`
     * `_from` the owner of token
     * `_dstChainId` the destination chain identifier
     * `_toAddress` can be any size depending on the `dstChainId`.
     * `_amount` the quantity of tokens in wei
     * `_refundAddress` the address LayerZero refunds if too much message fee is sent
     * `_zroPaymentAddress` set to address(0x0) if not paying in ZRO (LayerZero Token)
     * `_adapterParams` is a flexible bytes array to indicate messaging adapter services
     */
    function sendFrom(address _from, uint16 _dstChainId, bytes calldata _toAddress, uint _amount, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable;

    /**
     * @dev returns the circulating amount of tokens on current chain
     */
    function circulatingSupply() external view returns (uint);

    /**
     * @dev returns the address of the ERC20 token
     */
    function token() external view returns (address);

    /**
     * @dev Emitted when `_amount` tokens are moved from the `_sender` to (`_dstChainId`, `_toAddress`)
     * `_nonce` is the outbound nonce
     */
    event SendToChain(uint16 indexed _dstChainId, address indexed _from, bytes _toAddress, uint _amount);

    /**
     * @dev Emitted when `_amount` tokens are received from `_srcChainId` into the `_toAddress` on the local chain.
     * `_nonce` is the inbound nonce.
     */
    event ReceiveFromChain(uint16 indexed _srcChainId, address indexed _to, uint _amount);

    event SetUseCustomAdapterParams(bool _useCustomAdapterParams);
}

File 24 of 29 : IOFT.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.5.0;

import "./IOFTCore.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
 * @dev Interface of the OFT standard
 */
interface IOFT is IOFTCore, IERC20 {

}

File 25 of 29 : NonblockingLzApp.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./LzApp.sol";
import "../util/ExcessivelySafeCall.sol";

/*
 * the default LayerZero messaging behaviour is blocking, i.e. any failed message will block the channel
 * this abstract class try-catch all fail messages and store locally for future retry. hence, non-blocking
 * NOTE: if the srcAddress is not configured properly, it will still block the message pathway from (srcChainId, srcAddress)
 */
abstract contract NonblockingLzApp is LzApp {
    using ExcessivelySafeCall for address;

    constructor(address _endpoint) LzApp(_endpoint) {}

    mapping(uint16 => mapping(bytes => mapping(uint64 => bytes32))) public failedMessages;

    event MessageFailed(uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes _payload, bytes _reason);
    event RetryMessageSuccess(uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes32 _payloadHash);

    // overriding the virtual function in LzReceiver
    function _blockingLzReceive(uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload) internal virtual override {
        (bool success, bytes memory reason) = address(this).excessivelySafeCall(gasleft(), 150, abi.encodeWithSelector(this.nonblockingLzReceive.selector, _srcChainId, _srcAddress, _nonce, _payload));
        // try-catch all errors/exceptions
        if (!success) {
            _storeFailedMessage(_srcChainId, _srcAddress, _nonce, _payload, reason);
        }
    }

    function _storeFailedMessage(uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload, bytes memory _reason) internal virtual {
        failedMessages[_srcChainId][_srcAddress][_nonce] = keccak256(_payload);
        emit MessageFailed(_srcChainId, _srcAddress, _nonce, _payload, _reason);
    }

    function nonblockingLzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) public virtual {
        // only internal transaction
        require(_msgSender() == address(this), "NonblockingLzApp: caller must be LzApp");
        _nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);
    }

    //@notice override this function
    function _nonblockingLzReceive(uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload) internal virtual;

    function retryMessage(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) public payable virtual {
        // assert there is message to retry
        bytes32 payloadHash = failedMessages[_srcChainId][_srcAddress][_nonce];
        require(payloadHash != bytes32(0), "NonblockingLzApp: no stored message");
        require(keccak256(_payload) == payloadHash, "NonblockingLzApp: invalid payload");
        // clear the stored message
        failedMessages[_srcChainId][_srcAddress][_nonce] = bytes32(0);
        // execute the message. revert if it fails again
        _nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);
        emit RetryMessageSuccess(_srcChainId, _srcAddress, _nonce, payloadHash);
    }
}

File 26 of 29 : LzApp.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";
import "../interfaces/ILayerZeroReceiver.sol";
import "../interfaces/ILayerZeroUserApplicationConfig.sol";
import "../interfaces/ILayerZeroEndpoint.sol";
import "../util/BytesLib.sol";

/*
 * a generic LzReceiver implementation
 */
abstract contract LzApp is Ownable, ILayerZeroReceiver, ILayerZeroUserApplicationConfig {
    using BytesLib for bytes;

    // ua can not send payload larger than this by default, but it can be changed by the ua owner
    uint constant public DEFAULT_PAYLOAD_SIZE_LIMIT = 10000;

    ILayerZeroEndpoint public immutable lzEndpoint;
    mapping(uint16 => bytes) public trustedRemoteLookup;
    mapping(uint16 => mapping(uint16 => uint)) public minDstGasLookup;
    mapping(uint16 => uint) public payloadSizeLimitLookup;
    address public precrime;

    event SetPrecrime(address precrime);
    event SetTrustedRemote(uint16 _remoteChainId, bytes _path);
    event SetTrustedRemoteAddress(uint16 _remoteChainId, bytes _remoteAddress);
    event SetMinDstGas(uint16 _dstChainId, uint16 _type, uint _minDstGas);

    constructor(address _endpoint) {
        lzEndpoint = ILayerZeroEndpoint(_endpoint);
    }

    function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) public virtual override {
        // lzReceive must be called by the endpoint for security
        require(_msgSender() == address(lzEndpoint), "LzApp: invalid endpoint caller");

        bytes memory trustedRemote = trustedRemoteLookup[_srcChainId];
        // if will still block the message pathway from (srcChainId, srcAddress). should not receive message from untrusted remote.
        require(_srcAddress.length == trustedRemote.length && trustedRemote.length > 0 && keccak256(_srcAddress) == keccak256(trustedRemote), "LzApp: invalid source sending contract");

        _blockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);
    }

    // abstract function - the default behaviour of LayerZero is blocking. See: NonblockingLzApp if you dont need to enforce ordered messaging
    function _blockingLzReceive(uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload) internal virtual;

    function _lzSend(uint16 _dstChainId, bytes memory _payload, address payable _refundAddress, address _zroPaymentAddress, bytes memory _adapterParams, uint _nativeFee) internal virtual {
        bytes memory trustedRemote = trustedRemoteLookup[_dstChainId];
        require(trustedRemote.length != 0, "LzApp: destination chain is not a trusted source");
        _checkPayloadSize(_dstChainId, _payload.length);
        lzEndpoint.send{value: _nativeFee}(_dstChainId, trustedRemote, _payload, _refundAddress, _zroPaymentAddress, _adapterParams);
    }

    function _checkGasLimit(uint16 _dstChainId, uint16 _type, bytes memory _adapterParams, uint _extraGas) internal view virtual {
        uint providedGasLimit = _getGasLimit(_adapterParams);
        uint minGasLimit = minDstGasLookup[_dstChainId][_type] + _extraGas;
        require(minGasLimit > 0, "LzApp: minGasLimit not set");
        require(providedGasLimit >= minGasLimit, "LzApp: gas limit is too low");
    }

    function _getGasLimit(bytes memory _adapterParams) internal pure virtual returns (uint gasLimit) {
        require(_adapterParams.length >= 34, "LzApp: invalid adapterParams");
        assembly {
            gasLimit := mload(add(_adapterParams, 34))
        }
    }

    function _checkPayloadSize(uint16 _dstChainId, uint _payloadSize) internal view virtual {
        uint payloadSizeLimit = payloadSizeLimitLookup[_dstChainId];
        if (payloadSizeLimit == 0) { // use default if not set
            payloadSizeLimit = DEFAULT_PAYLOAD_SIZE_LIMIT;
        }
        require(_payloadSize <= payloadSizeLimit, "LzApp: payload size is too large");
    }

    //---------------------------UserApplication config----------------------------------------
    function getConfig(uint16 _version, uint16 _chainId, address, uint _configType) external view returns (bytes memory) {
        return lzEndpoint.getConfig(_version, _chainId, address(this), _configType);
    }

    // generic config for LayerZero user Application
    function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external override onlyOwner {
        lzEndpoint.setConfig(_version, _chainId, _configType, _config);
    }

    function setSendVersion(uint16 _version) external override onlyOwner {
        lzEndpoint.setSendVersion(_version);
    }

    function setReceiveVersion(uint16 _version) external override onlyOwner {
        lzEndpoint.setReceiveVersion(_version);
    }

    function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external override onlyOwner {
        lzEndpoint.forceResumeReceive(_srcChainId, _srcAddress);
    }

    // _path = abi.encodePacked(remoteAddress, localAddress)
    // this function set the trusted path for the cross-chain communication
    function setTrustedRemote(uint16 _remoteChainId, bytes calldata _path) external onlyOwner {
        trustedRemoteLookup[_remoteChainId] = _path;
        emit SetTrustedRemote(_remoteChainId, _path);
    }

    function setTrustedRemoteAddress(uint16 _remoteChainId, bytes calldata _remoteAddress) external onlyOwner {
        trustedRemoteLookup[_remoteChainId] = abi.encodePacked(_remoteAddress, address(this));
        emit SetTrustedRemoteAddress(_remoteChainId, _remoteAddress);
    }

    function getTrustedRemoteAddress(uint16 _remoteChainId) external view returns (bytes memory) {
        bytes memory path = trustedRemoteLookup[_remoteChainId];
        require(path.length != 0, "LzApp: no trusted path record");
        return path.slice(0, path.length - 20); // the last 20 bytes should be address(this)
    }

    function setPrecrime(address _precrime) external onlyOwner {
        precrime = _precrime;
        emit SetPrecrime(_precrime);
    }

    function setMinDstGas(uint16 _dstChainId, uint16 _packetType, uint _minGas) external onlyOwner {
        require(_minGas > 0, "LzApp: invalid minGas");
        minDstGasLookup[_dstChainId][_packetType] = _minGas;
        emit SetMinDstGas(_dstChainId, _packetType, _minGas);
    }

    // if the size is 0, it means default size limit
    function setPayloadSizeLimit(uint16 _dstChainId, uint _size) external onlyOwner {
        payloadSizeLimitLookup[_dstChainId] = _size;
    }

    //--------------------------- VIEW FUNCTION ----------------------------------------
    function isTrustedRemote(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool) {
        bytes memory trustedSource = trustedRemoteLookup[_srcChainId];
        return keccak256(trustedSource) == keccak256(_srcAddress);
    }
}

File 27 of 29 : ILayerZeroUserApplicationConfig.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.5.0;

interface ILayerZeroUserApplicationConfig {
    // @notice set the configuration of the LayerZero messaging library of the specified version
    // @param _version - messaging library version
    // @param _chainId - the chainId for the pending config change
    // @param _configType - type of configuration. every messaging library has its own convention.
    // @param _config - configuration in the bytes. can encode arbitrary content.
    function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external;

    // @notice set the send() LayerZero messaging library version to _version
    // @param _version - new messaging library version
    function setSendVersion(uint16 _version) external;

    // @notice set the lzReceive() LayerZero messaging library version to _version
    // @param _version - new messaging library version
    function setReceiveVersion(uint16 _version) external;

    // @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload
    // @param _srcChainId - the chainId of the source chain
    // @param _srcAddress - the contract address of the source contract at the source chain
    function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;
}

File 28 of 29 : ILayerZeroReceiver.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.5.0;

interface ILayerZeroReceiver {
    // @notice LayerZero endpoint will invoke this function to deliver the message on the destination
    // @param _srcChainId - the source endpoint identifier
    // @param _srcAddress - the source sending contract address from the source chain
    // @param _nonce - the ordered message nonce
    // @param _payload - the signed payload is the UA bytes has encoded to be sent
    function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) external;
}

File 29 of 29 : ILayerZeroEndpoint.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.5.0;

import "./ILayerZeroUserApplicationConfig.sol";

interface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig {
    // @notice send a LayerZero message to the specified address at a LayerZero endpoint.
    // @param _dstChainId - the destination chain identifier
    // @param _destination - the address on destination chain (in bytes). address length/format may vary by chains
    // @param _payload - a custom bytes payload to send to the destination contract
    // @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address
    // @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction
    // @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination
    function send(uint16 _dstChainId, bytes calldata _destination, bytes calldata _payload, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable;

    // @notice used by the messaging library to publish verified payload
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source contract (as bytes) at the source chain
    // @param _dstAddress - the address on destination chain
    // @param _nonce - the unbound message ordering nonce
    // @param _gasLimit - the gas limit for external contract execution
    // @param _payload - verified payload to send to the destination contract
    function receivePayload(uint16 _srcChainId, bytes calldata _srcAddress, address _dstAddress, uint64 _nonce, uint _gasLimit, bytes calldata _payload) external;

    // @notice get the inboundNonce of a lzApp from a source chain which could be EVM or non-EVM chain
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source chain contract address
    function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64);

    // @notice get the outboundNonce from this source chain which, consequently, is always an EVM
    // @param _srcAddress - the source chain contract address
    function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64);

    // @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery
    // @param _dstChainId - the destination chain identifier
    // @param _userApplication - the user app address on this EVM chain
    // @param _payload - the custom message to send over LayerZero
    // @param _payInZRO - if false, user app pays the protocol fee in native token
    // @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain
    function estimateFees(uint16 _dstChainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParam) external view returns (uint nativeFee, uint zroFee);

    // @notice get this Endpoint's immutable source identifier
    function getChainId() external view returns (uint16);

    // @notice the interface to retry failed message on this Endpoint destination
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source chain contract address
    // @param _payload - the payload to be retried
    function retryPayload(uint16 _srcChainId, bytes calldata _srcAddress, bytes calldata _payload) external;

    // @notice query if any STORED payload (message blocking) at the endpoint.
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source chain contract address
    function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool);

    // @notice query if the _libraryAddress is valid for sending msgs.
    // @param _userApplication - the user app address on this EVM chain
    function getSendLibraryAddress(address _userApplication) external view returns (address);

    // @notice query if the _libraryAddress is valid for receiving msgs.
    // @param _userApplication - the user app address on this EVM chain
    function getReceiveLibraryAddress(address _userApplication) external view returns (address);

    // @notice query if the non-reentrancy guard for send() is on
    // @return true if the guard is on. false otherwise
    function isSendingPayload() external view returns (bool);

    // @notice query if the non-reentrancy guard for receive() is on
    // @return true if the guard is on. false otherwise
    function isReceivingPayload() external view returns (bool);

    // @notice get the configuration of the LayerZero messaging library of the specified version
    // @param _version - messaging library version
    // @param _chainId - the chainId for the pending config change
    // @param _userApplication - the contract address of the user application
    // @param _configType - type of configuration. every messaging library has its own convention.
    function getConfig(uint16 _version, uint16 _chainId, address _userApplication, uint _configType) external view returns (bytes memory);

    // @notice get the send() LayerZero messaging library version
    // @param _userApplication - the contract address of the user application
    function getSendVersion(address _userApplication) external view returns (uint16);

    // @notice get the lzReceive() LayerZero messaging library version
    // @param _userApplication - the contract address of the user application
    function getReceiveVersion(address _userApplication) external view returns (uint16);
}

Settings
{
  "remappings": [],
  "optimizer": {
    "enabled": true,
    "runs": 10
  },
  "evmVersion": "shanghai",
  "libraries": {},
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_minter","type":"address"},{"internalType":"address","name":"_layerZeroEndpoint","type":"address"},{"internalType":"uint256","name":"_cap","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"dstChainId","type":"uint16"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"bytes","name":"toAddress","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"FeedToChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"_srcAddress","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"_nonce","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"_payload","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"_reason","type":"bytes"}],"name":"MessageFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"ReceiveFromChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"_srcAddress","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"_nonce","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"_payloadHash","type":"bytes32"}],"name":"RetryMessageSuccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":false,"internalType":"bytes","name":"_toAddress","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"SendToChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"dstChainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"toAddress","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"cap","type":"uint256"}],"name":"SetCapFor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"dstChainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"toAddress","type":"bytes"},{"indexed":false,"internalType":"bool","name":"flag","type":"bool"}],"name":"SetEnableFor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"_type","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"_minDstGas","type":"uint256"}],"name":"SetMinDstGas","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"precrime","type":"address"}],"name":"SetPrecrime","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"_remoteChainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"_path","type":"bytes"}],"name":"SetTrustedRemote","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"_remoteChainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"_remoteAddress","type":"bytes"}],"name":"SetTrustedRemoteAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"_useCustomAdapterParams","type":"bool"}],"name":"SetUseCustomAdapterParams","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DAY_INTERVAL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_PAYLOAD_SIZE_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NO_EXTRA_GAS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PT_FEED","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PT_SEND","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PT_SET_CAP","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PT_SET_ENABLE","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"circulatingSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"bytes","name":"_toAddress","type":"bytes"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_useZro","type":"bool"},{"internalType":"bytes","name":"_adapterParams","type":"bytes"}],"name":"estimateSendFee","outputs":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"zroFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"uint64","name":"","type":"uint64"}],"name":"failedMessages","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"}],"name":"forceResumeReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_version","type":"uint16"},{"internalType":"uint16","name":"_chainId","type":"uint16"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"_configType","type":"uint256"}],"name":"getConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getQuota","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_remoteChainId","type":"uint16"}],"name":"getTrustedRemoteAddress","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"}],"name":"isTrustedRemote","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lzEndpoint","outputs":[{"internalType":"contract ILayerZeroEndpoint","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"},{"internalType":"uint64","name":"_nonce","type":"uint64"},{"internalType":"bytes","name":"_payload","type":"bytes"}],"name":"lzReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"uint16","name":"","type":"uint16"}],"name":"minDstGasLookup","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"},{"internalType":"uint64","name":"_nonce","type":"uint64"},{"internalType":"bytes","name":"_payload","type":"bytes"}],"name":"nonblockingLzReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"payloadSizeLimitLookup","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"precrime","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"quota","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"},{"internalType":"uint64","name":"_nonce","type":"uint64"},{"internalType":"bytes","name":"_payload","type":"bytes"}],"name":"retryMessage","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"bytes","name":"_toAddress","type":"bytes"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address payable","name":"_refundAddress","type":"address"},{"internalType":"address","name":"_zroPaymentAddress","type":"address"},{"internalType":"bytes","name":"_adapterParams","type":"bytes"}],"name":"sendFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"uint256","name":"_cap","type":"uint256"},{"internalType":"bytes","name":"_toAddress","type":"bytes"}],"name":"setCapFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_version","type":"uint16"},{"internalType":"uint16","name":"_chainId","type":"uint16"},{"internalType":"uint256","name":"_configType","type":"uint256"},{"internalType":"bytes","name":"_config","type":"bytes"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"bool","name":"_flag","type":"bool"},{"internalType":"bytes","name":"_toAddress","type":"bytes"}],"name":"setEnableFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"uint16","name":"_packetType","type":"uint16"},{"internalType":"uint256","name":"_minGas","type":"uint256"}],"name":"setMinDstGas","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"uint256","name":"_size","type":"uint256"}],"name":"setPayloadSizeLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_precrime","type":"address"}],"name":"setPrecrime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_version","type":"uint16"}],"name":"setReceiveVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_version","type":"uint16"}],"name":"setSendVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_remoteChainId","type":"uint16"},{"internalType":"bytes","name":"_path","type":"bytes"}],"name":"setTrustedRemote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_remoteChainId","type":"uint16"},{"internalType":"bytes","name":"_remoteAddress","type":"bytes"}],"name":"setTrustedRemoteAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_useCustomAdapterParams","type":"bool"}],"name":"setUseCustomAdapterParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenPrice","outputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"nonpayable","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":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"trustedRemoteLookup","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"bytes","name":"_toAddress","type":"bytes"}],"name":"updatePrice","outputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"useCustomAdapterParams","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

60a0604052600e805460ff191660011790553480156200001d575f80fd5b50604051620040113803806200401183398101604081905262000040916200017d565b6040518060400160405280601081526020016f29ba30b5b2a9ba37b7329022ba3432b960811b8152506040518060400160405280600581526020016453544f4e4560d81b815250838282828282828080620000aa620000a46200010e60201b60201c565b62000112565b6001600160a01b031660805250600a9050620000c783826200025b565b50600b620000d682826200025b565b5050600c80546001600160a01b0319166001600160a01b039b909b169a909a17909955505050600d9390935550620003239350505050565b3390565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b038116811462000178575f80fd5b919050565b5f805f6060848603121562000190575f80fd5b6200019b8462000161565b9250620001ab6020850162000161565b9150604084015190509250925092565b634e487b7160e01b5f52604160045260245ffd5b600181811c90821680620001e457607f821691505b6020821081036200020357634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111562000256575f81815260208120601f850160051c81016020861015620002315750805b601f850160051c820191505b8181101562000252578281556001016200023d565b5050505b505050565b81516001600160401b03811115620002775762000277620001bb565b6200028f81620002888454620001cf565b8462000209565b602080601f831160018114620002c5575f8415620002ad5750858301515b5f19600386901b1c1916600185901b17855562000252565b5f85815260208120601f198616915b82811015620002f557888601518255948401946001909101908401620002d4565b50858210156200031357878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b608051613c9d620003745f395f8181610812015281816109bd01528181610cd301528181610d8c01528181610e79015281816110480152818161188601528181611df101526125580152613c9d5ff3fe6080604052600436106102a5575f3560e01c80621d3567146102a957806301ffc9a7146102ca57806306fdde03146102fe578063075461721461031f57806307e0db171461034b578063095ea7b31461036a5780630df374831461038957806310ddb137146103a857806318160ddd146103c75780631df8ba77146103e557806323b872dd146103f95780632a205e3d14610418578063313ce5671461044c578063355274ea14610467578063395093511461047c5780633d8b38f61461049b5780633f1f4fa4146104ba57806340c10f19146104e557806342d65a8d146105045780634477051514610523578063471744d1146105365780634c42899a1461055d57806351905636146105705780635b8c41e61461058357806366ad5c8a146105d057806368322ff5146105ef5780636abe0abf1461060257806370a0823114610618578063715018a6146106375780637533d7881461064b5780637ff9b5961461066a5780638cfd8f5c1461067e5780638da5cb5b146106b457806390e9097a146106c85780639358928b146106db578063950c8a74146106ef57806395d89b411461070e5780639dc29fac146107225780639f38369a14610741578063a162b0a214610760578063a3907d711461078b578063a457c2d7146107a4578063a6c3d165146107c3578063a9059cbb146107e2578063b353aaa714610801578063baf3292d14610834578063c446183414610853578063ca5ea40614610868578063cbed8b9c1461087c578063d1b4a2d81461089b578063d1deba1f146108ae578063dd62ed3e146108c1578063df2a5b3b146108e0578063e3ec18ae146108ff578063eab45d9c14610913578063eb8d72b714610932578063ed629c5c14610951578063f2fde38b1461096a578063f5ecbdbc14610989578063fc0c546a146109a8575b5f80fd5b3480156102b4575f80fd5b506102c86102c3366004612dc5565b6109ba565b005b3480156102d5575f80fd5b506102e96102e4366004612e54565b610be5565b60405190151581526020015b60405180910390f35b348015610309575f80fd5b50610312610c22565b6040516102f59190612ec8565b34801561032a575f80fd5b50600c5461033e906001600160a01b031681565b6040516102f59190612eda565b348015610356575f80fd5b506102c8610365366004612eee565b610cb2565b348015610375575f80fd5b506102e9610384366004612f1d565b610d36565b348015610394575f80fd5b506102c86103a3366004612f47565b610d4d565b3480156103b3575f80fd5b506102c86103c2366004612eee565b610d6b565b3480156103d2575f80fd5b506009545b6040519081526020016102f5565b3480156103f0575f80fd5b506103d7610dc3565b348015610404575f80fd5b506102e9610413366004612f63565b610e15565b348015610423575f80fd5b50610437610432366004612fb0565b610e38565b604080519283526020830191909152016102f5565b348015610457575f80fd5b50604051601281526020016102f5565b348015610472575f80fd5b506103d7600d5481565b348015610487575f80fd5b506102e9610496366004612f1d565b610f07565b3480156104a6575f80fd5b506102e96104b5366004613048565b610f28565b3480156104c5575f80fd5b506103d76104d4366004612eee565b60036020525f908152604090205481565b3480156104f0575f80fd5b506102c86104ff366004612f1d565b610ff1565b34801561050f575f80fd5b506102c861051e366004613048565b611029565b34801561052e575f80fd5b506103d75f81565b348015610541575f80fd5b5061054a600181565b60405161ffff90911681526020016102f5565b348015610568575f80fd5b5061054a5f81565b6102c861057e366004613098565b6110aa565b34801561058e575f80fd5b506103d761059d366004613215565b600560209081525f9384526040808520845180860184018051928152908401958401959095209452929052825290205481565b3480156105db575f80fd5b506102c86105ea366004612dc5565b61119d565b6102c86105fd366004613270565b611277565b34801561060d575f80fd5b506103d76201518081565b348015610623575f80fd5b506103d76106323660046132cb565b611368565b348015610642575f80fd5b506102c8611382565b348015610656575f80fd5b50610312610665366004612eee565b611395565b348015610675575f80fd5b506103d761142c565b348015610689575f80fd5b506103d76106983660046132e6565b600260209081525f928352604080842090915290825290205481565b3480156106bf575f80fd5b5061033e61149d565b6103d76106d636600461331d565b6114ab565b3480156106e6575f80fd5b506103d7611593565b3480156106fa575f80fd5b5060045461033e906001600160a01b031681565b348015610719575f80fd5b506103126115a6565b34801561072d575f80fd5b506102c861073c366004612f1d565b6115b5565b34801561074c575f80fd5b5061031261075b366004612eee565b6115e9565b34801561076b575f80fd5b506103d761077a366004613369565b600f6020525f908152604090205481565b348015610796575f80fd5b50600e546102e99060ff1681565b3480156107af575f80fd5b506102e96107be366004612f1d565b6116fa565b3480156107ce575f80fd5b506102c86107dd366004613048565b611774565b3480156107ed575f80fd5b506102e96107fc366004612f1d565b6117fc565b34801561080c575f80fd5b5061033e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561083f575f80fd5b506102c861084e3660046132cb565b611809565b34801561085e575f80fd5b506103d761271081565b348015610873575f80fd5b5061054a600281565b348015610887575f80fd5b506102c8610896366004613380565b611867565b6102c86108a93660046133ed565b6118f7565b6102c86108bc366004612dc5565b6119bb565b3480156108cc575f80fd5b506103d76108db36600461342b565b611bcb565b3480156108eb575f80fd5b506102c86108fa366004613457565b611bf5565b34801561090a575f80fd5b5061054a600381565b34801561091e575f80fd5b506102c861092d366004613484565b611ca5565b34801561093d575f80fd5b506102c861094c366004613048565b611cee565b34801561095c575f80fd5b506006546102e99060ff1681565b348015610975575f80fd5b506102c86109843660046132cb565b611d47565b348015610994575f80fd5b506103126109a336600461349d565b611dc0565b3480156109b3575f80fd5b503061033e565b337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614610a375760405162461bcd60e51b815260206004820152601e60248201527f4c7a4170703a20696e76616c696420656e64706f696e742063616c6c6572000060448201526064015b60405180910390fd5b61ffff86165f9081526001602052604081208054610a54906134eb565b80601f0160208091040260200160405190810160405280929190818152602001828054610a80906134eb565b8015610acb5780601f10610aa257610100808354040283529160200191610acb565b820191905f5260205f20905b815481529060010190602001808311610aae57829003601f168201915b50505050509050805186869050148015610ae557505f8151115b8015610b0d575080516020820120604051610b039088908890613523565b6040518091039020145b610b685760405162461bcd60e51b815260206004820152602660248201527f4c7a4170703a20696e76616c696420736f757263652073656e64696e6720636f6044820152651b9d1c9858dd60d21b6064820152608401610a2e565b610bdc8787878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050604080516020601f8a018190048102820181019092528881528a9350915088908890819084018382808284375f92019190915250611e6d92505050565b50505050505050565b5f6001600160e01b031982161580610c0d57506001600160e01b031982166336372b0760e01b145b80610c1c5750610c1c82611ee5565b92915050565b6060600a8054610c31906134eb565b80601f0160208091040260200160405190810160405280929190818152602001828054610c5d906134eb565b8015610ca85780601f10610c7f57610100808354040283529160200191610ca8565b820191905f5260205f20905b815481529060010190602001808311610c8b57829003601f168201915b5050505050905090565b610cba611f19565b6040516307e0db1760e01b815261ffff821660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906307e0db17906024015b5f604051808303815f87803b158015610d1d575f80fd5b505af1158015610d2f573d5f803e3d5ffd5b5050505050565b5f33610d43818585611f78565b5060019392505050565b610d55611f19565b61ffff9091165f90815260036020526040902055565b610d73611f19565b6040516310ddb13760e01b815261ffff821660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906310ddb13790602401610d06565b5f80600f81610dd56201518042613546565b81526020019081526020015f2054905080600d54118015610df85750600e5460ff165b15610e115780600d54610e0b9190613565565b91505090565b5090565b5f33610e2285828561209b565b610e2d858585612113565b506001949350505050565b5f805f80898989604051602001610e5294939291906135a0565b60408051601f198184030181529082905263040a7bb160e41b825291506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906340a7bb1090610eb8908d90309086908c908c908c906004016135ce565b6040805180830381865afa158015610ed2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ef69190613623565b925092505097509795505050505050565b5f33610d43818585610f198383611bcb565b610f239190613645565b611f78565b61ffff83165f9081526001602052604081208054829190610f48906134eb565b80601f0160208091040260200160405190810160405280929190818152602001828054610f74906134eb565b8015610fbf5780601f10610f9657610100808354040283529160200191610fbf565b820191905f5260205f20905b815481529060010190602001808311610fa257829003601f168201915b505050505090508383604051610fd6929190613523565b60405180910390208180519060200120149150509392505050565b600c546001600160a01b0316331461101b5760405162461bcd60e51b8152600401610a2e90613658565b61102582826122a9565b5050565b611031611f19565b6040516342d65a8d60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906342d65a8d9061108190869086908690600401613674565b5f604051808303815f87803b158015611098575f80fd5b505af1158015610bdc573d5f803e3d5ffd5b600e5460ff166110cc5760405162461bcd60e51b8152600401610a2e90613691565b4661ffff891681036110f05760405162461bcd60e51b8152600401610a2e906136b2565b5f6110fe6201518042613546565b600d545f828152600f60205260409020549192509061111d9089613645565b11156111585760405162461bcd60e51b815260206004820152600a6024820152690457863656564206361760b41b6044820152606401610a2e565b5f818152600f6020526040902054611171908890613645565b5f828152600f60205260409020556111908b8b8b8b8b8b8b8b8b612355565b5050505050505050505050565b3330146111fb5760405162461bcd60e51b815260206004820152602660248201527f4e6f6e626c6f636b696e674c7a4170703a2063616c6c6572206d7573742062656044820152650204c7a4170760d41b6064820152608401610a2e565b61126f8686868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050604080516020601f8901819004810282018101909252878152899350915087908790819084018382808284375f920191909152506123cd92505050565b505050505050565b61127f611f19565b4661ffff84168190036112f157600e805460ff191684151517905560405161ffff8516905f80516020613c08833981519152906112c09030906020016136d6565b60408051601f1981840301815290829052600e546112e39260ff909116906136ee565b60405180910390a250505050565b5f6002838560405160200161130893929190613711565b60405160208183030381529060405290506113358582335f60405180602001604052805f81525034612433565b8461ffff165f80516020613c0883398151915284866040516113589291906136ee565b60405180910390a250505b505050565b6001600160a01b03165f9081526007602052604090205490565b61138a611f19565b6113935f6125d0565b565b60016020525f9081526040902080546113ad906134eb565b80601f01602080910402602001604051908101604052809291908181526020018280546113d9906134eb565b80156114245780601f106113fb57610100808354040283529160200191611424565b820191905f5260205f20905b81548152906001019060200180831161140757829003601f168201915b505050505081565b600c54604080516325ca7a8760e11b815290515f926001600160a01b031691634b94f50e916004808301926020929190829003018187875af1158015611474573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611498919061373f565b905090565b5f546001600160a01b031690565b600e545f9060ff166114cf5760405162461bcd60e51b8152600401610a2e90613691565b4661ffff841681036114f35760405162461bcd60e51b8152600401610a2e906136b2565b6114fb61142c565b91505f60018484426040516020016115169493929190613756565b60405160208183030381529060405290506115438582335f60405180602001604052805f81525034612433565b336001600160a01b03168561ffff167fa9abd88cb9207ea146a8c570a7c926ee640d4ef1eed13893a603f574d762f8818686604051611583929190613785565b60405180910390a3505092915050565b5f61159d30611368565b60095403905090565b6060600b8054610c31906134eb565b600c546001600160a01b031633146115df5760405162461bcd60e51b8152600401610a2e90613658565b611025828261261f565b61ffff81165f9081526001602052604081208054606092919061160b906134eb565b80601f0160208091040260200160405190810160405280929190818152602001828054611637906134eb565b80156116825780601f1061165957610100808354040283529160200191611682565b820191905f5260205f20905b81548152906001019060200180831161166557829003601f168201915b5050505050905080515f036116d95760405162461bcd60e51b815260206004820152601d60248201527f4c7a4170703a206e6f20747275737465642070617468207265636f72640000006044820152606401610a2e565b6116f35f601483516116eb9190613565565b83919061273e565b9392505050565b5f33816117078286611bcb565b9050838110156117675760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610a2e565b610e2d8286868403611f78565b61177c611f19565b818130604051602001611791939291906137a6565b60408051601f1981840301815291815261ffff85165f908152600160205220906117bb9082613820565b507f8c0400cfe2d1199b1a725c78960bcc2a344d869b80590d0f2bd005db15a572ce8383836040516117ef93929190613674565b60405180910390a1505050565b5f33610d43818585612113565b611811611f19565b600480546001600160a01b0319166001600160a01b0383161790556040517f5db758e995a17ec1ad84bdef7e8c3293a0bd6179bcce400dff5d4c3d87db726b9061185c908390612eda565b60405180910390a150565b61186f611f19565b6040516332fb62e760e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063cbed8b9c906118c390889088908890889088906004016138d6565b5f604051808303815f87803b1580156118da575f80fd5b505af11580156118ec573d5f803e3d5ffd5b505050505050505050565b6118ff611f19565b4661ffff84168190036119545782600d819055508361ffff165f80516020613c288339815191523060405160200161193791906136d6565b60408051601f1981840301815290829052600d546112e392613785565b5f6003838560405160200161196b9392919061390e565b60405160208183030381529060405290506119988582335f60405180602001604052805f81525034612433565b8461ffff165f80516020613c288339815191528486604051611358929190613785565b61ffff86165f9081526005602052604080822090516119dd9088908890613523565b90815260408051602092819003830190206001600160401b0387165f9081529252902054905080611a5c5760405162461bcd60e51b815260206004820152602360248201527f4e6f6e626c6f636b696e674c7a4170703a206e6f2073746f726564206d65737360448201526261676560e81b6064820152608401610a2e565b808383604051611a6d929190613523565b604051809103902014611acc5760405162461bcd60e51b815260206004820152602160248201527f4e6f6e626c6f636b696e674c7a4170703a20696e76616c6964207061796c6f616044820152601960fa1b6064820152608401610a2e565b61ffff87165f908152600560205260408082209051611aee9089908990613523565b90815260408051602092819003830181206001600160401b0389165f90815290845282902093909355601f88018290048202830182019052868252611b8391899189908990819084018382808284375f9201919091525050604080516020601f8a018190048102820181019092528881528a9350915088908890819084018382808284375f920191909152506123cd92505050565b7fc264d91f3adc5588250e1551f547752ca0cfa8f6b530d243b9f9f4cab10ea8e58787878785604051611bba95949392919061393a565b60405180910390a150505050505050565b6001600160a01b039182165f90815260086020908152604080832093909416825291909152205490565b611bfd611f19565b5f8111611c445760405162461bcd60e51b81526020600482015260156024820152744c7a4170703a20696e76616c6964206d696e47617360581b6044820152606401610a2e565b61ffff8381165f8181526002602090815260408083209487168084529482529182902085905581519283528201929092529081018290527f9d5c7c0b934da8fefa9c7760c98383778a12dfbfc0c3b3106518f43fb9508ac0906060016117ef565b611cad611f19565b6006805460ff19168215159081179091556040519081527f1584ad594a70cbe1e6515592e1272a987d922b097ead875069cebe8b40c004a49060200161185c565b611cf6611f19565b61ffff83165f908152600160205260409020611d13828483613974565b507ffa41487ad5d6728f0b19276fa1eddc16558578f5109fc39d2dc33c3230470dab8383836040516117ef93929190613674565b611d4f611f19565b6001600160a01b038116611db45760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610a2e565b611dbd816125d0565b50565b604051633d7b2f6f60e21b815261ffff808616600483015284166024820152306044820152606481018290526060907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063f5ecbdbc906084015f60405180830381865afa158015611e3d573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611e649190810190613a73565b95945050505050565b5f80611ecf5a60966366ad5c8a60e01b89898989604051602401611e949493929190613aa4565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091523092919061284a565b915091508161126f5761126f86868686856128ce565b5f6001600160e01b03198216630a72677560e11b1480610c1c57506301ffc9a760e01b6001600160e01b0319831614610c1c565b33611f2261149d565b6001600160a01b0316146113935760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a2e565b6001600160a01b038316611fda5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610a2e565b6001600160a01b03821661203b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610a2e565b6001600160a01b038381165f8181526008602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b5f6120a68484611bcb565b90505f19811461210d57818110156121005760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610a2e565b61210d8484848403611f78565b50505050565b6001600160a01b0383166121775760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610a2e565b6001600160a01b0382166121d95760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610a2e565b6001600160a01b0383165f90815260076020526040902054818110156122505760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610a2e565b6001600160a01b038085165f8181526007602052604080822086860390559286168082529083902080548601905591515f80516020613c488339815191529061229c9086815260200190565b60405180910390a361210d565b6001600160a01b0382166122ff5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610a2e565b8060095f8282546123109190613645565b90915550506001600160a01b0382165f818152600760209081526040808320805486019055518481525f80516020613c48833981519152910160405180910390a35050565b6118ec898989898080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050604080516020601f8a018190048102820181019092528881528c93508b92508a918a908a90819084018382808284375f9201919091525061296892505050565b602081015161ffff81166123ec576123e785858585612a0b565b610d2f565b60405162461bcd60e51b815260206004820152601c60248201527b4f4654436f72653a20756e6b6e6f776e207061636b6574207479706560201b6044820152606401610a2e565b61ffff86165f9081526001602052604081208054612450906134eb565b80601f016020809104026020016040519081016040528092919081815260200182805461247c906134eb565b80156124c75780601f1061249e576101008083540402835291602001916124c7565b820191905f5260205f20905b8154815290600101906020018083116124aa57829003601f168201915b5050505050905080515f036125375760405162461bcd60e51b815260206004820152603060248201527f4c7a4170703a2064657374696e6174696f6e20636861696e206973206e6f742060448201526f61207472757374656420736f7572636560801b6064820152608401610a2e565b612542878751612a93565b60405162c5803160e81b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c5803100908490612599908b9086908c908c908c908c90600401613ae1565b5f604051808303818588803b1580156125b0575f80fd5b505af11580156125c2573d5f803e3d5ffd5b505050505050505050505050565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03821661267f5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610a2e565b6001600160a01b0382165f90815260076020526040902054818110156126f25760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610a2e565b6001600160a01b0383165f8181526007602090815260408083208686039055600980548790039055518581529192915f80516020613c48833981519152910160405180910390a3505050565b60608161274c81601f613645565b101561278b5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610a2e565b6127958284613645565b845110156127d95760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401610a2e565b6060821580156127f75760405191505f825260208201604052612841565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015612830578051835260209283019201612818565b5050858452601f01601f1916604052505b50949350505050565b5f60605f805f8661ffff166001600160401b0381111561286c5761286c613159565b6040519080825280601f01601f191660200182016040528015612896576020820181803683370190505b5090505f808751602089015f8d8df191503d9250868311156128b6578692505b828152825f602083013e909890975095505050505050565b818051906020012060055f8761ffff1661ffff1681526020019081526020015f20856040516128fd9190613b3a565b9081526040805191829003602090810183206001600160401b0388165f908152915220919091557fe183f33de2837795525b4792ca4cd60535bd77c53b7e7030060bfcf5734d6b0c906129599087908790879087908790613b55565b60405180910390a15050505050565b612974865f835f612b03565b5f61298188888888612b7d565b90505f8087836040516020016129999392919061390e565b60405160208183030381529060405290506129b8888287878734612433565b886001600160a01b03168861ffff167f39a4c66499bcf4b56d79f0dde8ed7a9d4925a0df55825206b2b8531e202be0d089856040516129f8929190613785565b60405180910390a3505050505050505050565b5f8082806020019051810190612a219190613bb2565b90935091505f9050612a338382612baf565b9050612a40878284612c13565b9150806001600160a01b03168761ffff167fbf551ec93859b170f9b2141bd9298bf3f64322c6f7beb2543a0cb669834118bf84604051612a8291815260200190565b60405180910390a350505050505050565b61ffff82165f9081526003602052604081205490819003612ab357506127105b808211156113635760405162461bcd60e51b815260206004820181905260248201527f4c7a4170703a207061796c6f61642073697a6520697320746f6f206c617267656044820152606401610a2e565b60065460ff1615612b1f57612b1a84848484612c26565b61210d565b81511561210d5760405162461bcd60e51b815260206004820152602660248201527f4f4654436f72653a205f61646170746572506172616d73206d7573742062652060448201526532b6b83a3c9760d11b6064820152608401610a2e565b5f336001600160a01b0386168114612b9a57612b9a86828561209b565b612ba5863085612113565b5090949350505050565b5f612bbb826014613645565b83511015612c035760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b6044820152606401610a2e565b500160200151600160601b900490565b5f612c1f308484612113565b5092915050565b5f612c3083612cfd565b61ffff8087165f90815260026020908152604080832093891683529290529081205491925090612c61908490613645565b90505f8111612caf5760405162461bcd60e51b815260206004820152601a602482015279131e905c1c0e881b5a5b91d85cd31a5b5a5d081b9bdd081cd95d60321b6044820152606401610a2e565b8082101561126f5760405162461bcd60e51b815260206004820152601b60248201527a4c7a4170703a20676173206c696d697420697320746f6f206c6f7760281b6044820152606401610a2e565b5f602282511015612d4f5760405162461bcd60e51b815260206004820152601c60248201527b4c7a4170703a20696e76616c69642061646170746572506172616d7360201b6044820152606401610a2e565b506022015190565b61ffff81168114611dbd575f80fd5b5f8083601f840112612d76575f80fd5b5081356001600160401b03811115612d8c575f80fd5b602083019150836020828501011115612da3575f80fd5b9250929050565b80356001600160401b0381168114612dc0575f80fd5b919050565b5f805f805f8060808789031215612dda575f80fd5b8635612de581612d57565b955060208701356001600160401b0380821115612e00575f80fd5b612e0c8a838b01612d66565b9097509550859150612e2060408a01612daa565b94506060890135915080821115612e35575f80fd5b50612e4289828a01612d66565b979a9699509497509295939492505050565b5f60208284031215612e64575f80fd5b81356001600160e01b0319811681146116f3575f80fd5b5f5b83811015612e95578181015183820152602001612e7d565b50505f910152565b5f8151808452612eb4816020860160208601612e7b565b601f01601f19169290920160200192915050565b602081525f6116f36020830184612e9d565b6001600160a01b0391909116815260200190565b5f60208284031215612efe575f80fd5b81356116f381612d57565b6001600160a01b0381168114611dbd575f80fd5b5f8060408385031215612f2e575f80fd5b8235612f3981612f09565b946020939093013593505050565b5f8060408385031215612f58575f80fd5b8235612f3981612d57565b5f805f60608486031215612f75575f80fd5b8335612f8081612f09565b92506020840135612f9081612f09565b929592945050506040919091013590565b80358015158114612dc0575f80fd5b5f805f805f805f60a0888a031215612fc6575f80fd5b8735612fd181612d57565b965060208801356001600160401b0380821115612fec575f80fd5b612ff88b838c01612d66565b909850965060408a0135955086915061301360608b01612fa1565b945060808a0135915080821115613028575f80fd5b506130358a828b01612d66565b989b979a50959850939692959293505050565b5f805f6040848603121561305a575f80fd5b833561306581612d57565b925060208401356001600160401b0381111561307f575f80fd5b61308b86828701612d66565b9497909650939450505050565b5f805f805f805f805f60e08a8c0312156130b0575f80fd5b89356130bb81612f09565b985060208a01356130cb81612d57565b975060408a01356001600160401b03808211156130e6575f80fd5b6130f28d838e01612d66565b909950975060608c0135965060808c0135915061310e82612f09565b90945060a08b01359061312082612f09565b90935060c08b01359080821115613135575f80fd5b506131428c828d01612d66565b915080935050809150509295985092959850929598565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b038111828210171561319557613195613159565b604052919050565b5f6001600160401b038211156131b5576131b5613159565b50601f01601f191660200190565b5f82601f8301126131d2575f80fd5b81356131e56131e08261319d565b61316d565b8181528460208386010111156131f9575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f60608486031215613227575f80fd5b833561323281612d57565b925060208401356001600160401b0381111561324c575f80fd5b613258868287016131c3565b92505061326760408501612daa565b90509250925092565b5f805f60608486031215613282575f80fd5b833561328d81612d57565b925061329b60208501612fa1565b915060408401356001600160401b038111156132b5575f80fd5b6132c1868287016131c3565b9150509250925092565b5f602082840312156132db575f80fd5b81356116f381612f09565b5f80604083850312156132f7575f80fd5b823561330281612d57565b9150602083013561331281612d57565b809150509250929050565b5f806040838503121561332e575f80fd5b823561333981612d57565b915060208301356001600160401b03811115613353575f80fd5b61335f858286016131c3565b9150509250929050565b5f60208284031215613379575f80fd5b5035919050565b5f805f805f60808688031215613394575f80fd5b853561339f81612d57565b945060208601356133af81612d57565b93506040860135925060608601356001600160401b038111156133d0575f80fd5b6133dc88828901612d66565b969995985093965092949392505050565b5f805f606084860312156133ff575f80fd5b833561340a81612d57565b92506020840135915060408401356001600160401b038111156132b5575f80fd5b5f806040838503121561343c575f80fd5b823561344781612f09565b9150602083013561331281612f09565b5f805f60608486031215613469575f80fd5b833561347481612d57565b92506020840135612f9081612d57565b5f60208284031215613494575f80fd5b6116f382612fa1565b5f805f80608085870312156134b0575f80fd5b84356134bb81612d57565b935060208501356134cb81612d57565b925060408501356134db81612f09565b9396929550929360600135925050565b600181811c908216806134ff57607f821691505b60208210810361351d57634e487b7160e01b5f52602260045260245ffd5b50919050565b818382375f9101908152919050565b634e487b7160e01b5f52601160045260245ffd5b5f8261356057634e487b7160e01b5f52601260045260245ffd5b500490565b81810381811115610c1c57610c1c613532565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b61ffff85168152606060208201525f6135bd606083018587613578565b905082604083015295945050505050565b61ffff871681526001600160a01b038616602082015260a0604082018190525f906135fb90830187612e9d565b85151560608401528281036080840152613616818587613578565b9998505050505050505050565b5f8060408385031215613634575f80fd5b505080516020909101519092909150565b80820180821115610c1c57610c1c613532565b6020808252600290820152614e4d60f01b604082015260600190565b61ffff84168152604060208201525f611e64604083018486613578565b6020808252600790820152661a5b9d985b1a5960ca1b604082015260600190565b6020808252600a908201526939b0b6b29031b430b4b760b11b604082015260600190565b60609190911b6001600160601b031916815260140190565b604081525f6137006040830185612e9d565b905082151560208301529392505050565b61ffff84168152606060208201525f61372d6060830185612e9d565b90508215156040830152949350505050565b5f6020828403121561374f575f80fd5b5051919050565b61ffff85168152608060208201525f6137726080830186612e9d565b6040830194909452506060015292915050565b604081525f6137976040830185612e9d565b90508260208301529392505050565b8284823760609190911b6001600160601b0319169101908152601401919050565b601f821115611363575f81815260208120601f850160051c810160208610156137ed5750805b601f850160051c820191505b8181101561126f578281556001016137f9565b5f19600383901b1c191660019190911b1790565b81516001600160401b0381111561383957613839613159565b61384d8161384784546134eb565b846137c7565b602080601f83116001811461387b575f84156138695750858301515b613873858261380c565b86555061126f565b5f85815260208120601f198616915b828110156138a95788860151825594840194600190910190840161388a565b50858210156138c657878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f61ffff808816835280871660208401525084604083015260806060830152613903608083018486613578565b979650505050505050565b61ffff84168152606060208201525f61392a6060830185612e9d565b9050826040830152949350505050565b61ffff86168152608060208201525f613957608083018688613578565b6001600160401b0394909416604083015250606001529392505050565b6001600160401b0383111561398b5761398b613159565b61399f8361399983546134eb565b836137c7565b5f601f8411600181146139cb575f85156139b95750838201355b6139c3868261380c565b845550610d2f565b5f83815260209020601f19861690835b828110156139fb57868501358255602094850194600190920191016139db565b5086821015613a17575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b5f82601f830112613a38575f80fd5b8151613a466131e08261319d565b818152846020838601011115613a5a575f80fd5b613a6b826020830160208701612e7b565b949350505050565b5f60208284031215613a83575f80fd5b81516001600160401b03811115613a98575f80fd5b613a6b84828501613a29565b61ffff85168152608060208201525f613ac06080830186612e9d565b6001600160401b038516604084015282810360608401526139038185612e9d565b61ffff8716815260c060208201525f613afd60c0830188612e9d565b8281036040840152613b0f8188612e9d565b6001600160a01b0387811660608601528616608085015283810360a085015290506136168185612e9d565b5f8251613b4b818460208701612e7b565b9190910192915050565b61ffff8616815260a060208201525f613b7160a0830187612e9d565b6001600160401b03861660408401528281036060840152613b928186612e9d565b90508281036080840152613ba68185612e9d565b98975050505050505050565b5f805f60608486031215613bc4575f80fd5b8351613bcf81612d57565b60208501519093506001600160401b03811115613bea575f80fd5b613bf686828701613a29565b92505060408401519050925092509256fe8bf89adedf6e5cb38caf3b2cc7e255e668fec50ffeee80e627d7ee7ff42ea89ffba6058f70462ebfb18b3e74d307def7438209fc600413e1fc842c59b0ba5bf4ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212200925be473ed0a77aaeba73c62029065d5a6c096f58b568386f13c80bcd4271d964736f6c63430008150033000000000000000000000000ec306e46549a7e8f4fce823d3058f2d134133b1700000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd67500000000000000000000000000000000000000000000021e19e0c9bab2400000

Deployed Bytecode

0x6080604052600436106102a5575f3560e01c80621d3567146102a957806301ffc9a7146102ca57806306fdde03146102fe578063075461721461031f57806307e0db171461034b578063095ea7b31461036a5780630df374831461038957806310ddb137146103a857806318160ddd146103c75780631df8ba77146103e557806323b872dd146103f95780632a205e3d14610418578063313ce5671461044c578063355274ea14610467578063395093511461047c5780633d8b38f61461049b5780633f1f4fa4146104ba57806340c10f19146104e557806342d65a8d146105045780634477051514610523578063471744d1146105365780634c42899a1461055d57806351905636146105705780635b8c41e61461058357806366ad5c8a146105d057806368322ff5146105ef5780636abe0abf1461060257806370a0823114610618578063715018a6146106375780637533d7881461064b5780637ff9b5961461066a5780638cfd8f5c1461067e5780638da5cb5b146106b457806390e9097a146106c85780639358928b146106db578063950c8a74146106ef57806395d89b411461070e5780639dc29fac146107225780639f38369a14610741578063a162b0a214610760578063a3907d711461078b578063a457c2d7146107a4578063a6c3d165146107c3578063a9059cbb146107e2578063b353aaa714610801578063baf3292d14610834578063c446183414610853578063ca5ea40614610868578063cbed8b9c1461087c578063d1b4a2d81461089b578063d1deba1f146108ae578063dd62ed3e146108c1578063df2a5b3b146108e0578063e3ec18ae146108ff578063eab45d9c14610913578063eb8d72b714610932578063ed629c5c14610951578063f2fde38b1461096a578063f5ecbdbc14610989578063fc0c546a146109a8575b5f80fd5b3480156102b4575f80fd5b506102c86102c3366004612dc5565b6109ba565b005b3480156102d5575f80fd5b506102e96102e4366004612e54565b610be5565b60405190151581526020015b60405180910390f35b348015610309575f80fd5b50610312610c22565b6040516102f59190612ec8565b34801561032a575f80fd5b50600c5461033e906001600160a01b031681565b6040516102f59190612eda565b348015610356575f80fd5b506102c8610365366004612eee565b610cb2565b348015610375575f80fd5b506102e9610384366004612f1d565b610d36565b348015610394575f80fd5b506102c86103a3366004612f47565b610d4d565b3480156103b3575f80fd5b506102c86103c2366004612eee565b610d6b565b3480156103d2575f80fd5b506009545b6040519081526020016102f5565b3480156103f0575f80fd5b506103d7610dc3565b348015610404575f80fd5b506102e9610413366004612f63565b610e15565b348015610423575f80fd5b50610437610432366004612fb0565b610e38565b604080519283526020830191909152016102f5565b348015610457575f80fd5b50604051601281526020016102f5565b348015610472575f80fd5b506103d7600d5481565b348015610487575f80fd5b506102e9610496366004612f1d565b610f07565b3480156104a6575f80fd5b506102e96104b5366004613048565b610f28565b3480156104c5575f80fd5b506103d76104d4366004612eee565b60036020525f908152604090205481565b3480156104f0575f80fd5b506102c86104ff366004612f1d565b610ff1565b34801561050f575f80fd5b506102c861051e366004613048565b611029565b34801561052e575f80fd5b506103d75f81565b348015610541575f80fd5b5061054a600181565b60405161ffff90911681526020016102f5565b348015610568575f80fd5b5061054a5f81565b6102c861057e366004613098565b6110aa565b34801561058e575f80fd5b506103d761059d366004613215565b600560209081525f9384526040808520845180860184018051928152908401958401959095209452929052825290205481565b3480156105db575f80fd5b506102c86105ea366004612dc5565b61119d565b6102c86105fd366004613270565b611277565b34801561060d575f80fd5b506103d76201518081565b348015610623575f80fd5b506103d76106323660046132cb565b611368565b348015610642575f80fd5b506102c8611382565b348015610656575f80fd5b50610312610665366004612eee565b611395565b348015610675575f80fd5b506103d761142c565b348015610689575f80fd5b506103d76106983660046132e6565b600260209081525f928352604080842090915290825290205481565b3480156106bf575f80fd5b5061033e61149d565b6103d76106d636600461331d565b6114ab565b3480156106e6575f80fd5b506103d7611593565b3480156106fa575f80fd5b5060045461033e906001600160a01b031681565b348015610719575f80fd5b506103126115a6565b34801561072d575f80fd5b506102c861073c366004612f1d565b6115b5565b34801561074c575f80fd5b5061031261075b366004612eee565b6115e9565b34801561076b575f80fd5b506103d761077a366004613369565b600f6020525f908152604090205481565b348015610796575f80fd5b50600e546102e99060ff1681565b3480156107af575f80fd5b506102e96107be366004612f1d565b6116fa565b3480156107ce575f80fd5b506102c86107dd366004613048565b611774565b3480156107ed575f80fd5b506102e96107fc366004612f1d565b6117fc565b34801561080c575f80fd5b5061033e7f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd67581565b34801561083f575f80fd5b506102c861084e3660046132cb565b611809565b34801561085e575f80fd5b506103d761271081565b348015610873575f80fd5b5061054a600281565b348015610887575f80fd5b506102c8610896366004613380565b611867565b6102c86108a93660046133ed565b6118f7565b6102c86108bc366004612dc5565b6119bb565b3480156108cc575f80fd5b506103d76108db36600461342b565b611bcb565b3480156108eb575f80fd5b506102c86108fa366004613457565b611bf5565b34801561090a575f80fd5b5061054a600381565b34801561091e575f80fd5b506102c861092d366004613484565b611ca5565b34801561093d575f80fd5b506102c861094c366004613048565b611cee565b34801561095c575f80fd5b506006546102e99060ff1681565b348015610975575f80fd5b506102c86109843660046132cb565b611d47565b348015610994575f80fd5b506103126109a336600461349d565b611dc0565b3480156109b3575f80fd5b503061033e565b337f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd6756001600160a01b031614610a375760405162461bcd60e51b815260206004820152601e60248201527f4c7a4170703a20696e76616c696420656e64706f696e742063616c6c6572000060448201526064015b60405180910390fd5b61ffff86165f9081526001602052604081208054610a54906134eb565b80601f0160208091040260200160405190810160405280929190818152602001828054610a80906134eb565b8015610acb5780601f10610aa257610100808354040283529160200191610acb565b820191905f5260205f20905b815481529060010190602001808311610aae57829003601f168201915b50505050509050805186869050148015610ae557505f8151115b8015610b0d575080516020820120604051610b039088908890613523565b6040518091039020145b610b685760405162461bcd60e51b815260206004820152602660248201527f4c7a4170703a20696e76616c696420736f757263652073656e64696e6720636f6044820152651b9d1c9858dd60d21b6064820152608401610a2e565b610bdc8787878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050604080516020601f8a018190048102820181019092528881528a9350915088908890819084018382808284375f92019190915250611e6d92505050565b50505050505050565b5f6001600160e01b031982161580610c0d57506001600160e01b031982166336372b0760e01b145b80610c1c5750610c1c82611ee5565b92915050565b6060600a8054610c31906134eb565b80601f0160208091040260200160405190810160405280929190818152602001828054610c5d906134eb565b8015610ca85780601f10610c7f57610100808354040283529160200191610ca8565b820191905f5260205f20905b815481529060010190602001808311610c8b57829003601f168201915b5050505050905090565b610cba611f19565b6040516307e0db1760e01b815261ffff821660048201527f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd6756001600160a01b0316906307e0db17906024015b5f604051808303815f87803b158015610d1d575f80fd5b505af1158015610d2f573d5f803e3d5ffd5b5050505050565b5f33610d43818585611f78565b5060019392505050565b610d55611f19565b61ffff9091165f90815260036020526040902055565b610d73611f19565b6040516310ddb13760e01b815261ffff821660048201527f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd6756001600160a01b0316906310ddb13790602401610d06565b5f80600f81610dd56201518042613546565b81526020019081526020015f2054905080600d54118015610df85750600e5460ff165b15610e115780600d54610e0b9190613565565b91505090565b5090565b5f33610e2285828561209b565b610e2d858585612113565b506001949350505050565b5f805f80898989604051602001610e5294939291906135a0565b60408051601f198184030181529082905263040a7bb160e41b825291506001600160a01b037f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd67516906340a7bb1090610eb8908d90309086908c908c908c906004016135ce565b6040805180830381865afa158015610ed2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ef69190613623565b925092505097509795505050505050565b5f33610d43818585610f198383611bcb565b610f239190613645565b611f78565b61ffff83165f9081526001602052604081208054829190610f48906134eb565b80601f0160208091040260200160405190810160405280929190818152602001828054610f74906134eb565b8015610fbf5780601f10610f9657610100808354040283529160200191610fbf565b820191905f5260205f20905b815481529060010190602001808311610fa257829003601f168201915b505050505090508383604051610fd6929190613523565b60405180910390208180519060200120149150509392505050565b600c546001600160a01b0316331461101b5760405162461bcd60e51b8152600401610a2e90613658565b61102582826122a9565b5050565b611031611f19565b6040516342d65a8d60e01b81526001600160a01b037f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd67516906342d65a8d9061108190869086908690600401613674565b5f604051808303815f87803b158015611098575f80fd5b505af1158015610bdc573d5f803e3d5ffd5b600e5460ff166110cc5760405162461bcd60e51b8152600401610a2e90613691565b4661ffff891681036110f05760405162461bcd60e51b8152600401610a2e906136b2565b5f6110fe6201518042613546565b600d545f828152600f60205260409020549192509061111d9089613645565b11156111585760405162461bcd60e51b815260206004820152600a6024820152690457863656564206361760b41b6044820152606401610a2e565b5f818152600f6020526040902054611171908890613645565b5f828152600f60205260409020556111908b8b8b8b8b8b8b8b8b612355565b5050505050505050505050565b3330146111fb5760405162461bcd60e51b815260206004820152602660248201527f4e6f6e626c6f636b696e674c7a4170703a2063616c6c6572206d7573742062656044820152650204c7a4170760d41b6064820152608401610a2e565b61126f8686868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050604080516020601f8901819004810282018101909252878152899350915087908790819084018382808284375f920191909152506123cd92505050565b505050505050565b61127f611f19565b4661ffff84168190036112f157600e805460ff191684151517905560405161ffff8516905f80516020613c08833981519152906112c09030906020016136d6565b60408051601f1981840301815290829052600e546112e39260ff909116906136ee565b60405180910390a250505050565b5f6002838560405160200161130893929190613711565b60405160208183030381529060405290506113358582335f60405180602001604052805f81525034612433565b8461ffff165f80516020613c0883398151915284866040516113589291906136ee565b60405180910390a250505b505050565b6001600160a01b03165f9081526007602052604090205490565b61138a611f19565b6113935f6125d0565b565b60016020525f9081526040902080546113ad906134eb565b80601f01602080910402602001604051908101604052809291908181526020018280546113d9906134eb565b80156114245780601f106113fb57610100808354040283529160200191611424565b820191905f5260205f20905b81548152906001019060200180831161140757829003601f168201915b505050505081565b600c54604080516325ca7a8760e11b815290515f926001600160a01b031691634b94f50e916004808301926020929190829003018187875af1158015611474573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611498919061373f565b905090565b5f546001600160a01b031690565b600e545f9060ff166114cf5760405162461bcd60e51b8152600401610a2e90613691565b4661ffff841681036114f35760405162461bcd60e51b8152600401610a2e906136b2565b6114fb61142c565b91505f60018484426040516020016115169493929190613756565b60405160208183030381529060405290506115438582335f60405180602001604052805f81525034612433565b336001600160a01b03168561ffff167fa9abd88cb9207ea146a8c570a7c926ee640d4ef1eed13893a603f574d762f8818686604051611583929190613785565b60405180910390a3505092915050565b5f61159d30611368565b60095403905090565b6060600b8054610c31906134eb565b600c546001600160a01b031633146115df5760405162461bcd60e51b8152600401610a2e90613658565b611025828261261f565b61ffff81165f9081526001602052604081208054606092919061160b906134eb565b80601f0160208091040260200160405190810160405280929190818152602001828054611637906134eb565b80156116825780601f1061165957610100808354040283529160200191611682565b820191905f5260205f20905b81548152906001019060200180831161166557829003601f168201915b5050505050905080515f036116d95760405162461bcd60e51b815260206004820152601d60248201527f4c7a4170703a206e6f20747275737465642070617468207265636f72640000006044820152606401610a2e565b6116f35f601483516116eb9190613565565b83919061273e565b9392505050565b5f33816117078286611bcb565b9050838110156117675760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610a2e565b610e2d8286868403611f78565b61177c611f19565b818130604051602001611791939291906137a6565b60408051601f1981840301815291815261ffff85165f908152600160205220906117bb9082613820565b507f8c0400cfe2d1199b1a725c78960bcc2a344d869b80590d0f2bd005db15a572ce8383836040516117ef93929190613674565b60405180910390a1505050565b5f33610d43818585612113565b611811611f19565b600480546001600160a01b0319166001600160a01b0383161790556040517f5db758e995a17ec1ad84bdef7e8c3293a0bd6179bcce400dff5d4c3d87db726b9061185c908390612eda565b60405180910390a150565b61186f611f19565b6040516332fb62e760e21b81526001600160a01b037f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd675169063cbed8b9c906118c390889088908890889088906004016138d6565b5f604051808303815f87803b1580156118da575f80fd5b505af11580156118ec573d5f803e3d5ffd5b505050505050505050565b6118ff611f19565b4661ffff84168190036119545782600d819055508361ffff165f80516020613c288339815191523060405160200161193791906136d6565b60408051601f1981840301815290829052600d546112e392613785565b5f6003838560405160200161196b9392919061390e565b60405160208183030381529060405290506119988582335f60405180602001604052805f81525034612433565b8461ffff165f80516020613c288339815191528486604051611358929190613785565b61ffff86165f9081526005602052604080822090516119dd9088908890613523565b90815260408051602092819003830190206001600160401b0387165f9081529252902054905080611a5c5760405162461bcd60e51b815260206004820152602360248201527f4e6f6e626c6f636b696e674c7a4170703a206e6f2073746f726564206d65737360448201526261676560e81b6064820152608401610a2e565b808383604051611a6d929190613523565b604051809103902014611acc5760405162461bcd60e51b815260206004820152602160248201527f4e6f6e626c6f636b696e674c7a4170703a20696e76616c6964207061796c6f616044820152601960fa1b6064820152608401610a2e565b61ffff87165f908152600560205260408082209051611aee9089908990613523565b90815260408051602092819003830181206001600160401b0389165f90815290845282902093909355601f88018290048202830182019052868252611b8391899189908990819084018382808284375f9201919091525050604080516020601f8a018190048102820181019092528881528a9350915088908890819084018382808284375f920191909152506123cd92505050565b7fc264d91f3adc5588250e1551f547752ca0cfa8f6b530d243b9f9f4cab10ea8e58787878785604051611bba95949392919061393a565b60405180910390a150505050505050565b6001600160a01b039182165f90815260086020908152604080832093909416825291909152205490565b611bfd611f19565b5f8111611c445760405162461bcd60e51b81526020600482015260156024820152744c7a4170703a20696e76616c6964206d696e47617360581b6044820152606401610a2e565b61ffff8381165f8181526002602090815260408083209487168084529482529182902085905581519283528201929092529081018290527f9d5c7c0b934da8fefa9c7760c98383778a12dfbfc0c3b3106518f43fb9508ac0906060016117ef565b611cad611f19565b6006805460ff19168215159081179091556040519081527f1584ad594a70cbe1e6515592e1272a987d922b097ead875069cebe8b40c004a49060200161185c565b611cf6611f19565b61ffff83165f908152600160205260409020611d13828483613974565b507ffa41487ad5d6728f0b19276fa1eddc16558578f5109fc39d2dc33c3230470dab8383836040516117ef93929190613674565b611d4f611f19565b6001600160a01b038116611db45760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610a2e565b611dbd816125d0565b50565b604051633d7b2f6f60e21b815261ffff808616600483015284166024820152306044820152606481018290526060907f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd6756001600160a01b03169063f5ecbdbc906084015f60405180830381865afa158015611e3d573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611e649190810190613a73565b95945050505050565b5f80611ecf5a60966366ad5c8a60e01b89898989604051602401611e949493929190613aa4565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091523092919061284a565b915091508161126f5761126f86868686856128ce565b5f6001600160e01b03198216630a72677560e11b1480610c1c57506301ffc9a760e01b6001600160e01b0319831614610c1c565b33611f2261149d565b6001600160a01b0316146113935760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a2e565b6001600160a01b038316611fda5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610a2e565b6001600160a01b03821661203b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610a2e565b6001600160a01b038381165f8181526008602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b5f6120a68484611bcb565b90505f19811461210d57818110156121005760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610a2e565b61210d8484848403611f78565b50505050565b6001600160a01b0383166121775760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610a2e565b6001600160a01b0382166121d95760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610a2e565b6001600160a01b0383165f90815260076020526040902054818110156122505760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610a2e565b6001600160a01b038085165f8181526007602052604080822086860390559286168082529083902080548601905591515f80516020613c488339815191529061229c9086815260200190565b60405180910390a361210d565b6001600160a01b0382166122ff5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610a2e565b8060095f8282546123109190613645565b90915550506001600160a01b0382165f818152600760209081526040808320805486019055518481525f80516020613c48833981519152910160405180910390a35050565b6118ec898989898080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050604080516020601f8a018190048102820181019092528881528c93508b92508a918a908a90819084018382808284375f9201919091525061296892505050565b602081015161ffff81166123ec576123e785858585612a0b565b610d2f565b60405162461bcd60e51b815260206004820152601c60248201527b4f4654436f72653a20756e6b6e6f776e207061636b6574207479706560201b6044820152606401610a2e565b61ffff86165f9081526001602052604081208054612450906134eb565b80601f016020809104026020016040519081016040528092919081815260200182805461247c906134eb565b80156124c75780601f1061249e576101008083540402835291602001916124c7565b820191905f5260205f20905b8154815290600101906020018083116124aa57829003601f168201915b5050505050905080515f036125375760405162461bcd60e51b815260206004820152603060248201527f4c7a4170703a2064657374696e6174696f6e20636861696e206973206e6f742060448201526f61207472757374656420736f7572636560801b6064820152608401610a2e565b612542878751612a93565b60405162c5803160e81b81526001600160a01b037f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd675169063c5803100908490612599908b9086908c908c908c908c90600401613ae1565b5f604051808303818588803b1580156125b0575f80fd5b505af11580156125c2573d5f803e3d5ffd5b505050505050505050505050565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03821661267f5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610a2e565b6001600160a01b0382165f90815260076020526040902054818110156126f25760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610a2e565b6001600160a01b0383165f8181526007602090815260408083208686039055600980548790039055518581529192915f80516020613c48833981519152910160405180910390a3505050565b60608161274c81601f613645565b101561278b5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610a2e565b6127958284613645565b845110156127d95760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401610a2e565b6060821580156127f75760405191505f825260208201604052612841565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015612830578051835260209283019201612818565b5050858452601f01601f1916604052505b50949350505050565b5f60605f805f8661ffff166001600160401b0381111561286c5761286c613159565b6040519080825280601f01601f191660200182016040528015612896576020820181803683370190505b5090505f808751602089015f8d8df191503d9250868311156128b6578692505b828152825f602083013e909890975095505050505050565b818051906020012060055f8761ffff1661ffff1681526020019081526020015f20856040516128fd9190613b3a565b9081526040805191829003602090810183206001600160401b0388165f908152915220919091557fe183f33de2837795525b4792ca4cd60535bd77c53b7e7030060bfcf5734d6b0c906129599087908790879087908790613b55565b60405180910390a15050505050565b612974865f835f612b03565b5f61298188888888612b7d565b90505f8087836040516020016129999392919061390e565b60405160208183030381529060405290506129b8888287878734612433565b886001600160a01b03168861ffff167f39a4c66499bcf4b56d79f0dde8ed7a9d4925a0df55825206b2b8531e202be0d089856040516129f8929190613785565b60405180910390a3505050505050505050565b5f8082806020019051810190612a219190613bb2565b90935091505f9050612a338382612baf565b9050612a40878284612c13565b9150806001600160a01b03168761ffff167fbf551ec93859b170f9b2141bd9298bf3f64322c6f7beb2543a0cb669834118bf84604051612a8291815260200190565b60405180910390a350505050505050565b61ffff82165f9081526003602052604081205490819003612ab357506127105b808211156113635760405162461bcd60e51b815260206004820181905260248201527f4c7a4170703a207061796c6f61642073697a6520697320746f6f206c617267656044820152606401610a2e565b60065460ff1615612b1f57612b1a84848484612c26565b61210d565b81511561210d5760405162461bcd60e51b815260206004820152602660248201527f4f4654436f72653a205f61646170746572506172616d73206d7573742062652060448201526532b6b83a3c9760d11b6064820152608401610a2e565b5f336001600160a01b0386168114612b9a57612b9a86828561209b565b612ba5863085612113565b5090949350505050565b5f612bbb826014613645565b83511015612c035760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b6044820152606401610a2e565b500160200151600160601b900490565b5f612c1f308484612113565b5092915050565b5f612c3083612cfd565b61ffff8087165f90815260026020908152604080832093891683529290529081205491925090612c61908490613645565b90505f8111612caf5760405162461bcd60e51b815260206004820152601a602482015279131e905c1c0e881b5a5b91d85cd31a5b5a5d081b9bdd081cd95d60321b6044820152606401610a2e565b8082101561126f5760405162461bcd60e51b815260206004820152601b60248201527a4c7a4170703a20676173206c696d697420697320746f6f206c6f7760281b6044820152606401610a2e565b5f602282511015612d4f5760405162461bcd60e51b815260206004820152601c60248201527b4c7a4170703a20696e76616c69642061646170746572506172616d7360201b6044820152606401610a2e565b506022015190565b61ffff81168114611dbd575f80fd5b5f8083601f840112612d76575f80fd5b5081356001600160401b03811115612d8c575f80fd5b602083019150836020828501011115612da3575f80fd5b9250929050565b80356001600160401b0381168114612dc0575f80fd5b919050565b5f805f805f8060808789031215612dda575f80fd5b8635612de581612d57565b955060208701356001600160401b0380821115612e00575f80fd5b612e0c8a838b01612d66565b9097509550859150612e2060408a01612daa565b94506060890135915080821115612e35575f80fd5b50612e4289828a01612d66565b979a9699509497509295939492505050565b5f60208284031215612e64575f80fd5b81356001600160e01b0319811681146116f3575f80fd5b5f5b83811015612e95578181015183820152602001612e7d565b50505f910152565b5f8151808452612eb4816020860160208601612e7b565b601f01601f19169290920160200192915050565b602081525f6116f36020830184612e9d565b6001600160a01b0391909116815260200190565b5f60208284031215612efe575f80fd5b81356116f381612d57565b6001600160a01b0381168114611dbd575f80fd5b5f8060408385031215612f2e575f80fd5b8235612f3981612f09565b946020939093013593505050565b5f8060408385031215612f58575f80fd5b8235612f3981612d57565b5f805f60608486031215612f75575f80fd5b8335612f8081612f09565b92506020840135612f9081612f09565b929592945050506040919091013590565b80358015158114612dc0575f80fd5b5f805f805f805f60a0888a031215612fc6575f80fd5b8735612fd181612d57565b965060208801356001600160401b0380821115612fec575f80fd5b612ff88b838c01612d66565b909850965060408a0135955086915061301360608b01612fa1565b945060808a0135915080821115613028575f80fd5b506130358a828b01612d66565b989b979a50959850939692959293505050565b5f805f6040848603121561305a575f80fd5b833561306581612d57565b925060208401356001600160401b0381111561307f575f80fd5b61308b86828701612d66565b9497909650939450505050565b5f805f805f805f805f60e08a8c0312156130b0575f80fd5b89356130bb81612f09565b985060208a01356130cb81612d57565b975060408a01356001600160401b03808211156130e6575f80fd5b6130f28d838e01612d66565b909950975060608c0135965060808c0135915061310e82612f09565b90945060a08b01359061312082612f09565b90935060c08b01359080821115613135575f80fd5b506131428c828d01612d66565b915080935050809150509295985092959850929598565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b038111828210171561319557613195613159565b604052919050565b5f6001600160401b038211156131b5576131b5613159565b50601f01601f191660200190565b5f82601f8301126131d2575f80fd5b81356131e56131e08261319d565b61316d565b8181528460208386010111156131f9575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f60608486031215613227575f80fd5b833561323281612d57565b925060208401356001600160401b0381111561324c575f80fd5b613258868287016131c3565b92505061326760408501612daa565b90509250925092565b5f805f60608486031215613282575f80fd5b833561328d81612d57565b925061329b60208501612fa1565b915060408401356001600160401b038111156132b5575f80fd5b6132c1868287016131c3565b9150509250925092565b5f602082840312156132db575f80fd5b81356116f381612f09565b5f80604083850312156132f7575f80fd5b823561330281612d57565b9150602083013561331281612d57565b809150509250929050565b5f806040838503121561332e575f80fd5b823561333981612d57565b915060208301356001600160401b03811115613353575f80fd5b61335f858286016131c3565b9150509250929050565b5f60208284031215613379575f80fd5b5035919050565b5f805f805f60808688031215613394575f80fd5b853561339f81612d57565b945060208601356133af81612d57565b93506040860135925060608601356001600160401b038111156133d0575f80fd5b6133dc88828901612d66565b969995985093965092949392505050565b5f805f606084860312156133ff575f80fd5b833561340a81612d57565b92506020840135915060408401356001600160401b038111156132b5575f80fd5b5f806040838503121561343c575f80fd5b823561344781612f09565b9150602083013561331281612f09565b5f805f60608486031215613469575f80fd5b833561347481612d57565b92506020840135612f9081612d57565b5f60208284031215613494575f80fd5b6116f382612fa1565b5f805f80608085870312156134b0575f80fd5b84356134bb81612d57565b935060208501356134cb81612d57565b925060408501356134db81612f09565b9396929550929360600135925050565b600181811c908216806134ff57607f821691505b60208210810361351d57634e487b7160e01b5f52602260045260245ffd5b50919050565b818382375f9101908152919050565b634e487b7160e01b5f52601160045260245ffd5b5f8261356057634e487b7160e01b5f52601260045260245ffd5b500490565b81810381811115610c1c57610c1c613532565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b61ffff85168152606060208201525f6135bd606083018587613578565b905082604083015295945050505050565b61ffff871681526001600160a01b038616602082015260a0604082018190525f906135fb90830187612e9d565b85151560608401528281036080840152613616818587613578565b9998505050505050505050565b5f8060408385031215613634575f80fd5b505080516020909101519092909150565b80820180821115610c1c57610c1c613532565b6020808252600290820152614e4d60f01b604082015260600190565b61ffff84168152604060208201525f611e64604083018486613578565b6020808252600790820152661a5b9d985b1a5960ca1b604082015260600190565b6020808252600a908201526939b0b6b29031b430b4b760b11b604082015260600190565b60609190911b6001600160601b031916815260140190565b604081525f6137006040830185612e9d565b905082151560208301529392505050565b61ffff84168152606060208201525f61372d6060830185612e9d565b90508215156040830152949350505050565b5f6020828403121561374f575f80fd5b5051919050565b61ffff85168152608060208201525f6137726080830186612e9d565b6040830194909452506060015292915050565b604081525f6137976040830185612e9d565b90508260208301529392505050565b8284823760609190911b6001600160601b0319169101908152601401919050565b601f821115611363575f81815260208120601f850160051c810160208610156137ed5750805b601f850160051c820191505b8181101561126f578281556001016137f9565b5f19600383901b1c191660019190911b1790565b81516001600160401b0381111561383957613839613159565b61384d8161384784546134eb565b846137c7565b602080601f83116001811461387b575f84156138695750858301515b613873858261380c565b86555061126f565b5f85815260208120601f198616915b828110156138a95788860151825594840194600190910190840161388a565b50858210156138c657878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f61ffff808816835280871660208401525084604083015260806060830152613903608083018486613578565b979650505050505050565b61ffff84168152606060208201525f61392a6060830185612e9d565b9050826040830152949350505050565b61ffff86168152608060208201525f613957608083018688613578565b6001600160401b0394909416604083015250606001529392505050565b6001600160401b0383111561398b5761398b613159565b61399f8361399983546134eb565b836137c7565b5f601f8411600181146139cb575f85156139b95750838201355b6139c3868261380c565b845550610d2f565b5f83815260209020601f19861690835b828110156139fb57868501358255602094850194600190920191016139db565b5086821015613a17575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b5f82601f830112613a38575f80fd5b8151613a466131e08261319d565b818152846020838601011115613a5a575f80fd5b613a6b826020830160208701612e7b565b949350505050565b5f60208284031215613a83575f80fd5b81516001600160401b03811115613a98575f80fd5b613a6b84828501613a29565b61ffff85168152608060208201525f613ac06080830186612e9d565b6001600160401b038516604084015282810360608401526139038185612e9d565b61ffff8716815260c060208201525f613afd60c0830188612e9d565b8281036040840152613b0f8188612e9d565b6001600160a01b0387811660608601528616608085015283810360a085015290506136168185612e9d565b5f8251613b4b818460208701612e7b565b9190910192915050565b61ffff8616815260a060208201525f613b7160a0830187612e9d565b6001600160401b03861660408401528281036060840152613b928186612e9d565b90508281036080840152613ba68185612e9d565b98975050505050505050565b5f805f60608486031215613bc4575f80fd5b8351613bcf81612d57565b60208501519093506001600160401b03811115613bea575f80fd5b613bf686828701613a29565b92505060408401519050925092509256fe8bf89adedf6e5cb38caf3b2cc7e255e668fec50ffeee80e627d7ee7ff42ea89ffba6058f70462ebfb18b3e74d307def7438209fc600413e1fc842c59b0ba5bf4ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212200925be473ed0a77aaeba73c62029065d5a6c096f58b568386f13c80bcd4271d964736f6c63430008150033

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

000000000000000000000000ec306e46549a7e8f4fce823d3058f2d134133b1700000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd67500000000000000000000000000000000000000000000021e19e0c9bab2400000

-----Decoded View---------------
Arg [0] : _minter (address): 0xEc306E46549A7E8f4fCE823D3058f2D134133B17
Arg [1] : _layerZeroEndpoint (address): 0x66A71Dcef29A0fFBDBE3c6a460a3B5BC225Cd675
Arg [2] : _cap (uint256): 10000000000000000000000

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000ec306e46549a7e8f4fce823d3058f2d134133b17
Arg [1] : 00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd675
Arg [2] : 00000000000000000000000000000000000000000000021e19e0c9bab2400000


Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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