Contract 0x880672ab1d46d987e5d663fc7476cd8df3c9f937 1

 
Txn Hash Method
Block
From
To
Value [Txn Fee]
0xc67b1701a117a6aa0c032a474d72b0a382ad1203be9261b9e6da3c35a0824fc0Collect341867442022-03-23 11:00:22195 days 19 hrs ago0x45a6194d91156e0b6b54bb2cb816fead54593dcc IN  Fantasm Finance: Pool0 FTM0.007803042332
0x4346af245f1132ae26990d234efbd0e99b173ec30fa4f763b263a02b2e90126dCollect333432862022-03-13 20:02:16205 days 10 hrs ago0x45a6194d91156e0b6b54bb2cb816fead54593dcc IN  Fantasm Finance: Pool0 FTM0.008100379155
0x76667f4be40b3ead4ed90fdf5340e90cfc9d84673ef443c0d4a6a18414c2001fCollect330988742022-03-11 1:53:24208 days 4 hrs ago0x31ce4ae28d04791f8da6e3810cea7d151c429498 IN  Fantasm Finance: Pool0 FTM0.023425550336
0xaf85041bf9c2fec94a82a71f5f4690f4cbfcad4c27a4d50d641071a603b88482Collect330195802022-03-10 4:17:08209 days 1 hr ago0x25cc8596dcfaedce0a343974816aa5609ebe9d83 IN  Fantasm Finance: Pool0 FTM0.058320798277
0xa2854ec6c68750ea7ad0c40b94328408186dcd641dc1cd3ce1ac6585b42f8355Zap330195642022-03-10 4:16:56209 days 1 hr ago0x25cc8596dcfaedce0a343974816aa5609ebe9d83 IN  Fantasm Finance: Pool18 FTM0.119754469978
0x71ba7a9661f0cdad1e75bdd310459fa34f4c6d2d3fe406158c35e08d7ef8d96bMint330085972022-03-10 1:15:58209 days 4 hrs ago0x0c5a02f09f63760290ad96f640ca2d7fe11e67cb IN  Fantasm Finance: Pool0 FTM0.064848703416
0x971018d8c8f5dd2e5d1abb2431dfec948a6825f561334fe4a617520e4b82bf9bCollect330081782022-03-10 1:09:42209 days 5 hrs ago0x0c5a02f09f63760290ad96f640ca2d7fe11e67cb IN  Fantasm Finance: Pool0 FTM0.023977299481
0x33a4c20248d1bae3d89f00be83bc64c34c2bdf360d31f5258dd5625ff52541e6Mint330081302022-03-10 1:08:53209 days 5 hrs ago0x0c5a02f09f63760290ad96f640ca2d7fe11e67cb IN  Fantasm Finance: Pool0 FTM0.077029664126
0xf1a57f3d8487badb05177a877f0900a26a59aa58ab3bd8eba5341fc2ffe4615eCollect330060362022-03-10 0:32:28209 days 5 hrs ago0x0000000b6654b4bdfe81e4675d8d76333a944e70 IN  Fantasm Finance: Pool0 FTM0.021735569561
0x1c7e0770d6f7afbcd913db79e55d67810f7bf7c525824e8a956ac077526d6716Mint330060122022-03-10 0:32:04209 days 5 hrs ago0x0000000b6654b4bdfe81e4675d8d76333a944e70 IN  Fantasm Finance: Pool0 FTM0.051627913145
0xe3f52d1a0e5d458b37249aacf1e6793bcb395a9a0b6401dbca968199a3ffe556Recollateralize ...330040072022-03-09 23:48:54209 days 6 hrs ago0x0000000b6654b4bdfe81e4675d8d76333a944e70 IN  Fantasm Finance: Pool1 FTM0.019029075054
0x1d7b10838f91565ece2b0a40019c5ca51e72f711e0521cd8efb63a6721dac41cCollect330034102022-03-09 23:39:02209 days 6 hrs ago0x0000000b6654b4bdfe81e4675d8d76333a944e70 IN  Fantasm Finance: Pool0 FTM0.024352050867
0x95f9bdcde8458e059c631d1a69837ed32c29c389e8f3b3d856110224cb03bd6dMint330033862022-03-09 23:38:43209 days 6 hrs ago0x0000000b6654b4bdfe81e4675d8d76333a944e70 IN  Fantasm Finance: Pool0 FTM0.060785518732
0x9159aa96e4e7f3ab694a1f78b2506653a179f4dfeb38cbd8fc6d821751148259Collect330014032022-03-09 23:08:04209 days 7 hrs ago0x6853285716a92af6dd07f2f6aebca23e5b13f8f6 IN  Fantasm Finance: Pool0 FTM0.021960375297
0x6bd1efc60a8aac73a17b5e3beae6befbd03c687fa6d0c8d700944918a7b75ca3Mint330013882022-03-09 23:07:53209 days 7 hrs ago0x6853285716a92af6dd07f2f6aebca23e5b13f8f6 IN  Fantasm Finance: Pool0.001 FTM0.060459759593
0x08f49b198663c11bcc3c8d6cc966b95b8b662852b87c3ce1d34cbd7c78b5abdfCollect330011812022-03-09 23:04:43209 days 7 hrs ago0x0000000b6654b4bdfe81e4675d8d76333a944e70 IN  Fantasm Finance: Pool0 FTM0.019513437818
0xde55d2dd5d006979247c6ebfafd75ee9b5ef8a159105d1076924bc3b5ee210c0Mint330011512022-03-09 23:04:11209 days 7 hrs ago0x0000000b6654b4bdfe81e4675d8d76333a944e70 IN  Fantasm Finance: Pool0 FTM0.053472423092
0xd96767e74e98de5b01e1faf055018ff36c9afc3452a4a8bf61ff1069c37a3556Recollateralize ...330010642022-03-09 23:02:43209 days 7 hrs ago0xc53f5a27021455293aa34da308280abc4cad210a IN  Fantasm Finance: Pool1 FTM0.018399127609
0xbe49ae88274938b8b63b0a58a1a06180f9312e3415c9c29760645dc91d4c5605Collect329996112022-03-09 22:39:10209 days 7 hrs ago0x0000000b6654b4bdfe81e4675d8d76333a944e70 IN  Fantasm Finance: Pool0 FTM0.013725507044
0x943caaf1badbd55ba75b4db8a8579673e1845e89000ee1e65baaf50ac35ff85eCollect329995592022-03-09 22:38:18209 days 7 hrs ago0x0000000b6654b4bdfe81e4675d8d76333a944e70 IN  Fantasm Finance: Pool0 FTM0.028338774399
0x6c1c02b0bd8c5110bede7f292b8517113c1cacc53714524bc5398dd0054dbfbfMint329995122022-03-09 22:37:40209 days 7 hrs ago0x0000000b6654b4bdfe81e4675d8d76333a944e70 IN  Fantasm Finance: Pool0 FTM0.058451624935
0xc037358a4a28b6b097f6c1160da67e10d0e37fde6e2ea735ddba3f73c44f6093Mint329965842022-03-09 21:50:38209 days 8 hrs ago0x0000000b6654b4bdfe81e4675d8d76333a944e70 IN  Fantasm Finance: Pool0 FTM0.05153232449
0x85807e4ca31d03c758bbfa0d55f7840fb45d2741d66d9c5b5194ba733c37678cRedeem329933442022-03-09 20:56:07209 days 9 hrs ago0xd027e3bc1b4be983002119583d9453f7389d61fd IN  Fantasm Finance: Pool0 FTM0.037494847988
0x0c62dbee742da97425b88c34368fd6fda0ee4d98287f7d3e95fb3f1eb3e9a44eRedeem329914602022-03-09 20:25:34209 days 9 hrs ago0x2764d43a8b9cf15aafabde120329ee1bef95f7e3 IN  Fantasm Finance: Pool0 FTM0.054237109878
0xc13eaea7c66ec113d2457d3579241cae957fb2ec0f52f8d1e7840b6387292825Collect329909942022-03-09 20:15:10209 days 9 hrs ago0x910b8562fd07c9226490cb42be7d74d06a9906ae IN  Fantasm Finance: Pool0 FTM0.022858043517
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xa2854ec6c68750ea7ad0c40b94328408186dcd641dc1cd3ce1ac6585b42f8355330195642022-03-10 4:16:56209 days 1 hr ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token18 FTM
0xe3f52d1a0e5d458b37249aacf1e6793bcb395a9a0b6401dbca968199a3ffe556330040072022-03-09 23:48:54209 days 6 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token1 FTM
0x6bd1efc60a8aac73a17b5e3beae6befbd03c687fa6d0c8d700944918a7b75ca3330013882022-03-09 23:07:53209 days 7 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token0.001 FTM
0xd96767e74e98de5b01e1faf055018ff36c9afc3452a4a8bf61ff1069c37a3556330010642022-03-09 23:02:43209 days 7 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token1 FTM
0xe50ce17757cdc3064f16dc9e5081deb4d6b32d431cfbf843cb6ed6a6336de8e7329907112022-03-09 20:10:44209 days 10 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token1 FTM
0x8304ab8685377a7a28611eede1b5719bca1a0de886db2ad7e0e5c418a2376c5b329881492022-03-09 19:30:11209 days 10 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token0.611589080761168016 FTM
0xe73b13e8f966ec3de65e10d4d5dd35db8445791606bc924ece2bf24ae2b086fc329854192022-03-09 18:47:12209 days 11 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token800 FTM
0x430a0795b7e42fa898013eea81813df9b47d7fb5f313c003456eb3f287dbb012329851142022-03-09 18:42:28209 days 11 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token1,000 FTM
0x3cd8749509035a8dc2f6a6032a5d948792020bdb320eda68af19c392edafe701329846282022-03-09 18:35:07209 days 11 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token950 FTM
0x40c57ffc295fa34eea26ea27458eae8875e899974722a8ba3420ef532cbb2b2c329844552022-03-09 18:32:50209 days 11 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token600 FTM
0x14ed689a8eb789e416738f20aa3ef5785bd4e3fa2df22af1265ea538499e7de7329839162022-03-09 18:24:58209 days 11 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token300 FTM
0x6766101a6343a98c5165f5d7a4bf973a86f9f954c2887fd065d6e76fc2a93852329835762022-03-09 18:19:59209 days 11 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token50 FTM
0x2d648ff284d2b09fac009fc0ac2a9f3e10d6f03999488ffcd2da344b3df256d2329833662022-03-09 18:16:39209 days 11 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token480 FTM
0xda5caf558e191e09034fa98900112908a29eea99733682bf1f61a4c589b00714329831682022-03-09 18:13:37209 days 11 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token50 FTM
0x0ebf6eb98352620e28b2046d2929cdf293c4627d3ae12848932533da98cd1f10329831492022-03-09 18:13:18209 days 12 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token350 FTM
0x164167fa5ca2a3e6082bbd556cadb7890833eb5c6a5c96968f1e950ef21d2a58329830722022-03-09 18:11:54209 days 12 hrs ago 0xdbde92f633f87fd19a4172ac5902d96a6de417be Fantasm Finance: Pool0.187743637516095885 FTM
0x1f19c9f3b99b7b3f658d94956320e659643e8afeb7874e2fa7d590a191d913a9329829932022-03-09 18:10:51209 days 12 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token220 FTM
0x74094edd5e5278d3eb4969533157169782a27e6da789a768be064a128f30e4db329827212022-03-09 18:07:10209 days 12 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token200 FTM
0x791985c0a1aac3b05254833a7e5f146bec6e0cbec4fe10984587f61caab5b042329825232022-03-09 18:03:11209 days 12 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token150 FTM
0x7acef681b0615112aa1412228050ebdac396bb62efa0e8df105015f8e0dbf30d329823472022-03-09 18:00:04209 days 12 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token8 FTM
0x62a209f99497d79afb8b4df8aae52a9ba15a8f8e5e132260c62747681d04da33329812482022-03-09 17:43:26209 days 12 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token3 FTM
0x68a3c1c0c75e5e02584ecc67d2f8f45c1c0059aa586164071ee401135c29189c329790592022-03-09 17:08:39209 days 13 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token10 FTM
0x336316b7a9622119978439baa48d92652389038ba2ff3ffabf1eeda5f5575f49329785782022-03-09 17:01:55209 days 13 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token1 FTM
0x2d1fccb80e6283602923b02fc9d0a3d3500de18bc5509790b8a89c5e2fd7d5f0329784162022-03-09 16:59:47209 days 13 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token1 FTM
0xddd2dabe3365c5919d794fe2035fc6c2aefed58393de1c5e8e717c0faabf0585329761542022-03-09 16:26:23209 days 13 hrs ago Fantasm Finance: Pool Fantom Finance: Wrapped Fantom Token0.000000000000001 FTM
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Pool

Compiler Version
v0.8.4+commit.c7e474f2

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 16 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (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 Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

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

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _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 2 of 16 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (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() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

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

        _;

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

File 3 of 16 : ERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.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.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * 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}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * 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 value {ERC20} uses, unless this function is
     * 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, _allowances[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 = _allowances[owner][spender];
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `sender` to `recipient`.
     *
     * 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;
        }
        _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;
        _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;
        }
        _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 Spend `amount` form the allowance of `owner` toward `spender`.
     *
     * 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 4 of 16 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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);

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

File 5 of 16 : 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 6 of 16 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 7 of 16 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

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

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

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

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

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

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

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 8 of 16 : 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 9 of 16 : IUniswapV2Router01.sol
pragma solidity >=0.6.2;

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

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

    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}

File 10 of 16 : IUniswapV2Router02.sol
pragma solidity >=0.6.2;

import './IUniswapV2Router01.sol';

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

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}

File 11 of 16 : Pool.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.4;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "./interfaces/IXftm.sol";
import "./interfaces/IFantasm.sol";
import "./interfaces/IMasterOracle.sol";
import "./interfaces/IWETH.sol";
import "./libs/WethUtils.sol";

contract Pool is Ownable, ReentrancyGuard {
    using SafeERC20 for ERC20;
    using SafeERC20 for IWETH;
    using SafeERC20 for IXftm;
    using SafeERC20 for IFantasm;

    struct UserInfo {
        uint256 xftmBalance;
        uint256 fantasmBalance;
        uint256 ftmBalance;
        uint256 lastAction;
    }

    /* ========== ADDRESSES ================ */

    IMasterOracle public oracle;
    IXftm public xftm;
    IFantasm public fantasm;
    address public feeReserve;

    /* ========== STATE VARIABLES ========== */

    mapping(address => UserInfo) public userInfo;

    uint256 public unclaimedFtm;
    uint256 public unclaimedXftm;
    uint256 public unclaimedFantasm;

    // Constants for various precisions
    uint256 private constant PRICE_PRECISION = 1e18;
    uint256 private constant COLLATERAL_RATIO_MAX = 1e6;
    uint256 private constant PRECISION = 1e6;

    // AccessControl state variables
    bool public mintPaused = false;
    bool public redeemPaused = false;

    uint256 public maxXftmSupply = 100_000_000 ether; // limit the maximum Xftm Supply

    // Collateral ratio
    uint256 public collateralRatio = 1e6;
    uint256 public lastRefreshCrTimestamp;
    uint256 public refreshCooldown = 3600; // = 1 hour
    uint256 public ratioStepUp = 2000; // = 0.002 or 0.2% -> ratioStep when CR increase
    uint256 public ratioStepDown = 1000; // = 0.001 or 0.1% -> ratioStep when CR decrease
    uint256 public priceTarget = 1e18; // = 1; 1 XFTM pegged to the value of 1 FTM
    uint256 public priceBand = 5e15; // = 0.005; CR will be adjusted if XFTM > 1.005 FTM or XFTM < 0.995 FTM
    uint256 public minCollateralRatio = 1e6;
    bool public collateralRatioPaused = false;

    // fees
    uint256 public redemptionFee = 5000; // 6 decimals of precision
    uint256 public constant REDEMPTION_FEE_MAX = 9000; // 0.9%
    uint256 public mintingFee = 3000; // 6 decimals of precision
    uint256 public constant MINTING_FEE_MAX = 5000; // 0.5%

    // zap
    IUniswapV2Router02 public swapRouter;
    address[] public swapPaths;
    uint256 public swapSlippage;
    uint256 private constant SWAP_TIMEOUT = 10 minutes;
    uint256 private constant SLIPPAGE_PRECISION = 1e6;

    /* ========== CONSTRUCTOR ========== */

    constructor(address _xftm, address _fantasm) {
        require(_xftm != address(0), "Pool::initialize: invalidAddress");
        require(_fantasm != address(0), "Pool::initialize: invalidAddress");
        xftm = IXftm(_xftm);
        fantasm = IFantasm(_fantasm);
        xftm.setMinter(address(this));
        fantasm.setPool(address(this));
    }

    /* ========== VIEWS ========== */

    function info()
        external
        view
        returns (
            uint256 _collateralRatio,
            uint256 _lastRefreshCrTimestamp,
            uint256 _mintingFee,
            uint256 _redemptionFee,
            bool _mintingPaused,
            bool _redemptionPaused,
            uint256 _collateralBalance,
            uint256 _maxXftmSupply
        )
    {
        _collateralRatio = collateralRatio;
        _lastRefreshCrTimestamp = lastRefreshCrTimestamp;
        _mintingFee = mintingFee;
        _redemptionFee = redemptionFee;
        _mintingPaused = mintPaused;
        _redemptionPaused = redeemPaused;
        _collateralBalance = usableFtmBalance();
        _maxXftmSupply = maxXftmSupply;
    }

    function usableFtmBalance() public view returns (uint256) {
        uint256 _ftmBalance = WethUtils.weth.balanceOf(address(this));
        return _ftmBalance > unclaimedFtm ? (_ftmBalance - unclaimedFtm) : 0;
    }

    /// @param _ftmIn Amount of FTM input.
    /// @param _fantasmIn Amount of FSM input.
    /// @return _xftmOut : the amount of XFTM output.
    /// @return _minFtmIn : the required amount of FSM input.
    /// @return _minFantasmIn : the required amount of FSM input.
    /// @return _fee : the fee amount in FTM.
    function calcMint(uint256 _ftmIn, uint256 _fantasmIn)
        public
        view
        returns (
            uint256 _xftmOut,
            uint256 _minFtmIn,
            uint256 _minFantasmIn,
            uint256 _fee
        )
    {
        uint256 _fantasmPrice = oracle.getFantasmPrice();
        require(_fantasmPrice > 0, "Pool::calcMint: Invalid Fantasm price");

        if (collateralRatio == COLLATERAL_RATIO_MAX || (collateralRatio > 0 && _ftmIn > 0)) {
            _minFtmIn = _ftmIn;
            _minFantasmIn = (_ftmIn * (COLLATERAL_RATIO_MAX - collateralRatio) * PRICE_PRECISION) / collateralRatio / _fantasmPrice;
            _xftmOut = (_ftmIn * COLLATERAL_RATIO_MAX * (PRECISION - mintingFee)) / collateralRatio / PRECISION;
            _fee = (_ftmIn * mintingFee) / PRECISION;
        } else {
            _minFantasmIn = _fantasmIn;
            _xftmOut = (_fantasmIn * _fantasmPrice * COLLATERAL_RATIO_MAX * (PRECISION - mintingFee)) / PRECISION / (COLLATERAL_RATIO_MAX - collateralRatio) / PRICE_PRECISION;
            _minFtmIn = (_fantasmIn * _fantasmPrice * collateralRatio) / (COLLATERAL_RATIO_MAX - collateralRatio) / PRICE_PRECISION;
            _fee = (_fantasmIn * _fantasmPrice * collateralRatio * mintingFee) / PRECISION / (COLLATERAL_RATIO_MAX - collateralRatio) / PRICE_PRECISION;
        }
    }

    /// @notice Calculate the expected results for zap minting
    /// @param _ftmIn Amount of FTM input.
    /// @return _xftmOut : the amount of XFTM output.
    /// @return _fantasmOut : the amount of Fantasm output by swapping
    /// @return _ftmFee : the fee amount in FTM.
    /// @return _ftmSwapIn : the amount of FTM to swap
    function calcZapMint(uint256 _ftmIn)
        public
        view
        returns (
            uint256 _xftmOut,
            uint256 _fantasmOut,
            uint256 _ftmFee,
            uint256 _ftmSwapIn
        )
    {
        uint256 _fantasmPrice = oracle.getFantasmPrice();
        require(_fantasmPrice > 0, "Pool::calcZapMint: Invalid Fantasm price");
        _ftmSwapIn = (_ftmIn * (COLLATERAL_RATIO_MAX - collateralRatio)) / COLLATERAL_RATIO_MAX;
        _fantasmOut = (_ftmSwapIn * PRICE_PRECISION) / _fantasmPrice;
        _ftmFee = (_ftmIn * mintingFee * collateralRatio) / COLLATERAL_RATIO_MAX / PRECISION;
        _xftmOut = _ftmIn - ((_ftmIn * mintingFee) / PRECISION);
    }

    /// @notice Calculate the expected results for redemption
    /// @param _xftmIn Amount of XFTM input.
    /// @return _ftmOut : the amount of FTM output.
    /// @return _fantasmOut : the amount of Fantasm output by swapping
    /// @return _ftmFee : the fee amount in FTM
    /// @return _requiredFtmBalance : required FTM balance in the pool
    function calcRedeem(uint256 _xftmIn)
        public
        view
        returns (
            uint256 _ftmOut,
            uint256 _fantasmOut,
            uint256 _ftmFee,
            uint256 _requiredFtmBalance
        )
    {
        uint256 _fantasmPrice = oracle.getFantasmPrice();
        require(_fantasmPrice > 0, "Pool::calcRedeem: Invalid Fantasm price");

        _requiredFtmBalance = (_xftmIn * collateralRatio) / PRECISION;
        if (collateralRatio < COLLATERAL_RATIO_MAX) {
            _fantasmOut = (_xftmIn * (COLLATERAL_RATIO_MAX - collateralRatio) * (PRECISION - redemptionFee) * PRICE_PRECISION) / COLLATERAL_RATIO_MAX / PRECISION / _fantasmPrice;
        }

        if (collateralRatio > 0) {
            _ftmOut = (_xftmIn * collateralRatio * (PRECISION - redemptionFee)) / COLLATERAL_RATIO_MAX / PRECISION;
            _ftmFee = (_xftmIn * collateralRatio * redemptionFee) / COLLATERAL_RATIO_MAX / PRECISION;
        }
    }

    /// @notice Calculate the expected results for minting
    function calcExcessFtmBalance() public view returns (uint256 _delta, bool _exceeded) {
        uint256 _requiredFtmBal = (xftm.totalSupply() * collateralRatio) / COLLATERAL_RATIO_MAX;
        uint256 _usableFtmBal = usableFtmBalance();
        if (_usableFtmBal >= _requiredFtmBal) {
            _delta = _usableFtmBal - _requiredFtmBal;
            _exceeded = true;
        } else {
            _delta = _requiredFtmBal - _usableFtmBal;
            _exceeded = false;
        }
    }

    /* ========== PUBLIC FUNCTIONS ========== */

    /// @notice Update collateral ratio and adjust based on the TWAP price of XFTM
    function refreshCollateralRatio() public {
        require(collateralRatioPaused == false, "Pool::refreshCollateralRatio: Collateral Ratio has been paused");
        require(block.timestamp - lastRefreshCrTimestamp >= refreshCooldown, "Pool::refreshCollateralRatio: Must wait for the refresh cooldown since last refresh");

        uint256 _xftmPrice = oracle.getXftmTWAP();
        if (_xftmPrice > priceTarget + priceBand) {
            if (collateralRatio <= ratioStepDown) {
                collateralRatio = 0;
            } else {
                uint256 _newCR = collateralRatio - ratioStepDown;
                if (_newCR <= minCollateralRatio) {
                    collateralRatio = minCollateralRatio;
                } else {
                    collateralRatio = _newCR;
                }
            }
        } else if (_xftmPrice < priceTarget - priceBand) {
            if (collateralRatio + ratioStepUp >= COLLATERAL_RATIO_MAX) {
                collateralRatio = COLLATERAL_RATIO_MAX;
            } else {
                collateralRatio = collateralRatio + ratioStepUp;
            }
        }

        lastRefreshCrTimestamp = block.timestamp;
        emit NewCollateralRatioSet(collateralRatio);
    }

    /// @notice fallback for payable -> required to unwrap WETH
    receive() external payable {}

    /* ========== MUTATIVE FUNCTIONS ========== */

    function mint(uint256 _fantasmIn, uint256 _minXftmOut) external payable nonReentrant {
        require(!mintPaused, "Pool::mint: Minting is paused");
        uint256 _ftmIn = msg.value;
        address _minter = msg.sender;

        (uint256 _xftmOut, , uint256 _minFantasmIn, uint256 _ftmFee) = calcMint(_ftmIn, _fantasmIn);
        require(_minXftmOut <= _xftmOut, "Pool::mint: slippage");
        require(_minFantasmIn <= _fantasmIn, "Pool::mint: Not enough Fantasm input");
        require(maxXftmSupply >= xftm.totalSupply() + _xftmOut, "Pool::mint: > Xftm supply limit");

        WethUtils.wrap(_ftmIn);
        userInfo[_minter].lastAction = block.number;

        if (_xftmOut > 0) {
            userInfo[_minter].xftmBalance = userInfo[_minter].xftmBalance + _xftmOut;
            unclaimedXftm = unclaimedXftm + _xftmOut;
        }

        if (_minFantasmIn > 0) {
            fantasm.safeTransferFrom(_minter, address(this), _minFantasmIn);
            fantasm.burn(_minFantasmIn);
        }

        if (_ftmFee > 0) {
            WethUtils.transfer(feeReserve, _ftmFee);
        }

        emit Mint(_minter, _xftmOut, _ftmIn, _fantasmIn, _ftmFee);
    }

    function zap(uint256 _minXftmOut) external payable nonReentrant {
        require(!mintPaused, "Pool::zap: Minting is paused");
        uint256 _ftmIn = msg.value;
        address _sender = msg.sender;

        (uint256 _xftmOut, uint256 _fantasmOut, uint256 _fee, uint256 _ftmSwapIn) = calcZapMint(_ftmIn);
        require(_xftmOut >= _minXftmOut, "Pool::zap: slippage");

        WethUtils.wrap(_ftmIn);
        if (_fantasmOut > 0 && _ftmSwapIn > 0) {
            uint256 _fantasmReceived = swap(_ftmSwapIn, _fantasmOut);
            fantasm.burn(_fantasmReceived);
        }

        if (_xftmOut > 0) {
            userInfo[_sender].xftmBalance = userInfo[_sender].xftmBalance + _xftmOut;
            unclaimedXftm = unclaimedXftm + _xftmOut;
        }

        if (_fee > 0) {
            WethUtils.transfer(feeReserve, _fee);
        }

        emit ZapMint(_sender, _xftmOut, _ftmIn, _fee);
    }

    function redeem(
        uint256 _xftmIn,
        uint256 _minFantasmOut,
        uint256 _minFtmOut
    ) external nonReentrant {
        require(!redeemPaused, "Pool::redeem: Redeeming is paused");

        address _sender = msg.sender;
        (uint256 _ftmOut, uint256 _fantasmOut, uint256 _fee, uint256 _requiredFtmBalance) = calcRedeem(_xftmIn);

        // Check if collateral balance meets and meet output expectation
        require(_requiredFtmBalance <= usableFtmBalance(), "Pool::redeem: > FTM balance");
        require(_minFtmOut <= _ftmOut && _minFantasmOut <= _fantasmOut, "Pool::redeem: >slippage");

        if (_ftmOut > 0) {
            userInfo[_sender].ftmBalance = userInfo[_sender].ftmBalance + _ftmOut;
            unclaimedFtm = unclaimedFtm + _ftmOut;
        }

        if (_fantasmOut > 0) {
            userInfo[_sender].fantasmBalance = userInfo[_sender].fantasmBalance + _fantasmOut;
            unclaimedFantasm = unclaimedFantasm + _fantasmOut;
        }

        userInfo[_sender].lastAction = block.number;

        // Move all external functions to the end
        IXftm(xftm).burn(_sender, _xftmIn);
        if (_fee > 0) {
            WethUtils.transfer(feeReserve, _fee);
        }

        emit Redeem(_sender, _xftmIn, _ftmOut, _fantasmOut, _fee);
    }

    /**
     * @notice collect all minting and redemption
     */
    function collect() external nonReentrant {
        address _sender = msg.sender;
        require(userInfo[_sender].lastAction < block.number, "Pool::collect: <minimum_delay");

        bool _sendXftm = false;
        bool _sendFantasm = false;
        bool _sendFtm = false;
        uint256 _xftmAmount;
        uint256 _fantasmAmount;
        uint256 _ftmAmount;

        // Use Checks-Effects-Interactions pattern
        if (userInfo[_sender].xftmBalance > 0) {
            _xftmAmount = userInfo[_sender].xftmBalance;
            userInfo[_sender].xftmBalance = 0;
            unclaimedXftm = unclaimedXftm - _xftmAmount;
            _sendXftm = true;
        }

        if (userInfo[_sender].fantasmBalance > 0) {
            _fantasmAmount = userInfo[_sender].fantasmBalance;
            userInfo[_sender].fantasmBalance = 0;
            unclaimedFantasm = unclaimedFantasm - _fantasmAmount;
            _sendFantasm = true;
        }

        if (userInfo[_sender].ftmBalance > 0) {
            _ftmAmount = userInfo[_sender].ftmBalance;
            userInfo[_sender].ftmBalance = 0;
            unclaimedFtm = unclaimedFtm - _ftmAmount;
            _sendFtm = true;
        }

        if (_sendXftm) {
            xftm.mint(_sender, _xftmAmount);
        }

        if (_sendFantasm) {
            fantasm.mint(_sender, _fantasmAmount);
        }

        if (_sendFtm) {
            WethUtils.unwrap(_ftmAmount);
            payable(_sender).transfer(_ftmAmount);
        }
    }

    /// @notice Function to recollateralize the pool by receiving WFTM
    /// @param _amount Amount of WFTM input
    function recollateralize(uint256 _amount) external {
        require(_amount > 0, "Pool::recollateralize: Invalid amount");
        WethUtils.weth.safeTransferFrom(msg.sender, address(this), _amount);
        emit Recollateralized(msg.sender, _amount);
    }

    /// @notice Function to recollateralize the pool by receiving FTM
    function recollateralizeETH() external payable {
        uint256 _amount = msg.value;
        require(_amount > 0, "Pool::recollateralize: Invalid amount");
        WethUtils.wrap(_amount);
        emit Recollateralized(msg.sender, _amount);
    }

    /* ========== INTERNAL FUNCTIONS ============ */

    /// @notice Function to take input FTM to swap to FSM and burn
    /// @param _ftmIn Amount of FTM input
    /// @param _fantasmOut Amount of FSM output expected
    function swap(uint256 _ftmIn, uint256 _fantasmOut) internal returns (uint256 _fsmOut) {
        uint256 _minFantasmOut = (_fantasmOut * (SLIPPAGE_PRECISION - swapSlippage)) / SLIPPAGE_PRECISION;
        WethUtils.weth.safeIncreaseAllowance(address(swapRouter), _ftmIn);
        uint256 _fsmBefore = fantasm.balanceOf(address(this));
        swapRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(_ftmIn, _minFantasmOut, swapPaths, address(this), block.timestamp + SWAP_TIMEOUT);
        _fsmOut = fantasm.balanceOf(address(this)) - _fsmBefore;
    }

    /* ========== RESTRICTED FUNCTIONS ========== */

    /// @notice Turn on / off minting and redemption
    /// @param _mintPaused Paused or NotPaused Minting
    /// @param _redeemPaused Paused or NotPaused Redemption
    function toggle(bool _mintPaused, bool _redeemPaused) public onlyOwner {
        mintPaused = _mintPaused;
        redeemPaused = _redeemPaused;
        emit Toggled(_mintPaused, _redeemPaused);
    }

    /// @notice Configure variables related to Collateral Ratio
    /// @param _ratioStepUp Step which Collateral Ratio will be increased each updates
    /// @param _ratioStepDown Step which Collateral Ratio will be decreased each updates
    /// @param _priceBand The collateral ratio will only be adjusted if current price move out of this band
    /// @param _refreshCooldown The minimum delay between each Collateral Ratio updates
    function setCollateralRatioOptions(
        uint256 _ratioStepUp,
        uint256 _ratioStepDown,
        uint256 _priceBand,
        uint256 _refreshCooldown
    ) public onlyOwner {
        ratioStepUp = _ratioStepUp;
        ratioStepDown = _ratioStepDown;
        priceBand = _priceBand;
        refreshCooldown = _refreshCooldown;
        emit NewCollateralRatioOptions(_ratioStepUp, _ratioStepDown, _priceBand, _refreshCooldown);
    }

    /// @notice Pause or unpause collateral ratio updates
    /// @param _collateralRatioPaused `true` or `false`
    function toggleCollateralRatio(bool _collateralRatioPaused) public onlyOwner {
        if (collateralRatioPaused != _collateralRatioPaused) {
            collateralRatioPaused = _collateralRatioPaused;
            emit UpdateCollateralRatioPaused(_collateralRatioPaused);
        }
    }

    /// @notice Set the protocol fees
    /// @param _mintingFee Minting fee in percentage
    /// @param _redemptionFee Redemption fee in percentage
    function setFees(uint256 _mintingFee, uint256 _redemptionFee) public onlyOwner {
        require(_mintingFee <= MINTING_FEE_MAX, "Pool::setFees:>MINTING_FEE_MAX");
        require(_redemptionFee <= REDEMPTION_FEE_MAX, "Pool::setFees:>REDEMPTION_FEE_MAX");
        redemptionFee = _redemptionFee;
        mintingFee = _mintingFee;
        emit FeesUpdated(_mintingFee, _redemptionFee);
    }

    /// @notice Set the minimum Collateral Ratio
    /// @param _minCollateralRatio value of minimum Collateral Ratio in 1e6 precision
    function setMinCollateralRatio(uint256 _minCollateralRatio) external onlyOwner {
        require(_minCollateralRatio <= COLLATERAL_RATIO_MAX, "Pool::setMinCollateralRatio: >COLLATERAL_RATIO_MAX");
        minCollateralRatio = _minCollateralRatio;
        emit MinCollateralRatioUpdated(_minCollateralRatio);
    }

    /// @notice Set the maxium XFTM supply
    /// @param _newValue value of maxium XFTM supply
    function setMaxXftmSupply(uint256 _newValue) external onlyOwner {
        require(_newValue > xftm.totalSupply(), "Pool::setMaxXftmSupply: Cannot smaller than current limit");
        maxXftmSupply = _newValue;
        emit MaxXftmSupplyUpdated(_newValue);
    }

    /// @notice Transfer the excess balance of FTM to FeeReserve
    /// @param _amount amount of FTM to reduce
    function reduceExcessFtm(uint256 _amount) external onlyOwner {
        (uint256 _excessFtmBal, bool exceeded) = calcExcessFtmBalance();
        if (exceeded && _excessFtmBal > 0) {
            require(_amount <= _excessFtmBal, "Pool::reduceExcessFtm: The amount is too large");
            require(address(feeReserve) != address(0), "Pool::reduceExcessFtm: invalid address");
            WethUtils.transfer(address(feeReserve), _amount);
        }
    }

    /// @notice Set the address of FeeReserve
    /// @param _feeReserve address of FeeReserve contract
    function setFeeReserve(address _feeReserve) external {
        require(feeReserve == address(0), "Pool::setFeeReserve: not allowed");
        feeReserve = _feeReserve;
    }

    /// @notice Set new oracle address
    /// @param _oracle address of the oracle
    function setOracle(IMasterOracle _oracle) external onlyOwner {
        require(address(_oracle) != address(0), "Pool::setOracle: invalid address");
        oracle = _oracle;
        emit OracleChanged(address(_oracle));
    }

    /// @notice Config poolHelper parameters
    /// @param _swapRouter Address of DEX router
    /// @param _swapSlippage slippage
    /// @param _swapPaths paths to swap
    function configSwap(
        IUniswapV2Router02 _swapRouter,
        uint256 _swapSlippage,
        address[] memory _swapPaths
    ) external onlyOwner {
        swapRouter = _swapRouter;
        swapSlippage = _swapSlippage;
        swapPaths = _swapPaths;
        emit SwapConfigUpdated(address(_swapRouter), _swapSlippage, _swapPaths);
    }

    // EVENTS
    event OracleChanged(address indexed _oracle);
    event Toggled(bool _mintPaused, bool _redeemPaused);
    event Mint(address minter, uint256 amount, uint256 ftmIn, uint256 fantasmIn, uint256 fee);
    event ZapMint(address minter, uint256 amount, uint256 ftmIn, uint256 fee);
    event Redeem(address redeemer, uint256 amount, uint256 ftmOut, uint256 fantasmOut, uint256 fee);
    event PoolUtilsChanged(address indexed _addr);
    event SwapConfigUpdated(address indexed _router, uint256 _slippage, address[] _paths);
    event UpdateCollateralRatioPaused(bool _collateralRatioPaused);
    event NewCollateralRatioOptions(uint256 _ratioStepUp, uint256 _ratioStepDown, uint256 _priceBand, uint256 _refreshCooldown);
    event MinCollateralRatioUpdated(uint256 _minCollateralRatio);
    event NewCollateralRatioSet(uint256 _cr);
    event FeesUpdated(uint256 _mintingFee, uint256 _redemptionFee);
    event MaxXftmSupplyUpdated(uint256 _value);
    event Recollateralized(address indexed _sender, uint256 _amount);
}

File 12 of 16 : IFantasm.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.4;

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

interface IFantasm is IERC20 {
    function mint(address _address, uint256 _amount) external;

    function burn(uint256 _amount) external;

    function setRewarder(address _rewarder) external returns (bool);

    function setTreasuryFund(address _rewarder)
        external
        returns (
            uint256 _allocation,
            uint256 _vestingDuration,
            uint256 _vestingStart
        );

    function setDevFund(address _rewarder)
        external
        returns (
            uint256 _allocation,
            uint256 _vestingDuration,
            uint256 _vestingStart
        );

    function setPool(address _pool) external returns (bool);
}

File 13 of 16 : IMasterOracle.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.4;

interface IMasterOracle {
    function getFantasmPrice() external view returns (uint256);

    function getFantasmTWAP() external view returns (uint256);

    function getXftmTWAP() external view returns (uint256);
}

File 14 of 16 : IWETH.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.4;

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

interface IWETH is IERC20 {
    function deposit() external payable;

    function withdraw(uint256 wad) external;
}

File 15 of 16 : IXftm.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.4;

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

interface IXftm is IERC20 {
    function burn(address _address, uint256 _amount) external;

    function burn(uint256 _amount) external;

    function mint(address _address, uint256 _amount) external;

    function setMinter(address _minter) external;
}

File 16 of 16 : WethUtils.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.4;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../interfaces/IWETH.sol";

library WethUtils {
    using SafeERC20 for IWETH;

    // unit test only
    // IWETH public constant weth = IWETH(0x77eb900076Cf04865f3491f47e18024C01ac0ae7);
    IWETH public constant weth = IWETH(0x21be370D5312f44cB42ce377BC9b8a0cEF1A4C83);

    function isWeth(address token) internal pure returns (bool) {
        return address(weth) == token;
    }

    function wrap(uint256 amount) internal {
        weth.deposit{value: amount}();
    }

    function unwrap(uint256 amount) internal {
        weth.withdraw(amount);
    }

    function transfer(address to, uint256 amount) internal {
        weth.safeTransfer(to, amount);
    }
}

Settings
{
  "evmVersion": "istanbul",
  "libraries": {
    "contracts/Pool.sol:Pool": {
      "WethUtils": "0xeFFD5efaCe491c15C126e1430106257197B02F0A"
    }
  },
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": [],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_xftm","type":"address"},{"internalType":"address","name":"_fantasm","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_mintingFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_redemptionFee","type":"uint256"}],"name":"FeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"MaxXftmSupplyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_minCollateralRatio","type":"uint256"}],"name":"MinCollateralRatioUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ftmIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fantasmIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_ratioStepUp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_ratioStepDown","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_priceBand","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_refreshCooldown","type":"uint256"}],"name":"NewCollateralRatioOptions","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_cr","type":"uint256"}],"name":"NewCollateralRatioSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_oracle","type":"address"}],"name":"OracleChanged","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":"address","name":"_addr","type":"address"}],"name":"PoolUtilsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Recollateralized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ftmOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fantasmOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_router","type":"address"},{"indexed":false,"internalType":"uint256","name":"_slippage","type":"uint256"},{"indexed":false,"internalType":"address[]","name":"_paths","type":"address[]"}],"name":"SwapConfigUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"_mintPaused","type":"bool"},{"indexed":false,"internalType":"bool","name":"_redeemPaused","type":"bool"}],"name":"Toggled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"_collateralRatioPaused","type":"bool"}],"name":"UpdateCollateralRatioPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ftmIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"ZapMint","type":"event"},{"inputs":[],"name":"MINTING_FEE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REDEMPTION_FEE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"calcExcessFtmBalance","outputs":[{"internalType":"uint256","name":"_delta","type":"uint256"},{"internalType":"bool","name":"_exceeded","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ftmIn","type":"uint256"},{"internalType":"uint256","name":"_fantasmIn","type":"uint256"}],"name":"calcMint","outputs":[{"internalType":"uint256","name":"_xftmOut","type":"uint256"},{"internalType":"uint256","name":"_minFtmIn","type":"uint256"},{"internalType":"uint256","name":"_minFantasmIn","type":"uint256"},{"internalType":"uint256","name":"_fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_xftmIn","type":"uint256"}],"name":"calcRedeem","outputs":[{"internalType":"uint256","name":"_ftmOut","type":"uint256"},{"internalType":"uint256","name":"_fantasmOut","type":"uint256"},{"internalType":"uint256","name":"_ftmFee","type":"uint256"},{"internalType":"uint256","name":"_requiredFtmBalance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ftmIn","type":"uint256"}],"name":"calcZapMint","outputs":[{"internalType":"uint256","name":"_xftmOut","type":"uint256"},{"internalType":"uint256","name":"_fantasmOut","type":"uint256"},{"internalType":"uint256","name":"_ftmFee","type":"uint256"},{"internalType":"uint256","name":"_ftmSwapIn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateralRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateralRatioPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collect","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IUniswapV2Router02","name":"_swapRouter","type":"address"},{"internalType":"uint256","name":"_swapSlippage","type":"uint256"},{"internalType":"address[]","name":"_swapPaths","type":"address[]"}],"name":"configSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fantasm","outputs":[{"internalType":"contract IFantasm","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeReserve","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"info","outputs":[{"internalType":"uint256","name":"_collateralRatio","type":"uint256"},{"internalType":"uint256","name":"_lastRefreshCrTimestamp","type":"uint256"},{"internalType":"uint256","name":"_mintingFee","type":"uint256"},{"internalType":"uint256","name":"_redemptionFee","type":"uint256"},{"internalType":"bool","name":"_mintingPaused","type":"bool"},{"internalType":"bool","name":"_redemptionPaused","type":"bool"},{"internalType":"uint256","name":"_collateralBalance","type":"uint256"},{"internalType":"uint256","name":"_maxXftmSupply","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastRefreshCrTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxXftmSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minCollateralRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fantasmIn","type":"uint256"},{"internalType":"uint256","name":"_minXftmOut","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mintPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintingFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"contract IMasterOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceBand","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceTarget","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ratioStepDown","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ratioStepUp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"recollateralize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"recollateralizeETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_xftmIn","type":"uint256"},{"internalType":"uint256","name":"_minFantasmOut","type":"uint256"},{"internalType":"uint256","name":"_minFtmOut","type":"uint256"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redeemPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"redemptionFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"reduceExcessFtm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"refreshCollateralRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"refreshCooldown","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ratioStepUp","type":"uint256"},{"internalType":"uint256","name":"_ratioStepDown","type":"uint256"},{"internalType":"uint256","name":"_priceBand","type":"uint256"},{"internalType":"uint256","name":"_refreshCooldown","type":"uint256"}],"name":"setCollateralRatioOptions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeReserve","type":"address"}],"name":"setFeeReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_mintingFee","type":"uint256"},{"internalType":"uint256","name":"_redemptionFee","type":"uint256"}],"name":"setFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newValue","type":"uint256"}],"name":"setMaxXftmSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minCollateralRatio","type":"uint256"}],"name":"setMinCollateralRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IMasterOracle","name":"_oracle","type":"address"}],"name":"setOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"swapPaths","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapRouter","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapSlippage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_mintPaused","type":"bool"},{"internalType":"bool","name":"_redeemPaused","type":"bool"}],"name":"toggle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_collateralRatioPaused","type":"bool"}],"name":"toggleCollateralRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unclaimedFantasm","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unclaimedFtm","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unclaimedXftm","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usableFtmBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userInfo","outputs":[{"internalType":"uint256","name":"xftmBalance","type":"uint256"},{"internalType":"uint256","name":"fantasmBalance","type":"uint256"},{"internalType":"uint256","name":"ftmBalance","type":"uint256"},{"internalType":"uint256","name":"lastAction","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"xftm","outputs":[{"internalType":"contract IXftm","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minXftmOut","type":"uint256"}],"name":"zap","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]

6080604052600a805461ffff191690556a52b7d2dcc80cd2e4000000600b55620f4240600c819055610e10600e556107d0600f556103e8601055670de0b6b3a76400006011556611c37937e080006012556013556014805460ff19169055611388601555610bb86016553480156200007657600080fd5b506040516200392f3803806200392f8339810160408190526200009991620002b2565b620000a43362000245565b600180556001600160a01b038216620000f35760405162461bcd60e51b815260206004820181905260248201526000805160206200390f83398151915260448201526064015b60405180910390fd5b6001600160a01b0381166200013a5760405162461bcd60e51b815260206004820181905260248201526000805160206200390f8339815191526044820152606401620000ea565b600380546001600160a01b038481166001600160a01b031992831681179093556004805491851691909216178155604051637e51dad560e11b8152309181019190915263fca3b5aa90602401600060405180830381600087803b158015620001a157600080fd5b505af1158015620001b6573d6000803e3d6000fd5b50506004805460405163221b8a9560e11b815230928101929092526001600160a01b03169250634437152a9150602401602060405180830381600087803b1580156200020157600080fd5b505af115801562000216573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200023c9190620002e9565b50505062000312565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114620002ad57600080fd5b919050565b60008060408385031215620002c5578182fd5b620002d08362000295565b9150620002e06020840162000295565b90509250929050565b600060208284031215620002fb578081fd5b815180151581146200030b578182fd5b9392505050565b6135ed80620003226000396000f3fe60806040526004361061031e5760003560e01c806380fe2b75116101ab578063b6168acf116100f7578063daf69e3011610095578063ea5f7abe1161006f578063ea5f7abe14610904578063ed21b9751461091a578063f2fde38b1461093a578063f8c321241461095a57600080fd5b8063daf69e30146108b9578063df0c71dc146108cf578063e5225381146108ef57600080fd5b8063c31c9c07116100d1578063c31c9c0714610844578063d5d0cb1614610864578063d744209314610884578063d8ceb6c6146108a457600080fd5b8063b6168acf146107e4578063b819220514610804578063c29118fc1461082457600080fd5b8063972cea6811610164578063a8508d3e1161013e578063a8508d3e14610779578063adcc2c741461078f578063b235d468146107af578063b4eae1cb146107ce57600080fd5b8063972cea68146107305780639f1bf63e14610750578063a1a1c8041461076657600080fd5b806380fe2b751461069a57806384da2666146106b0578063868a2724146106c65780638da5cb5b146106dc57806391012f9d146106fa578063932435091461071057600080fd5b80634013124a1161026a578063715018a6116102235780637a991b6d116101fd5780637a991b6d146106165780637adbf973146106405780637dc0d1d0146106605780637e4831d31461068057600080fd5b8063715018a6146105c157806373b82edd146105d6578063789ff0e1146105f657600080fd5b80634013124a1461054c578063458f5815146105615780634bfe4a57146105775780634ec839bb1461058d5780634efc25d6146105955780635a64ad95146105ab57600080fd5b806329491813116102d75780633430d7a1116102b15780633430d7a114610498578063370158ea146104b8578063385362751461050c57806339e324f01461052c57600080fd5b8063294918131461042a5780633251b36b1461044a57806333b3c8b81461048257600080fd5b80630b68acac1461032a5780630b78f9c0146103535780630fcd5809146103755780631959a0021461039f5780631aedeabe146104015780631b2ef1ca1461041757600080fd5b3661032557005b600080fd5b34801561033657600080fd5b50610340600f5481565b6040519081526020015b60405180910390f35b34801561035f57600080fd5b5061037361036e366004613288565b610970565b005b34801561038157600080fd5b5061038a610a99565b6040805192835290151560208301520161034a565b3480156103ab57600080fd5b506103e16103ba3660046130e7565b60066020526000908152604090208054600182015460028301546003909301549192909184565b60408051948552602085019390935291830152606082015260800161034a565b34801561040d57600080fd5b5061034060195481565b610373610425366004613288565b610b80565b34801561043657600080fd5b50610373610445366004613258565b610f06565b34801561045657600080fd5b5060035461046a906001600160a01b031681565b6040516001600160a01b03909116815260200161034a565b34801561048e57600080fd5b5061034060085481565b3480156104a457600080fd5b506103736104b3366004613258565b610f7e565b3480156104c457600080fd5b506104cd6110de565b60408051988952602089019790975295870194909452606086019290925215156080850152151560a084015260c083015260e08201526101000161034a565b34801561051857600080fd5b50610373610527366004613258565b611115565b34801561053857600080fd5b50610373610547366004613173565b6111e2565b34801561055857600080fd5b50610373611288565b34801561056d57600080fd5b5061034060155481565b34801561058357600080fd5b5061034061232881565b610373611507565b3480156105a157600080fd5b5061034060095481565b3480156105b757600080fd5b5061034060165481565b3480156105cd57600080fd5b5061037361152e565b3480156105e257600080fd5b506103736105f13660046132d4565b611564565b34801561060257600080fd5b5060055461046a906001600160a01b031681565b34801561062257600080fd5b506014546106309060ff1681565b604051901515815260200161034a565b34801561064c57600080fd5b5061037361065b3660046130e7565b6115f0565b34801561066c57600080fd5b5060025461046a906001600160a01b031681565b34801561068c57600080fd5b50600a546106309060ff1681565b3480156106a657600080fd5b5061034060105481565b3480156106bc57600080fd5b5061034060135481565b3480156106d257600080fd5b50610340600d5481565b3480156106e857600080fd5b506000546001600160a01b031661046a565b34801561070657600080fd5b5061034060075481565b34801561071c57600080fd5b5061046a61072b366004613258565b6116ba565b34801561073c57600080fd5b506103e161074b366004613258565b6116e4565b34801561075c57600080fd5b5061034060125481565b610373610774366004613258565b611885565b34801561078557600080fd5b5061034060115481565b34801561079b57600080fd5b506103e16107aa366004613288565b611aaf565b3480156107bb57600080fd5b50600a5461063090610100900460ff1681565b3480156107da57600080fd5b50610340600c5481565b3480156107f057600080fd5b506103736107ff3660046130e7565b611d9c565b34801561081057600080fd5b5061037361081f3660046132a9565b611e17565b34801561083057600080fd5b5061037361083f36600461313b565b612123565b34801561085057600080fd5b5060175461046a906001600160a01b031681565b34801561087057600080fd5b5061037361087f366004613103565b6121a9565b34801561089057600080fd5b5061037361089f366004613258565b612227565b3480156108b057600080fd5b5061034061235b565b3480156108c557600080fd5b50610340600b5481565b3480156108db57600080fd5b5060045461046a906001600160a01b031681565b3480156108fb57600080fd5b50610373612407565b34801561091057600080fd5b50610340600e5481565b34801561092657600080fd5b506103e1610935366004613258565b6126d0565b34801561094657600080fd5b506103736109553660046130e7565b6128e4565b34801561096657600080fd5b5061034061138881565b6000546001600160a01b031633146109a35760405162461bcd60e51b815260040161099a90613354565b60405180910390fd5b6113888211156109f55760405162461bcd60e51b815260206004820152601e60248201527f506f6f6c3a3a736574466565733a3e4d494e54494e475f4645455f4d41580000604482015260640161099a565b612328811115610a515760405162461bcd60e51b815260206004820152602160248201527f506f6f6c3a3a736574466565733a3e524544454d5054494f4e5f4645455f4d416044820152600b60fb1b606482015260840161099a565b6015819055601682905560408051838152602081018390527f5c6323bf1c2d7aaea2c091a4751c1c87af7f2864650c336507a77d0557af37a191015b60405180910390a15050565b6000806000620f4240600c54600360009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610af357600080fd5b505afa158015610b07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2b9190613270565b610b359190613506565b610b3f91906134e6565b90506000610b4b61235b565b9050818110610b6957610b5e8282613525565b935060019250610b7a565b610b738183613525565b9350600092505b50509091565b60026001541415610ba35760405162461bcd60e51b815260040161099a906133ce565b6002600155600a5460ff1615610bfb5760405162461bcd60e51b815260206004820152601d60248201527f506f6f6c3a3a6d696e743a204d696e74696e6720697320706175736564000000604482015260640161099a565b343360008080610c0b8588611aaf565b9350935050925082861115610c595760405162461bcd60e51b8152602060048201526014602482015273506f6f6c3a3a6d696e743a20736c69707061676560601b604482015260640161099a565b86821115610cb55760405162461bcd60e51b8152602060048201526024808201527f506f6f6c3a3a6d696e743a204e6f7420656e6f7567682046616e7461736d20696044820152631b9c1d5d60e21b606482015260840161099a565b600354604080516318160ddd60e01b8152905185926001600160a01b0316916318160ddd916004808301926020929190829003018186803b158015610cf957600080fd5b505afa158015610d0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d319190613270565b610d3b91906134ce565b600b541015610d8c5760405162461bcd60e51b815260206004820152601f60248201527f506f6f6c3a3a6d696e743a203e205866746d20737570706c79206c696d697400604482015260640161099a565b610d958561297c565b6001600160a01b0384166000908152600660205260409020436003909101558215610e09576001600160a01b038416600090815260066020526040902054610dde9084906134ce565b6001600160a01b038516600090815260066020526040902055600854610e059084906134ce565b6008555b8115610e8457600454610e27906001600160a01b03168530856129e7565b60048054604051630852cd8d60e31b81529182018490526001600160a01b0316906342966c6890602401600060405180830381600087803b158015610e6b57600080fd5b505af1158015610e7f573d6000803e3d6000fd5b505050505b8015610ea057600554610ea0906001600160a01b031682612a58565b604080516001600160a01b03861681526020810185905290810186905260608101889052608081018290527f94c792774c59479f7bd68442f3af3691c02123a5aabee8b6f9116d8af8aa66699060a0015b60405180910390a15050600180555050505050565b60008111610f265760405162461bcd60e51b815260040161099a90613389565b610f467321be370d5312f44cb42ce377bc9b8a0cef1a4c833330846129e7565b60405181815233907fbcce792384bcc41455f8efeface08ee7880d3a4264ada39bb979554fd5985d609060200160405180910390a250565b6000546001600160a01b03163314610fa85760405162461bcd60e51b815260040161099a90613354565b600360009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610ff657600080fd5b505afa15801561100a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061102e9190613270565b81116110a25760405162461bcd60e51b815260206004820152603960248201527f506f6f6c3a3a7365744d61785866746d537570706c793a2043616e6e6f74207360448201527f6d616c6c6572207468616e2063757272656e74206c696d697400000000000000606482015260840161099a565b600b8190556040518181527f74142966a2c6374108627a1e4ccaecc19f0f2d724a4c76859b0c1d8a35b2001c906020015b60405180910390a150565b600c54600d54601654601554600a5460ff8082169161010090041660008061110461235b565b9150600b5490509091929394959697565b6000546001600160a01b0316331461113f5760405162461bcd60e51b815260040161099a90613354565b620f42408111156111ad5760405162461bcd60e51b815260206004820152603260248201527f506f6f6c3a3a7365744d696e436f6c6c61746572616c526174696f3a203e434f6044820152710989882a88aa48298bea482a8929ebe9a82b60731b606482015260840161099a565b60138190556040518181527f5982e574cb778844329684a34107b512e3a2413a153fc02af924390158148c6f906020016110d3565b6000546001600160a01b0316331461120c5760405162461bcd60e51b815260040161099a90613354565b601780546001600160a01b0319166001600160a01b0385161790556019829055805161123f90601890602084019061305d565b50826001600160a01b03167f47cae1783a0815d8c4b5b54c623301f48699effcf061c5f1ed8d3238b4f5acd7838360405161127b929190613405565b60405180910390a2505050565b60145460ff16156113015760405162461bcd60e51b815260206004820152603e60248201527f506f6f6c3a3a72656672657368436f6c6c61746572616c526174696f3a20436f60448201527f6c6c61746572616c20526174696f20686173206265656e207061757365640000606482015260840161099a565b600e54600d546113119042613525565b10156113a15760405162461bcd60e51b815260206004820152605360248201527f506f6f6c3a3a72656672657368436f6c6c61746572616c526174696f3a204d7560448201527f7374207761697420666f7220746865207265667265736820636f6f6c646f776e606482015272040e6d2dcc6ca40d8c2e6e840e4cacce4cae6d606b1b608482015260a40161099a565b60025460408051630c3adc7360e41b815290516000926001600160a01b03169163c3adc730916004808301926020929190829003018186803b1580156113e657600080fd5b505afa1580156113fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141e9190613270565b905060125460115461143091906134ce565b81111561148057601054600c541161144c576000600c556114d0565b6000601054600c5461145e9190613525565b9050601354811161147457601354600c5561147a565b600c8190555b506114d0565b6012546011546114909190613525565b8110156114d057620f4240600f54600c546114ab91906134ce565b106114bc57620f4240600c556114d0565b600f54600c546114cc91906134ce565b600c555b42600d55600c546040519081527f43dd06cd14239ec6c5a1b4ea9c2def7d8940aeda88ead0ab6fb960ce3c3c412d906020016110d3565b34806115255760405162461bcd60e51b815260040161099a90613389565b610f468161297c565b6000546001600160a01b031633146115585760405162461bcd60e51b815260040161099a90613354565b6115626000612a7b565b565b6000546001600160a01b0316331461158e5760405162461bcd60e51b815260040161099a90613354565b600f84905560108390556012829055600e8190556040805185815260208101859052908101839052606081018290527f038f57571f57da47bfdd27bbcac94efe4d37d76fc9711fbeb5e68e75bc8243049060800160405180910390a150505050565b6000546001600160a01b0316331461161a5760405162461bcd60e51b815260040161099a90613354565b6001600160a01b0381166116705760405162461bcd60e51b815260206004820181905260248201527f506f6f6c3a3a7365744f7261636c653a20696e76616c69642061646472657373604482015260640161099a565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f0e05ae75e8b926552cf6fcd744d19f422561e3ced1e426868730852702dbe41890600090a250565b601881815481106116ca57600080fd5b6000918252602090912001546001600160a01b0316905081565b6000806000806000600260009054906101000a90046001600160a01b03166001600160a01b0316636280ac766040518163ffffffff1660e01b815260040160206040518083038186803b15801561173a57600080fd5b505afa15801561174e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117729190613270565b9050600081116117d55760405162461bcd60e51b815260206004820152602860248201527f506f6f6c3a3a63616c635a61704d696e743a20496e76616c69642046616e7461604482015267736d20707269636560c01b606482015260840161099a565b620f4240600c54620f42406117ea9190613525565b6117f49088613506565b6117fe91906134e6565b915080611813670de0b6b3a764000084613506565b61181d91906134e6565b9350620f424080600c54601654896118359190613506565b61183f9190613506565b61184991906134e6565b61185391906134e6565b9250620f4240601654876118679190613506565b61187191906134e6565b61187b9087613525565b9450509193509193565b600260015414156118a85760405162461bcd60e51b815260040161099a906133ce565b6002600155600a5460ff16156119005760405162461bcd60e51b815260206004820152601c60248201527f506f6f6c3a3a7a61703a204d696e74696e672069732070617573656400000000604482015260640161099a565b34336000808080611910866116e4565b93509350935093508684101561195e5760405162461bcd60e51b8152602060048201526013602482015272506f6f6c3a3a7a61703a20736c69707061676560681b604482015260640161099a565b6119678661297c565b6000831180156119775750600081115b156119f05760006119888285612acb565b60048054604051630852cd8d60e31b81529293506001600160a01b0316916342966c68916119bc9185910190815260200190565b600060405180830381600087803b1580156119d657600080fd5b505af11580156119ea573d6000803e3d6000fd5b50505050505b8315611a45576001600160a01b038516600090815260066020526040902054611a1a9085906134ce565b6001600160a01b038616600090815260066020526040902055600854611a419085906134ce565b6008555b8115611a6157600554611a61906001600160a01b031683612a58565b604080516001600160a01b038716815260208101869052908101879052606081018390527fede3b436c0d2101d71fe30d1e5a5325e90ad0986c9b5897b9cd7cbabf4356f1490608001610ef1565b6000806000806000600260009054906101000a90046001600160a01b03166001600160a01b0316636280ac766040518163ffffffff1660e01b815260040160206040518083038186803b158015611b0557600080fd5b505afa158015611b19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3d9190613270565b905060008111611b9d5760405162461bcd60e51b815260206004820152602560248201527f506f6f6c3a3a63616c634d696e743a20496e76616c69642046616e7461736d20604482015264707269636560d81b606482015260840161099a565b620f4240600c541480611bbd57506000600c54118015611bbd5750600087115b15611c7257600c548794508190670de0b6b3a7640000611be082620f4240613525565b611bea908b613506565b611bf49190613506565b611bfe91906134e6565b611c0891906134e6565b9250620f4240600c54601654620f4240611c229190613525565b611c2f620f42408b613506565b611c399190613506565b611c4391906134e6565b611c4d91906134e6565b9450620f424060165488611c619190613506565b611c6b91906134e6565b9150611d92565b859250670de0b6b3a7640000600c54620f4240611c8f9190613525565b620f4240601654620f4240611ca49190613525565b620f4240611cb2868c613506565b611cbc9190613506565b611cc69190613506565b611cd091906134e6565b611cda91906134e6565b611ce491906134e6565b9450670de0b6b3a7640000600c54620f4240611d009190613525565b600c54611d0d848a613506565b611d179190613506565b611d2191906134e6565b611d2b91906134e6565b9350670de0b6b3a7640000600c54620f4240611d479190613525565b620f4240601654600c54858b611d5d9190613506565b611d679190613506565b611d719190613506565b611d7b91906134e6565b611d8591906134e6565b611d8f91906134e6565b91505b5092959194509250565b6005546001600160a01b031615611df55760405162461bcd60e51b815260206004820181905260248201527f506f6f6c3a3a736574466565526573657276653a206e6f7420616c6c6f776564604482015260640161099a565b600580546001600160a01b0319166001600160a01b0392909216919091179055565b60026001541415611e3a5760405162461bcd60e51b815260040161099a906133ce565b6002600155600a54610100900460ff1615611ea15760405162461bcd60e51b815260206004820152602160248201527f506f6f6c3a3a72656465656d3a2052656465656d696e672069732070617573656044820152601960fa1b606482015260840161099a565b336000808080611eb0886126d0565b9350935093509350611ec061235b565b811115611f0f5760405162461bcd60e51b815260206004820152601b60248201527f506f6f6c3a3a72656465656d3a203e2046544d2062616c616e63650000000000604482015260640161099a565b838611158015611f1f5750828711155b611f6b5760405162461bcd60e51b815260206004820152601760248201527f506f6f6c3a3a72656465656d3a203e736c697070616765000000000000000000604482015260640161099a565b8315611fc6576001600160a01b038516600090815260066020526040902060020154611f989085906134ce565b6001600160a01b038616600090815260066020526040902060020155600754611fc29085906134ce565b6007555b8215612021576001600160a01b038516600090815260066020526040902060010154611ff39084906134ce565b6001600160a01b03861660009081526006602052604090206001015560095461201d9084906134ce565b6009555b6001600160a01b038581166000818152600660205260409081902043600391820155549051632770a7eb60e21b81526004810192909252602482018b905290911690639dc29fac90604401600060405180830381600087803b15801561208657600080fd5b505af115801561209a573d6000803e3d6000fd5b5050505060008211156120bd576005546120bd906001600160a01b031683612a58565b604080516001600160a01b0387168152602081018a905290810185905260608101849052608081018390527fe02f6383e19e87c24e0c03e2cd5dbd05156cb29a1b0f3dbca1fa3430e444f63d9060a00160405180910390a1505060018055505050505050565b6000546001600160a01b0316331461214d5760405162461bcd60e51b815260040161099a90613354565b600a8054821515610100810261ff001986151590811661ffff1990941693909317179092556040805191825260208201929092527fe4e2759610fe740b4c8247147491ae3e248b92fb63181dc697aff6faf00f65d79101610a8d565b6000546001600160a01b031633146121d35760405162461bcd60e51b815260040161099a90613354565b60145460ff16151581151514612224576014805460ff19168215159081179091556040519081527fe9b03f52b6ce464fd3d6eec943f0c67d7575005f3b0bbf2fad4ea38b4ed72084906020016110d3565b50565b6000546001600160a01b031633146122515760405162461bcd60e51b815260040161099a90613354565b60008061225c610a99565b9150915080801561226d5750600082115b1561235657818311156122d95760405162461bcd60e51b815260206004820152602e60248201527f506f6f6c3a3a72656475636545786365737346746d3a2054686520616d6f756e60448201526d7420697320746f6f206c6172676560901b606482015260840161099a565b6005546001600160a01b03166123405760405162461bcd60e51b815260206004820152602660248201527f506f6f6c3a3a72656475636545786365737346746d3a20696e76616c6964206160448201526564647265737360d01b606482015260840161099a565b600554612356906001600160a01b031684612a58565b505050565b6040516370a0823160e01b815230600482015260009081907321be370d5312f44cb42ce377bc9b8a0cef1a4c83906370a082319060240160206040518083038186803b1580156123aa57600080fd5b505afa1580156123be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123e29190613270565b905060075481116123f4576000612401565b6007546124019082613525565b91505090565b6002600154141561242a5760405162461bcd60e51b815260040161099a906133ce565b60026001553360008181526006602052604090206003015443116124905760405162461bcd60e51b815260206004820152601d60248201527f506f6f6c3a3a636f6c6c6563743a203c6d696e696d756d5f64656c6179000000604482015260640161099a565b6001600160a01b03811660009081526006602052604081205481908190819081908190156124ee576001600160a01b038716600090815260066020526040812080549190556008549093506124e6908490613525565b600855600195505b6001600160a01b03871660009081526006602052604090206001015415612548576001600160a01b03871660009081526006602052604081206001018054919055600954909250612540908390613525565b600955600194505b6001600160a01b038716600090815260066020526040902060020154156125a057506001600160a01b03861660009081526006602052604081206002018054919055600754612598908290613525565b600755600193505b851561260d576003546040516340c10f1960e01b81526001600160a01b03898116600483015260248201869052909116906340c10f1990604401600060405180830381600087803b1580156125f457600080fd5b505af1158015612608573d6000803e3d6000fd5b505050505b841561267c57600480546040516340c10f1960e01b81526001600160a01b038a811693820193909352602481018590529116906340c10f1990604401600060405180830381600087803b15801561266357600080fd5b505af1158015612677573d6000803e3d6000fd5b505050505b83156126c35761268b81612caf565b6040516001600160a01b0388169082156108fc029083906000818181858888f193505050501580156126c1573d6000803e3d6000fd5b505b5050600180555050505050565b6000806000806000600260009054906101000a90046001600160a01b03166001600160a01b0316636280ac766040518163ffffffff1660e01b815260040160206040518083038186803b15801561272657600080fd5b505afa15801561273a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061275e9190613270565b9050600081116127c05760405162461bcd60e51b815260206004820152602760248201527f506f6f6c3a3a63616c6352656465656d3a20496e76616c69642046616e7461736044820152666d20707269636560c81b606482015260840161099a565b620f4240600c54876127d29190613506565b6127dc91906134e6565b9150620f4240600c54101561285a5780620f424080670de0b6b3a7640000601554620f424061280b9190613525565b600c5461281b90620f4240613525565b612825908c613506565b61282f9190613506565b6128399190613506565b61284391906134e6565b61284d91906134e6565b61285791906134e6565b93505b600c54156128dc57620f424080601554620f42406128789190613525565b600c54612885908a613506565b61288f9190613506565b61289991906134e6565b6128a391906134e6565b9450620f424080601554600c54896128bb9190613506565b6128c59190613506565b6128cf91906134e6565b6128d991906134e6565b92505b509193509193565b6000546001600160a01b0316331461290e5760405162461bcd60e51b815260040161099a90613354565b6001600160a01b0381166129735760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161099a565b61222481612a7b565b7321be370d5312f44cb42ce377bc9b8a0cef1a4c836001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156129cb57600080fd5b505af11580156129df573d6000803e3d6000fd5b505050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052612a529085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612d17565b50505050565b612a777321be370d5312f44cb42ce377bc9b8a0cef1a4c838383612de9565b5050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080620f4240601954620f4240612ae39190613525565b612aed9085613506565b612af791906134e6565b601754909150612b26907321be370d5312f44cb42ce377bc9b8a0cef1a4c83906001600160a01b031686612e19565b600480546040516370a0823160e01b815230928101929092526000916001600160a01b03909116906370a082319060240160206040518083038186803b158015612b6f57600080fd5b505afa158015612b83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ba79190613270565b6017549091506001600160a01b0316635c11d7958684601830612bcc610258426134ce565b6040518663ffffffff1660e01b8152600401612bec95949392919061345b565b600060405180830381600087803b158015612c0657600080fd5b505af1158015612c1a573d6000803e3d6000fd5b5050600480546040516370a0823160e01b815230928101929092528493506001600160a01b031691506370a082319060240160206040518083038186803b158015612c6457600080fd5b505afa158015612c78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9c9190613270565b612ca69190613525565b95945050505050565b604051632e1a7d4d60e01b8152600481018290527321be370d5312f44cb42ce377bc9b8a0cef1a4c8390632e1a7d4d90602401600060405180830381600087803b158015612cfc57600080fd5b505af1158015612d10573d6000803e3d6000fd5b5050505050565b6000612d6c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612eda9092919063ffffffff16565b8051909150156123565780806020019051810190612d8a919061311f565b6123565760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161099a565b6040516001600160a01b03831660248201526044810182905261235690849063a9059cbb60e01b90606401612a1b565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e9060440160206040518083038186803b158015612e6557600080fd5b505afa158015612e79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9d9190613270565b612ea791906134ce565b6040516001600160a01b038516602482015260448101829052909150612a5290859063095ea7b360e01b90606401612a1b565b6060612ee98484600085612ef3565b90505b9392505050565b606082471015612f545760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161099a565b6001600160a01b0385163b612fab5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161099a565b600080866001600160a01b03168587604051612fc79190613305565b60006040518083038185875af1925050503d8060008114613004576040519150601f19603f3d011682016040523d82523d6000602084013e613009565b606091505b5091509150613019828286613024565b979650505050505050565b60608315613033575081612eec565b8251156130435782518084602001fd5b8160405162461bcd60e51b815260040161099a9190613321565b8280548282559060005260206000209081019282156130b2579160200282015b828111156130b257825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019061307d565b506130be9291506130c2565b5090565b5b808211156130be57600081556001016130c3565b80356130e281613594565b919050565b6000602082840312156130f8578081fd5b8135612eec81613594565b600060208284031215613114578081fd5b8135612eec816135a9565b600060208284031215613130578081fd5b8151612eec816135a9565b6000806040838503121561314d578081fd5b8235613158816135a9565b91506020830135613168816135a9565b809150509250929050565b600080600060608486031215613187578081fd5b833561319281613594565b92506020848101359250604085013567ffffffffffffffff808211156131b6578384fd5b818701915087601f8301126131c9578384fd5b8135818111156131db576131db61357e565b8060051b604051601f19603f830116810181811085821117156132005761320061357e565b604052828152858101935084860182860187018c101561321e578788fd5b8795505b8386101561324757613233816130d7565b855260019590950194938601938601613222565b508096505050505050509250925092565b600060208284031215613269578081fd5b5035919050565b600060208284031215613281578081fd5b5051919050565b6000806040838503121561329a578182fd5b50508035926020909101359150565b6000806000606084860312156132bd578283fd5b505081359360208301359350604090920135919050565b600080600080608085870312156132e9578081fd5b5050823594602084013594506040840135936060013592509050565b6000825161331781846020870161353c565b9190910192915050565b602081526000825180602084015261334081604085016020870161353c565b601f01601f19169190910160400192915050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526025908201527f506f6f6c3a3a7265636f6c6c61746572616c697a653a20496e76616c696420616040820152641b5bdd5b9d60da1b606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60006040820184835260206040818501528185518084526060860191508287019350845b8181101561344e5784516001600160a01b031683529383019391830191600101613429565b5090979650505050505050565b600060a082018783526020878185015260a0604085015281875480845260c0860191508885528285209350845b818110156134ad5784546001600160a01b031683526001948501949284019201613488565b50506001600160a01b03969096166060850152505050608001529392505050565b600082198211156134e1576134e1613568565b500190565b60008261350157634e487b7160e01b81526012600452602481fd5b500490565b600081600019048311821515161561352057613520613568565b500290565b60008282101561353757613537613568565b500390565b60005b8381101561355757818101518382015260200161353f565b83811115612a525750506000910152565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461222457600080fd5b801515811461222457600080fdfea26469706673582212208d87d385a3815c365c2ff77e819cb705f64769e2a4adb8a197b3cb073f30918a64736f6c63430008040033506f6f6c3a3a696e697469616c697a653a20696e76616c696441646472657373000000000000000000000000fbd2945d3601f21540ddd85c29c5c3caf108b96f000000000000000000000000aa621d2002b5a6275ef62d7a065a865167914801

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

000000000000000000000000fbd2945d3601f21540ddd85c29c5c3caf108b96f000000000000000000000000aa621d2002b5a6275ef62d7a065a865167914801

-----Decoded View---------------
Arg [0] : _xftm (address): 0xfbd2945d3601f21540ddd85c29c5c3caf108b96f
Arg [1] : _fantasm (address): 0xaa621d2002b5a6275ef62d7a065a865167914801

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000fbd2945d3601f21540ddd85c29c5c3caf108b96f
Arg [1] : 000000000000000000000000aa621d2002b5a6275ef62d7a065a865167914801


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Validator ID :
0 FTM

Amount Staked
0

Amount Delegated
0

Staking Total
0

Staking Start Epoch
0

Staking Start Time
0

Proof of Importance
0

Origination Score
0

Validation Score
0

Active
0

Online
0

Downtime
0 s
Address Amount claimed Rewards Created On Epoch Created On
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.