Contract 0xe206074595d33bd315aa436f3eb5159668ec8f8b 1

Contract Overview

Balance:
0.004402136810013328 MOVR

MOVR Value:
$0.03 (@ $7.88/MOVR)

Token:
Txn Hash Method
Block
From
To
Value [Txn Fee]
0xdaae531b6781336e535486226392862437212f7ba3e8ccd6ea28474ab9117342Set Max Tvl27033562022-10-04 15:03:36174 days 5 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.000026367
0xd8b3b4899b2799fc7148ce6036b6a30ef91f941f6f6f6b66f4c2cfc5c495058aHarvest27007342022-10-04 6:01:54174 days 14 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.0031299576
0xe29de145cdcba65e267cc0994458ac27b691e869c638da41ce0857df352e73f5Set Max Tvl26977972022-10-03 19:50:48175 days 37 mins ago0x157875c30f83729ce9c1e7a1568ec00250237862 IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.000074995
0x524573c6956fc4c921323d4712d639112f18c1f244896f8b85a61501464b37f2Rebalance26977442022-10-03 19:40:00175 days 48 mins ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.04062943695
0xb913178681c033b51842aa4694f7983f5efdc0f900744dd914145da7af1391ddHarvest26969762022-10-03 17:02:36175 days 3 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.005349825
0xd4bbba45ce30129590c6abc835221dce2797198cd362e8347a5b2373d4db1e87Harvest26932142022-10-03 4:01:42175 days 16 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.002283875
0xf365f8d7452282ebc62de2f775f1c71c1860ac3f369379144517f344f2a08796Harvest26894502022-10-02 15:02:42176 days 5 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.0024915
0x7a16bf5622669a6ac12bb92da7af3d46743319380c9f58afacf8310bde00bb44Harvest26856882022-10-02 2:02:12176 days 18 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.002353923
0x44b62e795c29674e24edb4c16eca26bc49a18e8d40b6313f353a4f314e8a3d38Harvest26819492022-10-01 13:02:42177 days 7 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.004152678
0xfab6eed1df1d3f5c314cb2c2eb339234d3d0c9ffbe622bf5c838521c315d24d6Harvest26781832022-10-01 0:03:12177 days 20 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.0027820143
0xf17855d7f2ea8b978783023955f526f6843dddf7b4a08dc21a2840d23ec1fb3bHarvest26744022022-09-30 11:02:54178 days 9 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.0054242864
0x897522e0c3f197e9d8534262f9316ad6f209ff25ed9ecacb51af2c93dc4fa1a0Harvest26706022022-09-29 22:01:18178 days 22 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.004168818
0x48f9f01ee6e689414ca75b3e69aee1b0b5277ada81678e4f6fedf2c3e3fcaf4aRebalance26669382022-09-29 9:18:06179 days 11 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.075630522
0xd07ef0b9baa65281c50d736328fa500c0e9838c9bd0e22861a63671dd4063e30Rebalance26664502022-09-29 7:37:24179 days 12 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.15007545
0xca6f9255a307eedaecd2ceea8e406d64a9cce3dbcad1330d96145623bc87acf2Rebalance Loan26664332022-09-29 7:33:48179 days 12 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.1104228
0x14bb67b6c7d21aceeebb45bfba1d2e951bf6547cd6920887d4957053031e6826Harvest26642282022-09-29 0:01:36179 days 20 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.004268032
0x3ef78f1d23cbcbf46dc577c3157ce119daed1655baf334f444cfd65e1f77fe17Harvest26639372022-09-28 23:01:30179 days 21 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.0023474264
0x7bb88f125c678a8044e2f457c114b1c4f8cc47405a5ba67faab675697c3f5c07Harvest26636492022-09-28 22:01:36179 days 22 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.00533504
0xc0eb97aef02b70b22fcd1c8136a7a6ad6fd3792985c79cf2d74e02bd57daefd2Harvest26630832022-09-28 20:01:42180 days 26 mins ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.00533504
0x0931bdf958a2817c97350ad008047c5cb3d7518b20dad29663b82a198f6f11c8Harvest26627942022-09-28 19:01:24180 days 1 hr ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.0053828736
0x474c362af6d6051ba67c8d08efaf4dd4b4ed24c53ad98e93d8e1756e5405ad82Harvest26625042022-09-28 18:01:30180 days 2 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.00521566
0xf5cd9f3b7f9376bc7d993ffdbdae85fc70f5c2bc051f22eebab76022033ebe59Harvest26622152022-09-28 17:01:30180 days 3 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.00533506
0x5715642bc40129e313ae429c318ee7154f12c0ea3015dcd1110d4eab7108bfccHarvest26619262022-09-28 16:01:06180 days 4 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.00533506
0x4a0d4ca1514b4c8d7504e0557dc8e6fe28cb67da915b7231e6608cc2ea1a67ffHarvest26616402022-09-28 15:01:36180 days 5 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.0055484416
0xde73c26310eea68c279efaf2912d72263cc3131c2e0c9a38d08d085e0eed501fHarvest26613482022-09-28 14:01:18180 days 6 hrs ago0x6ddf9da4c37df97cb2458f85050e09994cbb9c2a IN  0xe206074595d33bd315aa436f3eb5159668ec8f8b0 MOVR0.0055484416
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x793defbae51737d82a621d00a907479823c01c08c49e63796fc4ad53221cf49e27033212022-10-04 14:56:36174 days 5 hrs ago 0x957e034bcd6029f7bc71f6e9894fbf088a30f0a6 0xe206074595d33bd315aa436f3eb5159668ec8f8b0.00440213680961047 MOVR
0x793defbae51737d82a621d00a907479823c01c08c49e63796fc4ad53221cf49e27033212022-10-04 14:56:36174 days 5 hrs ago 0x48e47d6554d78ca7478a6eff5fcee463ecf13a8c 0xe206074595d33bd315aa436f3eb5159668ec8f8b0.000000000000402858 MOVR
0xd8b3b4899b2799fc7148ce6036b6a30ef91f941f6f6f6b66f4c2cfc5c495058a27007342022-10-04 6:01:54174 days 14 hrs ago 0xe206074595d33bd315aa436f3eb5159668ec8f8b Moonbeam Foundation: WMOVR Token0.977865448354556865 MOVR
0xd8b3b4899b2799fc7148ce6036b6a30ef91f941f6f6f6b66f4c2cfc5c495058a27007342022-10-04 6:01:54174 days 14 hrs ago Moonwell: Comptroller 2 0xe206074595d33bd315aa436f3eb5159668ec8f8b0.000000000000001489 MOVR
0xd8b3b4899b2799fc7148ce6036b6a30ef91f941f6f6f6b66f4c2cfc5c495058a27007342022-10-04 6:01:54174 days 14 hrs ago Moonwell: Comptroller 2 0xe206074595d33bd315aa436f3eb5159668ec8f8b0.977865448354555376 MOVR
0xd8b3b4899b2799fc7148ce6036b6a30ef91f941f6f6f6b66f4c2cfc5c495058a27007342022-10-04 6:01:54174 days 14 hrs ago 0xe206074595d33bd315aa436f3eb5159668ec8f8b Moonbeam Foundation: WMOVR Token3.239971035451520052 MOVR
0xd1533b599fdb8a174c22872c1a477fe8ff563bbfad0e75d483f29810d05f4e5126977952022-10-03 19:50:24175 days 37 mins ago 0xe206074595d33bd315aa436f3eb5159668ec8f8b Moonwell: mMOVR Token2,379.244587966153519337 MOVR
0xd1533b599fdb8a174c22872c1a477fe8ff563bbfad0e75d483f29810d05f4e5126977952022-10-03 19:50:24175 days 37 mins ago Moonbeam Foundation: WMOVR Token 0xe206074595d33bd315aa436f3eb5159668ec8f8b2,379.244587966153519337 MOVR
0xd1533b599fdb8a174c22872c1a477fe8ff563bbfad0e75d483f29810d05f4e5126977952022-10-03 19:50:24175 days 37 mins ago 0x957e034bcd6029f7bc71f6e9894fbf088a30f0a6 0xe206074595d33bd315aa436f3eb5159668ec8f8b0.005112244400557073 MOVR
0xd1533b599fdb8a174c22872c1a477fe8ff563bbfad0e75d483f29810d05f4e5126977952022-10-03 19:50:24175 days 37 mins ago 0x48e47d6554d78ca7478a6eff5fcee463ecf13a8c 0xe206074595d33bd315aa436f3eb5159668ec8f8b0.00000000000046451 MOVR
0x1c97d0119177c0d4d6d7d9749df0c810f86982bd34ec9331a5bfb02d678ae8bf26977862022-10-03 19:48:36175 days 39 mins ago 0xe206074595d33bd315aa436f3eb5159668ec8f8b Moonwell: mMOVR Token3,016.976456082685367652 MOVR
0x1c97d0119177c0d4d6d7d9749df0c810f86982bd34ec9331a5bfb02d678ae8bf26977862022-10-03 19:48:36175 days 39 mins ago Moonbeam Foundation: WMOVR Token 0xe206074595d33bd315aa436f3eb5159668ec8f8b3,016.976456082685367652 MOVR
0x1c97d0119177c0d4d6d7d9749df0c810f86982bd34ec9331a5bfb02d678ae8bf26977862022-10-03 19:48:36175 days 39 mins ago 0x957e034bcd6029f7bc71f6e9894fbf088a30f0a6 0xe206074595d33bd315aa436f3eb5159668ec8f8b0.012160221543435654 MOVR
0x1c97d0119177c0d4d6d7d9749df0c810f86982bd34ec9331a5bfb02d678ae8bf26977862022-10-03 19:48:36175 days 39 mins ago 0x48e47d6554d78ca7478a6eff5fcee463ecf13a8c 0xe206074595d33bd315aa436f3eb5159668ec8f8b0.000000000001109858 MOVR
0x0c8bfd25f3a06540df3bf7b46d44c7f38749635b5181b60832386fc8ecb3bb4226977772022-10-03 19:46:42175 days 41 mins ago 0xe206074595d33bd315aa436f3eb5159668ec8f8b Moonwell: mMOVR Token2,996.409584585884289878 MOVR
0x0c8bfd25f3a06540df3bf7b46d44c7f38749635b5181b60832386fc8ecb3bb4226977772022-10-03 19:46:42175 days 41 mins ago Moonbeam Foundation: WMOVR Token 0xe206074595d33bd315aa436f3eb5159668ec8f8b2,996.409584585884289878 MOVR
0x0c8bfd25f3a06540df3bf7b46d44c7f38749635b5181b60832386fc8ecb3bb4226977772022-10-03 19:46:42175 days 41 mins ago 0x957e034bcd6029f7bc71f6e9894fbf088a30f0a6 0xe206074595d33bd315aa436f3eb5159668ec8f8b0.067228359934668973 MOVR
0x0c8bfd25f3a06540df3bf7b46d44c7f38749635b5181b60832386fc8ecb3bb4226977772022-10-03 19:46:42175 days 41 mins ago 0x48e47d6554d78ca7478a6eff5fcee463ecf13a8c 0xe206074595d33bd315aa436f3eb5159668ec8f8b0.000000000006147203 MOVR
0x524573c6956fc4c921323d4712d639112f18c1f244896f8b85a61501464b37f226977442022-10-03 19:40:00175 days 48 mins ago 0x957e034bcd6029f7bc71f6e9894fbf088a30f0a6 0xe206074595d33bd315aa436f3eb5159668ec8f8b0.004910199441580707 MOVR
0x524573c6956fc4c921323d4712d639112f18c1f244896f8b85a61501464b37f226977442022-10-03 19:40:00175 days 48 mins ago 0x48e47d6554d78ca7478a6eff5fcee463ecf13a8c 0xe206074595d33bd315aa436f3eb5159668ec8f8b0.0000000000004474 MOVR
0x524573c6956fc4c921323d4712d639112f18c1f244896f8b85a61501464b37f226977442022-10-03 19:40:00175 days 48 mins ago 0xe206074595d33bd315aa436f3eb5159668ec8f8b Moonbeam Foundation: WMOVR Token529.126990187948483328 MOVR
0x524573c6956fc4c921323d4712d639112f18c1f244896f8b85a61501464b37f226977442022-10-03 19:40:00175 days 48 mins ago Moonwell: mMOVR Token 0xe206074595d33bd315aa436f3eb5159668ec8f8b529.126990187948483328 MOVR
0x04f7dfaf1d8af71bb8450f99903839d40a048ab243badf6bd105a051f284756826977422022-10-03 19:39:30175 days 48 mins ago 0xe206074595d33bd315aa436f3eb5159668ec8f8b Moonwell: mMOVR Token3,008.833383078065155811 MOVR
0x04f7dfaf1d8af71bb8450f99903839d40a048ab243badf6bd105a051f284756826977422022-10-03 19:39:30175 days 48 mins ago Moonbeam Foundation: WMOVR Token 0xe206074595d33bd315aa436f3eb5159668ec8f8b3,008.833383078065155811 MOVR
0x04f7dfaf1d8af71bb8450f99903839d40a048ab243badf6bd105a051f284756826977422022-10-03 19:39:30175 days 48 mins ago 0x957e034bcd6029f7bc71f6e9894fbf088a30f0a6 0xe206074595d33bd315aa436f3eb5159668ec8f8b0.037304105899517509 MOVR
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
USDCmovrSOLARwell

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 1 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 34 : 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 34 : 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 34 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (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 `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, 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 `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

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

    /**
     * @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 4 of 34 : 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 5 of 34 : 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 6 of 34 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)

pragma solidity ^0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 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 7 of 34 : 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 8 of 34 : Strategy.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

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

/// @notice Minimal interface for Vault compatible strategies.
/// @dev Designed for out of the box compatibility with Fuse cTokens.
/// @dev Like cTokens, strategies must be transferrable ERC20s.
abstract contract Strategy {
	/// @notice Returns whether the strategy accepts ETH or an ERC20.
	/// @return True if the strategy accepts ETH, false otherwise.
	/// @dev Only present in Fuse cTokens, not Compound cTokens.
	function isCEther() external view virtual returns (bool);

	/// @notice Withdraws a specific amount of underlying tokens from the strategy.
	/// @param amount The amount of underlying tokens to withdraw.
	/// @return An error code, or 0 if the withdrawal was successful.
	function redeemUnderlying(uint256 amount) external virtual returns (uint256);

	/// @notice Returns a user's strategy balance in underlying tokens.
	/// @param user The user to get the underlying balance of.
	/// @return The user's strategy balance in underlying tokens.
	/// @dev May mutate the state of the strategy by accruing interest.
	function balanceOfUnderlying(address user) external virtual returns (uint256);

	/// @notice Returns max deposits a strategy can take.
	/// @return MaxTvl
	function getMaxTvl() external virtual returns (uint256);

	/// @notice Withdraws any ERC20 tokens back to recipient.
	function emergencyWithdraw(address recipient, IERC20[] memory tokens) external virtual;
}

/// @notice Minimal interface for Vault strategies that accept ERC20s.
/// @dev Designed for out of the box compatibility with Fuse cERC20s.
abstract contract ERC20Strategy is Strategy {
	/// @notice Returns the underlying ERC20 token the strategy accepts.
	/// @return The underlying ERC20 token the strategy accepts.
	function underlying() external view virtual returns (IERC20);

	/// @notice Deposit a specific amount of underlying tokens into the strategy.
	/// @param amount The amount of underlying tokens to deposit.
	/// @return An error code, or 0 if the deposit was successful.
	function mint(uint256 amount) external virtual returns (uint256);
}

/// @notice Minimal interface for Vault strategies that accept ETH.
/// @dev Designed for out of the box compatibility with Fuse cEther.
abstract contract ETHStrategy is Strategy {
	/// @notice Deposit a specific amount of ETH into the strategy.
	/// @dev The amount of ETH is specified via msg.value. Reverts on error.
	function mint() external payable virtual;
}

File 9 of 34 : ICTokenInterfaces.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./IComptroller.sol";
import "./InterestRateModel.sol";

interface ICTokenStorage {
	/**
	 * @dev Container for borrow balance information
	 * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action
	 * @member interestIndex Global borrowIndex as of the most recent balance-changing action
	 */
	struct BorrowSnapshot {
		uint256 principal;
		uint256 interestIndex;
	}
}

interface ICToken is ICTokenStorage {
	/*** Market Events ***/

	/**
	 * @dev Event emitted when interest is accrued
	 */
	event AccrueInterest(
		uint256 cashPrior,
		uint256 interestAccumulated,
		uint256 borrowIndex,
		uint256 totalBorrows
	);

	/**
	 * @dev Event emitted when tokens are minted
	 */
	event Mint(address minter, uint256 mintAmount, uint256 mintTokens);

	/**
	 * @dev Event emitted when tokens are redeemed
	 */
	event Redeem(address redeemer, uint256 redeemAmount, uint256 redeemTokens);

	/**
	 * @dev Event emitted when underlying is borrowed
	 */
	event Borrow(
		address borrower,
		uint256 borrowAmount,
		uint256 accountBorrows,
		uint256 totalBorrows
	);

	/**
	 * @dev Event emitted when a borrow is repaid
	 */
	event RepayBorrow(
		address payer,
		address borrower,
		uint256 repayAmount,
		uint256 accountBorrows,
		uint256 totalBorrows
	);

	/**
	 * @dev Event emitted when a borrow is liquidated
	 */
	event LiquidateBorrow(
		address liquidator,
		address borrower,
		uint256 repayAmount,
		address cTokenCollateral,
		uint256 seizeTokens
	);

	/*** Admin Events ***/

	/**
	 * @dev Event emitted when pendingAdmin is changed
	 */
	event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);

	/**
	 * @dev Event emitted when pendingAdmin is accepted, which means admin is updated
	 */
	event NewAdmin(address oldAdmin, address newAdmin);

	/**
	 * @dev Event emitted when comptroller is changed
	 */
	event NewComptroller(IComptroller oldComptroller, IComptroller newComptroller);

	/**
	 * @dev Event emitted when interestRateModel is changed
	 */
	event NewMarketInterestRateModel(
		InterestRateModel oldInterestRateModel,
		InterestRateModel newInterestRateModel
	);

	/**
	 * @dev Event emitted when the reserve factor is changed
	 */
	event NewReserveFactor(uint256 oldReserveFactorMantissa, uint256 newReserveFactorMantissa);

	/**
	 * @dev Event emitted when the reserves are added
	 */
	event ReservesAdded(address benefactor, uint256 addAmount, uint256 newTotalReserves);

	/**
	 * @dev Event emitted when the reserves are reduced
	 */
	event ReservesReduced(address admin, uint256 reduceAmount, uint256 newTotalReserves);

	/**
	 * @dev EIP20 Transfer event
	 */
	event Transfer(address indexed from, address indexed to, uint256 amount);

	/**
	 * @dev EIP20 Approval event
	 */
	event Approval(address indexed owner, address indexed spender, uint256 amount);

	/**
	 * @dev Failure event
	 */
	event Failure(uint256 error, uint256 info, uint256 detail);

	/*** User Interface ***/
	function totalBorrows() external view returns (uint256);

	function totalReserves() external view returns (uint256);

	function totalSupply() external view returns (uint256);

	function transfer(address dst, uint256 amount) external returns (bool);

	function transferFrom(
		address src,
		address dst,
		uint256 amount
	) external returns (bool);

	function approve(address spender, uint256 amount) external returns (bool);

	function allowance(address owner, address spender) external view returns (uint256);

	function balanceOf(address owner) external view returns (uint256);

	function balanceOfUnderlying(address owner) external returns (uint256);

	function getAccountSnapshot(address account)
		external
		view
		returns (
			uint256,
			uint256,
			uint256,
			uint256
		);

	function borrowRatePerBlock() external view returns (uint256);

	function supplyRatePerBlock() external view returns (uint256);

	function totalBorrowsCurrent() external returns (uint256);

	function borrowBalanceCurrent(address account) external returns (uint256);

	function borrowBalanceStored(address account) external view returns (uint256);

	function exchangeRateCurrent() external returns (uint256);

	function exchangeRateStored() external view returns (uint256);

	function getCash() external view returns (uint256);

	function accrueInterest() external returns (uint256);

	function seize(
		address liquidator,
		address borrower,
		uint256 seizeTokens
	) external returns (uint256);

	/*** Admin Functions ***/

	function _setPendingAdmin(address payable newPendingAdmin) external returns (uint256);

	function _acceptAdmin() external returns (uint256);

	function _setComptroller(IComptroller newComptroller) external returns (uint256);

	function _setReserveFactor(uint256 newReserveFactorMantissa) external returns (uint256);

	function _reduceReserves(uint256 reduceAmount) external returns (uint256);

	function _setInterestRateModel(InterestRateModel newInterestRateModel)
		external
		returns (uint256);
}

interface ICTokenErc20 is ICToken {
	/*** User Interface ***/

	function mint(uint256 mintAmount) external returns (uint256);

	function redeem(uint256 redeemTokens) external returns (uint256);

	function redeemUnderlying(uint256 redeemAmount) external returns (uint256);

	function borrow(uint256 borrowAmount) external returns (uint256);

	function repayBorrow(uint256 repayAmount) external returns (uint256);

	function liquidateBorrow(
		address borrower,
		uint256 repayAmount,
		ICToken cTokenCollateral
	) external returns (uint256);

	/*** Admin Functions ***/

	function _addReserves(uint256 addAmount) external returns (uint256);
}

interface ICTokenBase is ICToken {
	function repayBorrow() external payable;
}

File 10 of 34 : ICompPriceOracle.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./ICTokenInterfaces.sol";

interface ICompPriceOracle {
	function isPriceOracle() external view returns (bool);

	/**
	 * @notice Get the underlying price of a cToken asset
	 * @param cToken The cToken to get the underlying price of
	 * @return The underlying asset price mantissa (scaled by 1e18).
	 *  Zero means the price is unavailable.
	 */
	function getUnderlyingPrice(address cToken) external view returns (uint256);
}

File 11 of 34 : IComptroller.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./ICTokenInterfaces.sol";

interface IComptroller {
	/*** Assets You Are In ***/

	function enterMarkets(address[] calldata cTokens) external returns (uint256[] memory);

	function exitMarket(address cToken) external returns (uint256);

	/*** Policy Hooks ***/

	function mintAllowed(
		address cToken,
		address minter,
		uint256 mintAmount
	) external returns (uint256);

	function mintVerify(
		address cToken,
		address minter,
		uint256 mintAmount,
		uint256 mintTokens
	) external;

	function redeemAllowed(
		address cToken,
		address redeemer,
		uint256 redeemTokens
	) external returns (uint256);

	function redeemVerify(
		address cToken,
		address redeemer,
		uint256 redeemAmount,
		uint256 redeemTokens
	) external;

	function borrowAllowed(
		address cToken,
		address borrower,
		uint256 borrowAmount
	) external returns (uint256);

	function borrowVerify(
		address cToken,
		address borrower,
		uint256 borrowAmount
	) external;

	function repayBorrowAllowed(
		address cToken,
		address payer,
		address borrower,
		uint256 repayAmount
	) external returns (uint256);

	function repayBorrowVerify(
		address cToken,
		address payer,
		address borrower,
		uint256 repayAmount,
		uint256 borrowerIndex
	) external;

	function liquidateBorrowAllowed(
		address cTokenBorrowed,
		address cTokenCollateral,
		address liquidator,
		address borrower,
		uint256 repayAmount
	) external returns (uint256);

	function liquidateBorrowVerify(
		address cTokenBorrowed,
		address cTokenCollateral,
		address liquidator,
		address borrower,
		uint256 repayAmount,
		uint256 seizeTokens
	) external;

	function seizeAllowed(
		address cTokenCollateral,
		address cTokenBorrowed,
		address liquidator,
		address borrower,
		uint256 seizeTokens
	) external returns (uint256);

	function seizeVerify(
		address cTokenCollateral,
		address cTokenBorrowed,
		address liquidator,
		address borrower,
		uint256 seizeTokens
	) external;

	function transferAllowed(
		address cToken,
		address src,
		address dst,
		uint256 transferTokens
	) external returns (uint256);

	function transferVerify(
		address cToken,
		address src,
		address dst,
		uint256 transferTokens
	) external;

	function claimComp(address holder) external;

	function claimComp(address holder, ICTokenErc20[] memory cTokens) external;

	/*** Liquidity/Liquidation Calculations ***/

	function liquidateCalculateSeizeTokens(
		address cTokenBorrowed,
		address cTokenCollateral,
		uint256 repayAmount
	) external view returns (uint256, uint256);
}

interface UnitrollerAdminStorage {
	/**
	 * @notice Administrator for this contract
	 */
	// address external admin;
	function admin() external view returns (address);

	/**
	 * @notice Pending administrator for this contract
	 */
	// address external pendingAdmin;
	function pendingAdmin() external view returns (address);

	/**
	 * @notice Active brains of Unitroller
	 */
	// address external comptrollerImplementation;
	function comptrollerImplementation() external view returns (address);

	/**
	 * @notice Pending brains of Unitroller
	 */
	// address external pendingComptrollerImplementation;
	function pendingComptrollerImplementation() external view returns (address);
}

interface ComptrollerV1Storage is UnitrollerAdminStorage {
	/**
	 * @notice Oracle which gives the price of any given asset
	 */
	// PriceOracle external oracle;
	function oracle() external view returns (address);

	/**
	 * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow
	 */
	// uint external closeFactorMantissa;
	function closeFactorMantissa() external view returns (uint256);

	/**
	 * @notice Multiplier representing the discount on collateral that a liquidator receives
	 */
	// uint external liquidationIncentiveMantissa;
	function liquidationIncentiveMantissa() external view returns (uint256);

	/**
	 * @notice Max number of assets a single account can participate in (borrow or use as collateral)
	 */
	// uint external maxAssets;
	function maxAssets() external view returns (uint256);

	/**
	 * @notice Per-account mapping of "assets you are in", capped by maxAssets
	 */
	// mapping(address => CToken[]) external accountAssets;
	// function accountAssets(address) external view returns (CToken[]);
}

abstract contract ComptrollerV2Storage is ComptrollerV1Storage {
	enum Version {
		VANILLA,
		COLLATERALCAP,
		WRAPPEDNATIVE
	}

	struct Market {
		bool isListed;
		uint256 collateralFactorMantissa;
		mapping(address => bool) accountMembership;
		bool isComped;
		// Version version;
	}

	/**
	 * @notice Official mapping of cTokens -> Market metadata
	 * @dev Used e.g. to determine if a market is supported
	 */
	mapping(address => Market) public markets;

	/**
	 * @notice The Pause Guardian can pause certain actions as a safety mechanism.
	 *  Actions which allow users to remove their own assets cannot be paused.
	 *  Liquidation / seizing / transfer can only be paused globally, not by market.
	 */
	// address external pauseGuardian;
	// bool external _mintGuardianPaused;
	// bool external _borrowGuardianPaused;
	// bool external transferGuardianPaused;
	// bool external seizeGuardianPaused;
	// mapping(address => bool) external mintGuardianPaused;
	// mapping(address => bool) external borrowGuardianPaused;
}

abstract contract ComptrollerV3Storage is ComptrollerV2Storage {
	// struct CompMarketState {
	//     /// @notice The market's last updated compBorrowIndex or compSupplyIndex
	//     uint224 index;
	//     /// @notice The block number the index was last updated at
	//     uint32 block;
	// }
	// /// @notice A list of all markets
	// CToken[] external allMarkets;
	// /// @notice The rate at which the flywheel distributes COMP, per block
	// uint external compRate;
	// /// @notice The portion of compRate that each market currently receives
	// mapping(address => uint) external compSpeeds;
	// /// @notice The COMP market supply state for each market
	// mapping(address => CompMarketState) external compSupplyState;
	// /// @notice The COMP market borrow state for each market
	// mapping(address => CompMarketState) external compBorrowState;
	// /// @notice The COMP borrow index for each market for each supplier as of the last time they accrued COMP
	// mapping(address => mapping(address => uint)) external compSupplierIndex;
	// /// @notice The COMP borrow index for each market for each borrower as of the last time they accrued COMP
	// mapping(address => mapping(address => uint)) external compBorrowerIndex;
	// /// @notice The COMP accrued but not yet transferred to each user
	// mapping(address => uint) external compAccrued;
}

abstract contract ComptrollerV4Storage is ComptrollerV3Storage {
	// @notice The borrowCapGuardian can set borrowCaps to any number for any market. Lowering the borrow cap could disable borrowing on the given market.
	// address external borrowCapGuardian;
	function borrowCapGuardian() external view virtual returns (address);

	// @notice Borrow caps enforced by borrowAllowed for each cToken address. Defaults to zero which corresponds to unlimited borrowing.
	// mapping(address => uint) external borrowCaps;
	function borrowCaps(address) external view virtual returns (uint256);
}

abstract contract ComptrollerV5Storage is ComptrollerV4Storage {
	// @notice The supplyCapGuardian can set supplyCaps to any number for any market. Lowering the supply cap could disable supplying to the given market.
	// address external supplyCapGuardian;
	function supplyCapGuardian() external view virtual returns (address);

	// @notice Supply caps enforced by mintAllowed for each cToken address. Defaults to zero which corresponds to unlimited supplying.
	// mapping(address => uint) external supplyCaps;
	function supplyCaps(address) external view virtual returns (uint256);
}

File 12 of 34 : InterestRateModel.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title Compound's InterestRateModel Interface
 * @author Compound
 */
interface InterestRateModel {
	/**
	 * @dev Calculates the current borrow interest rate per block
	 * @param cash The total amount of cash the market has
	 * @param borrows The total amount of borrows the market has outstanding
	 * @param reserves The total amnount of reserves the market has
	 * @return The borrow rate per block (as a percentage, and scaled by 1e18)
	 */
	function getBorrowRate(
		uint256 cash,
		uint256 borrows,
		uint256 reserves
	) external view returns (uint256);

	/**
	 * @dev Calculates the current supply interest rate per block
	 * @param cash The total amount of cash the market has
	 * @param borrows The total amount of borrows the market has outstanding
	 * @param reserves The total amnount of reserves the market has
	 * @param reserveFactorMantissa The current reserve factor the market has
	 * @return The supply rate per block (as a percentage, and scaled by 1e18)
	 */
	function getSupplyRate(
		uint256 cash,
		uint256 borrows,
		uint256 reserves,
		uint256 reserveFactorMantissa
	) external view returns (uint256);
}

File 13 of 34 : IClaimReward.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

abstract contract IClaimReward {
	function claimReward(uint8 rewardType, address payable holder) external virtual;
}

File 14 of 34 : IStakingRewards.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

interface IStakingRewards is IERC20 {
	function stakingToken() external view returns (address);

	function lastTimeRewardApplicable() external view returns (uint256);

	function rewardPerToken() external view returns (uint256);

	function earned(address account) external view returns (uint256);

	function getRewardForDuration() external view returns (uint256);

	function stakeWithPermit(
		uint256 amount,
		uint256 deadline,
		uint8 v,
		bytes32 r,
		bytes32 s
	) external;

	function stake(uint256 amount) external;

	function withdraw(uint256 amount) external;

	function getReward() external;

	function exit() external;
}

// some farms use sushi interface
interface IMasterChef {
	// depositing 0 amount will withdraw the rewards (harvest)
	function deposit(uint256 _pid, uint256 _amount) external;

	function withdraw(uint256 _pid, uint256 _amount) external;

	function userInfo(uint256 _pid, address _user) external view returns (uint256, uint256);

	function emergencyWithdraw(uint256 _pid) external;

	function pendingTokens(uint256 _pid, address _user)
		external
		view
		returns (
			uint256,
			address,
			string memory,
			uint256
		);
}

interface IMiniChefV2 {
	struct UserInfo {
		uint256 amount;
		int256 rewardDebt;
	}

	struct PoolInfo {
		uint128 accSushiPerShare;
		uint64 lastRewardTime;
		uint64 allocPoint;
	}

	function poolLength() external view returns (uint256);

	function updatePool(uint256 pid) external returns (IMiniChefV2.PoolInfo memory);

	function userInfo(uint256 _pid, address _user) external view returns (uint256, int256);

	function deposit(
		uint256 pid,
		uint256 amount,
		address to
	) external;

	function withdraw(
		uint256 pid,
		uint256 amount,
		address to
	) external;

	function harvest(uint256 pid, address to) external;

	function withdrawAndHarvest(
		uint256 pid,
		uint256 amount,
		address to
	) external;

	function emergencyWithdraw(uint256 pid, address to) external;
}

File 15 of 34 : IUniswapV2Factory.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

	function feeTo() external view returns (address);

	function feeToSetter() external view returns (address);

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

	function allPairs(uint256) external view returns (address pair);

	function allPairsLength() external view returns (uint256);

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

	function setFeeTo(address) external;

	function setFeeToSetter(address) external;
}

File 16 of 34 : IUniswapV2Pair.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

	function name() external pure returns (string memory);

	function symbol() external pure returns (string memory);

	function decimals() external pure returns (uint8);

	function totalSupply() external view returns (uint256);

	function balanceOf(address owner) external view returns (uint256);

	function allowance(address owner, address spender) external view returns (uint256);

	function approve(address spender, uint256 value) external returns (bool);

	function transfer(address to, uint256 value) external returns (bool);

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

	function DOMAIN_SEPARATOR() external view returns (bytes32);

	function PERMIT_TYPEHASH() external pure returns (bytes32);

	function nonces(address owner) external view returns (uint256);

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

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

	function MINIMUM_LIQUIDITY() external pure returns (uint256);

	function factory() external view returns (address);

	function token0() external view returns (address);

	function token1() external view returns (address);

	function getReserves()
		external
		view
		returns (
			uint112 reserve0,
			uint112 reserve1,
			uint32 blockTimestampLast
		);

	function price0CumulativeLast() external view returns (uint256);

	function price1CumulativeLast() external view returns (uint256);

	function kLast() external view returns (uint256);

	function mint(address to) external returns (uint256 liquidity);

	function burn(address to) external returns (uint256 amount0, uint256 amount1);

	function swap(
		uint256 amount0Out,
		uint256 amount1Out,
		address to,
		bytes calldata data
	) external;

	function skim(address to) external;

	function sync() external;

	function initialize(address, address) external;
}

File 17 of 34 : IUniswapV2Router01.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

	function WETH() external pure returns (address);

	function addLiquidity(
		address tokenA,
		address tokenB,
		uint256 amountADesired,
		uint256 amountBDesired,
		uint256 amountAMin,
		uint256 amountBMin,
		address to,
		uint256 deadline
	)
		external
		returns (
			uint256 amountA,
			uint256 amountB,
			uint256 liquidity
		);

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

	function removeLiquidity(
		address tokenA,
		address tokenB,
		uint256 liquidity,
		uint256 amountAMin,
		uint256 amountBMin,
		address to,
		uint256 deadline
	) external returns (uint256 amountA, uint256 amountB);

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

	function removeLiquidityWithPermit(
		address tokenA,
		address tokenB,
		uint256 liquidity,
		uint256 amountAMin,
		uint256 amountBMin,
		address to,
		uint256 deadline,
		bool approveMax,
		uint8 v,
		bytes32 r,
		bytes32 s
	) external returns (uint256 amountA, uint256 amountB);

	function removeLiquidityETHWithPermit(
		address token,
		uint256 liquidity,
		uint256 amountTokenMin,
		uint256 amountETHMin,
		address to,
		uint256 deadline,
		bool approveMax,
		uint8 v,
		bytes32 r,
		bytes32 s
	) external returns (uint256 amountToken, uint256 amountETH);

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

	function swapTokensForExactTokens(
		uint256 amountOut,
		uint256 amountInMax,
		address[] calldata path,
		address to,
		uint256 deadline
	) external returns (uint256[] memory amounts);

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

	function swapTokensForExactETH(
		uint256 amountOut,
		uint256 amountInMax,
		address[] calldata path,
		address to,
		uint256 deadline
	) external returns (uint256[] memory amounts);

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

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

	function quote(
		uint256 amountA,
		uint256 reserveA,
		uint256 reserveB
	) external pure returns (uint256 amountB);

	function getAmountOut(
		uint256 amountIn,
		uint256 reserveIn,
		uint256 reserveOut
	) external pure returns (uint256 amountOut);

	function getAmountIn(
		uint256 amountOut,
		uint256 reserveIn,
		uint256 reserveOut
	) external pure returns (uint256 amountIn);

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

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

File 18 of 34 : IWETH.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IWETH {
	function deposit() external payable;

	function transfer(address to, uint256 value) external returns (bool);

	function withdraw(uint256) external;

	function balanceOf(address) external returns (uint256);
}

File 19 of 34 : SafeETH.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

library SafeETH {
	function safeTransferETH(address to, uint256 amount) internal {
		bool callStatus;

		assembly {
			// Transfer the ETH and store if it succeeded or not.
			callStatus := call(gas(), to, amount, 0, 0, 0, 0)
		}

		require(callStatus, "ETH_TRANSFER_FAILED");
	}
}

File 20 of 34 : UniUtils.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../interfaces/uniswap/IUniswapV2Pair.sol";
import "../interfaces/uniswap/IUniswapV2Router01.sol";
import "../interfaces/uniswap/IUniswapV2Factory.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

library UniUtils {
	using SafeERC20 for IERC20;

	function _getPairTokens(IUniswapV2Pair pair) internal view returns (address, address) {
		return (pair.token0(), pair.token1());
	}

	function _getPairReserves(
		IUniswapV2Pair pair,
		address tokenA,
		address tokenB
	) internal view returns (uint256 reserveA, uint256 reserveB) {
		(address token0, ) = _sortTokens(tokenA, tokenB);
		(uint256 reserve0, uint256 reserve1, ) = pair.getReserves();
		(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
	}

	// given some amount of an asset and lp reserves, returns an equivalent amount of the other asset
	function _quote(
		uint256 amountA,
		uint256 reserveA,
		uint256 reserveB
	) internal pure returns (uint256 amountB) {
		require(amountA > 0, "UniUtils: INSUFFICIENT_AMOUNT");
		require(reserveA > 0 && reserveB > 0, "UniUtils: INSUFFICIENT_LIQUIDITY");
		amountB = (amountA * reserveB) / reserveA;
	}

	function _sortTokens(address tokenA, address tokenB)
		internal
		pure
		returns (address token0, address token1)
	{
		require(tokenA != tokenB, "UniUtils: IDENTICAL_ADDRESSES");
		(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
		require(token0 != address(0), "UniUtils: ZERO_ADDRESS");
	}

	function _getAmountOut(
		IUniswapV2Pair pair,
		uint256 amountIn,
		address inToken,
		address outToken
	) internal view returns (uint256 amountOut) {
		require(amountIn > 0, "UniUtils: INSUFFICIENT_INPUT_AMOUNT");
		(uint256 reserveIn, uint256 reserveOut) = _getPairReserves(pair, inToken, outToken);
		uint256 amountInWithFee = amountIn * 997;
		uint256 numerator = amountInWithFee * reserveOut;
		uint256 denominator = reserveIn * 1000 + amountInWithFee;
		amountOut = numerator / denominator;
	}

	function _getAmountIn(
		IUniswapV2Pair pair,
		uint256 amountOut,
		address inToken,
		address outToken
	) internal view returns (uint256 amountIn) {
		require(amountOut > 0, "UniUtils: INSUFFICIENT_OUTPUT_AMOUNT");
		(uint256 reserveIn, uint256 reserveOut) = _getPairReserves(pair, inToken, outToken);
		uint256 numerator = reserveIn * amountOut * 1000;
		uint256 denominator = (reserveOut - amountOut) * 997;
		amountIn = (numerator / denominator) + 1;
	}

	function _swapExactTokensForTokens(
		IUniswapV2Pair pair,
		uint256 amountIn,
		address inToken,
		address outToken
	) internal returns (uint256) {
		uint256 amountOut = _getAmountOut(pair, amountIn, inToken, outToken);
		(address token0, ) = _sortTokens(outToken, inToken);
		(uint256 amount0Out, uint256 amount1Out) = inToken == token0
			? (uint256(0), amountOut)
			: (amountOut, uint256(0));

		IERC20(inToken).safeTransfer(address(pair), amountIn);
		pair.swap(amount0Out, amount1Out, address(this), new bytes(0));
		return amountOut;
	}

	function _swapTokensForExactTokens(
		IUniswapV2Pair pair,
		uint256 amountOut,
		address inToken,
		address outToken
	) internal returns (uint256) {
		uint256 amountIn = _getAmountIn(pair, amountOut, inToken, outToken);
		(address token0, ) = _sortTokens(outToken, inToken);
		(uint256 amount0Out, uint256 amount1Out) = inToken == token0
			? (uint256(0), amountOut)
			: (amountOut, uint256(0));

		IERC20(inToken).safeTransfer(address(pair), amountIn);
		pair.swap(amount0Out, amount1Out, address(this), new bytes(0));
		return amountIn;
	}
}

File 21 of 34 : IBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

struct Config {
	address underlying;
	address short;
	address cTokenLend;
	address cTokenBorrow;
	address uniPair;
	address uniFarm;
	address farmToken;
	uint256 farmId;
	address farmRouter;
	address comptroller;
	address lendRewardRouter;
	address lendRewardToken;
	address vault;
	string symbol;
	string name;
	uint256 maxTvl;
}

// all interfaces need to inherit from base
abstract contract IBase {
	bool public isIntialized;

	modifier initializer() {
		require(isIntialized == false, "INITIALIZED");
		_;
	}

	function short() public view virtual returns (IERC20);

	function underlying() public view virtual returns (IERC20);
}

File 22 of 34 : ICompound.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../interfaces/compound/ICTokenInterfaces.sol";
import "../interfaces/compound/IComptroller.sol";
import "../interfaces/compound/ICompPriceOracle.sol";
import "../interfaces/compound/IComptroller.sol";

import "../interfaces/uniswap/IWETH.sol";

import "./ILending.sol";
import "./IBase.sol";

// import "hardhat/console.sol";

abstract contract ICompound is ILending {
	using SafeERC20 for IERC20;

	function cTokenLend() public view virtual returns (ICTokenErc20);

	function cTokenBorrow() public view virtual returns (ICTokenErc20);

	function oracle() public view virtual returns (ICompPriceOracle);

	function comptroller() public view virtual returns (IComptroller);

	function _enterMarket() internal {
		address[] memory cTokens = new address[](2);
		cTokens[0] = address(cTokenLend());
		cTokens[1] = address(cTokenBorrow());
		comptroller().enterMarkets(cTokens);
	}

	function _getCollateralFactor() internal view override returns (uint256) {
		(, uint256 collateralFactorMantissa, ) = ComptrollerV2Storage(address(comptroller()))
			.markets(address(cTokenLend()));
		return collateralFactorMantissa;
	}

	// TODO handle error
	function _redeem(uint256 amount) internal override {
		uint256 err = cTokenLend().redeemUnderlying(amount);
		// require(err == 0, "Compund: error redeeming underlying");
	}

	function _borrow(uint256 amount) internal override {
		cTokenBorrow().borrow(amount);

		// in case we need to wrap the tokens
		if (_isBase(1)) IWETH(address(short())).deposit{ value: amount }();
	}

	function _lend(uint256 amount) internal override {
		cTokenLend().mint(amount);
	}

	function _repay(uint256 amount) internal override {
		if (_isBase(1)) {
			// need to convert to base first
			IWETH(address(short())).withdraw(amount);

			// then repay in the base
			_repayBase(amount);
			return;
		}
		cTokenBorrow().repayBorrow(amount);
	}

	function _repayBase(uint256 amount) internal {
		ICTokenBase(address(cTokenBorrow())).repayBorrow{ value: amount }();
	}

	function _updateAndGetCollateralBalance() internal override returns (uint256) {
		return cTokenLend().balanceOfUnderlying(address(this));
	}

	function _getCollateralBalance() internal view override returns (uint256) {
		uint256 b = cTokenLend().balanceOf(address(this));
		return (b * cTokenLend().exchangeRateStored()) / 1e18;
	}

	function _updateAndGetBorrowBalance() internal override returns (uint256) {
		return cTokenBorrow().borrowBalanceCurrent(address(this));
	}

	function _getBorrowBalance() internal view override returns (uint256 shortBorrow) {
		shortBorrow = cTokenBorrow().borrowBalanceStored(address(this));
	}

	function _oraclePriceOfShort(uint256 amount) internal view override returns (uint256) {
		return
			(amount * oracle().getUnderlyingPrice(address(cTokenBorrow()))) /
			oracle().getUnderlyingPrice(address(cTokenLend()));
	}

	function _oraclePriceOfUnderlying(uint256 amount) internal view override returns (uint256) {
		return
			(amount * oracle().getUnderlyingPrice(address(cTokenLend()))) /
			oracle().getUnderlyingPrice(address(cTokenBorrow()));
	}

	function _maxBorrow() internal view virtual override returns (uint256) {
		return cTokenBorrow().getCash();
	}

	// returns true if either of the CTokens is cEth
	// index 0 = cTokenLend index 1 = cTokenBorrow
	function _isBase(uint8 index) internal virtual returns (bool) {}
}

File 23 of 34 : IFarmable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../interfaces/uniswap/IUniswapV2Router01.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./IBase.sol";

struct HarvestSwapParms {
	address[] path; //path that the token takes
	uint256 min; // min price of in token * 1e18 (computed externally based on spot * slippage + fees)
	uint256 deadline;
}

abstract contract IFarmable is IBase {
	using SafeERC20 for IERC20;

	event HarvestedToken(address indexed token, uint256 amount);

	function _swap(
		IUniswapV2Router01 router,
		HarvestSwapParms calldata swapParams,
		address from,
		uint256 amount
	) internal {
		address out = swapParams.path[swapParams.path.length - 1];
		// ensure malicious harvester is not trading with wrong tokens
		// TODO should we limit path length to 2 to prevent malicious path?
		require(
			((swapParams.path[0] == address(from) && (out == address(short()))) ||
				out == address(underlying())),
			"IFarmable: WRONG_PATH"
		);
		router.swapExactTokensForTokens(
			amount,
			swapParams.min,
			swapParams.path, // optimal route determined externally
			address(this),
			swapParams.deadline
		);
	}
}

File 24 of 34 : IFarmableLp.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;

import "./IFarmable.sol";

abstract contract IFarmableLp is IFarmable {
	function _depositIntoFarm(uint256 amount) internal virtual;

	function _withdrawFromFarm(uint256 amount) internal virtual;

	function _harvestFarm(HarvestSwapParms[] calldata swapParams)
		internal
		virtual
		returns (uint256[] memory);

	function _getFarmLp() internal view virtual returns (uint256);

	function _addFarmApprovals() internal virtual;

	function farmRouter() public view virtual returns (IUniswapV2Router01);
}

File 25 of 34 : ILending.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./IBase.sol";
import "./IFarmable.sol";

// import "hardhat/console.sol";

abstract contract ILending is IBase {
	function _addLendingApprovals() internal virtual;

	function _getCollateralBalance() internal view virtual returns (uint256);

	function _getBorrowBalance() internal view virtual returns (uint256);

	function _updateAndGetCollateralBalance() internal virtual returns (uint256);

	function _updateAndGetBorrowBalance() internal virtual returns (uint256);

	function _getCollateralFactor() internal view virtual returns (uint256);

	function safeCollateralRatio() public view virtual returns (uint256);

	function _oraclePriceOfShort(uint256 amount) internal view virtual returns (uint256);

	function _oraclePriceOfUnderlying(uint256 amount) internal view virtual returns (uint256);

	function _lend(uint256 amount) internal virtual;

	function _redeem(uint256 amount) internal virtual;

	function _borrow(uint256 amount) internal virtual;

	function _repay(uint256 amount) internal virtual;

	function _harvestLending(HarvestSwapParms[] calldata swapParams)
		internal
		virtual
		returns (uint256[] memory);

	function lendFarmRouter() public view virtual returns (IUniswapV2Router01);

	function getCollateralRatio() public view virtual returns (uint256) {
		return (_getCollateralFactor() * safeCollateralRatio()) / 1e18;
	}

	// returns loan health value which is collateralBalance / minCollateral
	function loanHealth() public view returns (uint256) {
		uint256 borrowValue = _oraclePriceOfShort(_getBorrowBalance());
		if (borrowValue == 0) return 10000;
		uint256 collateralBalance = _getCollateralBalance();
		uint256 minCollateral = (borrowValue * 1e18) / _getCollateralFactor();
		return (1e18 * collateralBalance) / minCollateral;
	}

	function _adjustCollateral(uint256 targetCollateral)
		internal
		returns (uint256 added, uint256 removed)
	{
		uint256 collateralBalance = _getCollateralBalance();
		if (collateralBalance == targetCollateral) return (0, 0);
		(added, removed) = collateralBalance > targetCollateral
			? (uint256(0), _removeCollateral(collateralBalance - targetCollateral))
			: (_addCollateral(targetCollateral - collateralBalance), uint256(0));
	}

	function _removeCollateral(uint256 amountToRemove) internal returns (uint256 removed) {
		uint256 maxRemove = _freeCollateral();
		removed = maxRemove > amountToRemove ? amountToRemove : maxRemove;
		if (removed > 0) _redeem(removed);
	}

	function _freeCollateral() internal view returns (uint256) {
		uint256 collateral = _getCollateralBalance();
		uint256 borrowValue = _oraclePriceOfShort(_getBorrowBalance());
		// stay within 1% of the liquidation threshold (this is allways temporary)
		uint256 minCollateral = (100 * (borrowValue * 1e18)) / _getCollateralFactor() / 99;
		if (minCollateral > collateral) return 0;
		return collateral - minCollateral;
	}

	function _addCollateral(uint256 amountToAdd) internal returns (uint256 added) {
		uint256 underlyingBalance = underlying().balanceOf(address(this));
		added = underlyingBalance > amountToAdd ? amountToAdd : underlyingBalance;
		if (added != 0) _lend(added);
	}

	function _maxBorrow() internal view virtual returns (uint256);
}

File 26 of 34 : ILp.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

abstract contract ILp {
	function _quote(
		uint256 amount,
		address token0,
		address token1
	) internal view virtual returns (uint256 price);

	function _addLiquidity(uint256 amountToken0, uint256 amountToken1)
		internal
		virtual
		returns (uint256 liquidity);

	function _removeLiquidity(uint256 liquidity) internal virtual returns (uint256, uint256);

	function _getLPBalances()
		internal
		view
		virtual
		returns (uint256 underlyingBalance, uint256 shortBalance);
}

File 27 of 34 : IUniLp.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import "../interfaces/uniswap/IUniswapV2Pair.sol";
import "../libraries/UniUtils.sol";

import "./IBase.sol";
import "./ILp.sol";

// import "hardhat/console.sol";

abstract contract IUniLp is IBase, ILp {
	using SafeERC20 for IERC20;
	using UniUtils for IUniswapV2Pair;

	function pair() public view virtual returns (IUniswapV2Pair);

	function _getLiquidity() internal view virtual returns (uint256);

	// should only be called after oracle or user-input swap price check
	function _addLiquidity(uint256 amountToken0, uint256 amountToken1)
		internal
		override
		returns (uint256 liquidity)
	{
		underlying().safeTransfer(address(pair()), amountToken0);
		short().safeTransfer(address(pair()), amountToken1);
		liquidity = pair().mint(address(this));
	}

	function _removeLiquidity(uint256 liquidity) internal override returns (uint256, uint256) {
		IERC20(address(pair())).safeTransfer(address(pair()), liquidity);
		(address tokenA, ) = UniUtils._sortTokens(address(underlying()), address(short()));
		(uint256 amountToken0, uint256 amountToken1) = pair().burn(address(this));
		return
			tokenA == address(underlying())
				? (amountToken0, amountToken1)
				: (amountToken1, amountToken0);
	}

	function _quote(
		uint256 amount,
		address token0,
		address token1
	) internal view virtual override returns (uint256 price) {
		if (amount == 0) return 0;
		(uint256 reserve0, uint256 reserve1) = pair()._getPairReserves(token0, token1);
		price = UniUtils._quote(amount, reserve0, reserve1);
	}

	// fetches and sorts the reserves for a uniswap pair
	function getUnderlyingShortReserves() public view returns (uint256 reserveA, uint256 reserveB) {
		(reserveA, reserveB) = pair()._getPairReserves(address(underlying()), address(short()));
	}

	function _getLPBalances()
		internal
		view
		override
		returns (uint256 underlyingBalance, uint256 shortBalance)
	{
		uint256 totalLp = _getLiquidity();
		(uint256 totalUnderlyingBalance, uint256 totalShortBalance) = getUnderlyingShortReserves();
		uint256 total = pair().totalSupply();
		underlyingBalance = (totalUnderlyingBalance * totalLp) / total;
		shortBalance = (totalShortBalance * totalLp) / total;
	}
}

File 28 of 34 : BaseStrategy.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

import "../interfaces/Strategy.sol";
import "../libraries/SafeETH.sol";

// import "hardhat/console.sol";

abstract contract BaseStrategy is Strategy, Ownable, ReentrancyGuard {
	using SafeERC20 for IERC20;

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

	modifier onlyAuth() {
		require(msg.sender == owner() || _managers[msg.sender] == true, "Strat: NO_AUTH");
		_;
	}

	bool isInitialized;

	uint256 constant BPS_ADJUST = 10000;
	uint256 public lastHarvest; // block.timestamp;
	address private _vault;
	uint256 private _shares;

	string public name;
	string public symbol;

	mapping(address => bool) private _managers;

	uint256 public BASE_UNIT; // 10 ** decimals

	event Harvest(uint256 harvested); // this is actual the tvl before harvest
	event Deposit(address sender, uint256 amount);
	event Withdraw(address sender, uint256 amount);
	event Rebalance(uint256 shortPrice, uint256 tvlBeforeRebalance, uint256 positionOffset);
	event EmergencyWithdraw(address indexed recipient, IERC20[] tokens);
	event ManagerUpdate(address indexed account, bool isManager);
	event VaultUpdate(address indexed vault);

	constructor(
		address vault_,
		string memory symbol_,
		string memory name_
	) Ownable() ReentrancyGuard() {
		_vault = vault_;
		symbol = symbol_;
		name = name_;
	}

	// VIEW
	function vault() public view returns (address) {
		return _vault;
	}

	function totalSupply() public view returns (uint256) {
		return _shares;
	}

	/**
	 * @notice
	 *  Returns the share price of the strategy in `underlying` units, multiplied
	 *  by 1e18
	 */
	function getPricePerShare() public view returns (uint256) {
		uint256 bal = balanceOfUnderlying();
		if (_shares == 0) return BASE_UNIT;
		return (bal * BASE_UNIT) / _shares;
	}

	function balanceOfUnderlying(address) public view virtual override returns (uint256) {
		return balanceOfUnderlying();
	}

	function balanceOfUnderlying() public view virtual returns (uint256);

	// PUBLIC METHODS
	function mint(uint256 amount) external onlyVault returns (uint256 errCode) {
		uint256 newShares = _deposit(amount);
		_shares += newShares;
		errCode = 0;
	}

	function redeemUnderlying(uint256 amount)
		external
		override
		onlyVault
		returns (uint256 errCode)
	{
		uint256 burnShares = _withdraw(amount);
		_shares -= burnShares;
		errCode = 0;
	}

	// GOVERNANCE - MANAGER
	function isManager(address user) public view returns (bool) {
		return _managers[user];
	}

	function setManager(address user, bool _isManager) external onlyOwner {
		_managers[user] = _isManager;
		emit ManagerUpdate(user, _isManager);
	}

	function setVault(address vault_) external onlyOwner {
		_vault = vault_;
		emit VaultUpdate(vault_);
	}

	// emergency only
	// closePosition should be attempted first, if after some tokens are stuck,
	// send them to a designated address
	function emergencyWithdraw(address recipient, IERC20[] calldata tokens)
		external
		override
		onlyVault
	{
		for (uint256 i = 0; i < tokens.length; i++) {
			IERC20 token = tokens[i];
			uint256 balance = token.balanceOf(address(this));
			if (balance != 0) token.safeTransfer(recipient, balance);
		}
		if (address(this).balance > 0) SafeETH.safeTransferETH(msg.sender, address(this).balance);
		emit EmergencyWithdraw(recipient, tokens);
	}

	function _deposit(uint256 amount) internal virtual returns (uint256 newShares);

	function _withdraw(uint256 amount) internal virtual returns (uint256 burnShares);

	function isCEther() public pure override returns (bool) {
		return false;
	}

	receive() external payable {}
}

File 29 of 34 : HedgedLP.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

import "../mixins/IBase.sol";
import "../mixins/ILending.sol";
import "../mixins/IFarmableLp.sol";
import "../mixins/IUniLp.sol";
import "./BaseStrategy.sol";
import "../interfaces/uniswap/IWETH.sol";

// import "hardhat/console.sol";

// @custom: alphabetize dependencies to avoid linearization conflicts
abstract contract HedgedLP is IBase, BaseStrategy, ILending, IFarmableLp, IUniLp {
	using UniUtils for IUniswapV2Pair;
	using SafeERC20 for IERC20;

	event RebalanceLoan(address indexed sender, uint256 startLoanHealth, uint256 updatedLoanHealth);
	event setMinLoanHealth(uint256 loanHealth);
	event SetMaxPriceMismatch(uint256 loanHealth);
	event SetRebalanceThreshold(uint256 loanHealth);
	event SetMaxTvl(uint256 loanHealth);
	event SetSafeCollateralRaio(uint256 collateralRatio);

	uint256 constant MINIMUM_LIQUIDITY = 1000;

	IERC20 private _underlying;
	IERC20 private _short;

	uint256 public maxPriceMismatch = 150; // 1.5%
	uint256 constant maxAllowedMismatch = 300; // manager cannot make price mismatch more than 3%
	uint256 public minLoanHealth = 1.04e18; // how close to liquidation we get

	uint16 public rebalanceThreshold = 400; // 4% of lp

	uint256 private _maxTvl;
	uint256 private _safeCollateralRatio = 8400; // 84% (90% is possible but not safe)

	// for security we update this value only after oracle price checks in 'getAndUpdateTvl'
	uint256 private _cachedBalanceOfUnderlying;
	uint256 public constant version = 1;

	modifier checkPrice(uint256 maxSlippage) {
		if (maxSlippage == 0) maxSlippage = maxPriceMismatch;
		require(getPriceOffset() <= maxSlippage, "HLP: PRICE_MISMATCH");
		_;
		// any method that uses checkPrice should updated the _cachedBalanceOfUnderlying
		(_cachedBalanceOfUnderlying, , , , , ) = getTVL();
	}

	function __HedgedLP_init_(
		address underlying_,
		address short_,
		uint256 maxTvl_
	) internal initializer {
		_underlying = IERC20(underlying_);
		_short = IERC20(short_);

		_underlying.safeApprove(address(this), type(uint256).max);

		BASE_UNIT = 10**decimals();

		// init params
		setMaxTvl(maxTvl_);

		// emit default settings events
		emit setMinLoanHealth(minLoanHealth);
		emit SetMaxPriceMismatch(maxPriceMismatch);
		emit SetRebalanceThreshold(rebalanceThreshold);
		emit SetSafeCollateralRaio(_safeCollateralRatio);

		// TODO should we add a revoke aprovals methods?
		_addLendingApprovals();
		_addFarmApprovals();

		isInitialized = true;
	}

	function safeCollateralRatio() public view override returns (uint256) {
		return _safeCollateralRatio;
	}

	function setSafeCollateralRatio(uint256 safeCollateralRatio_) public onlyOwner {
		_safeCollateralRatio = safeCollateralRatio_;
		emit SetSafeCollateralRaio(safeCollateralRatio_);
	}

	function decimals() public view returns (uint8) {
		return IERC20Metadata(address(_underlying)).decimals();
	}

	// OWNER CONFIG
	function setMinLoanHeath(uint256 minLoanHealth_) public onlyOwner {
		minLoanHealth = minLoanHealth_;
		emit setMinLoanHealth(minLoanHealth_);
	}

	// manager can adjust max price if needed
	function setMaxPriceMismatch(uint256 maxPriceMismatch_) public onlyAuth {
		require(msg.sender == owner() || maxAllowedMismatch >= maxPriceMismatch_, "HLP: TOO LARGE");
		maxPriceMismatch = maxPriceMismatch_;
		emit SetMaxPriceMismatch(maxPriceMismatch_);
	}

	function setRebalanceThreshold(uint16 rebalanceThreshold_) public onlyOwner {
		rebalanceThreshold = rebalanceThreshold_;
		emit SetRebalanceThreshold(rebalanceThreshold_);
	}

	function setMaxTvl(uint256 maxTvl_) public onlyAuth {
		_maxTvl = maxTvl_;
		emit SetMaxTvl(maxTvl_);
	}

	// PUBLIC METHODS

	function short() public view override returns (IERC20) {
		return _short;
	}

	function underlying() public view override returns (IERC20) {
		return _underlying;
	}

	// public method that anyone can call to prevent an immenent loan liquidation
	// this is an emergency measure in case rebalance() is not called in time
	// price check is not necessary here because we are only removing LP and
	// if swap price differs it is to our benefit
	function rebalanceLoan() public nonReentrant {
		uint256 _loanHealth = loanHealth();
		require(_loanHealth <= minLoanHealth, "HLP: SAFE");
		(uint256 underlyingLp, ) = _getLPBalances();

		// remove 5% of LP to repay loan & add collateral
		uint256 newLP = (9500 * _loanHealth * underlyingLp) / 10000 / minLoanHealth;

		// remove lp
		(uint256 underlyingBalance, uint256 shortBalance) = _decreaseLpTo(newLP);

		_repay(shortBalance);
		_lend(underlyingBalance);
		emit RebalanceLoan(msg.sender, _loanHealth, loanHealth());
	}

	function _deposit(uint256 amount)
		internal
		override
		checkPrice(0)
		nonReentrant
		returns (uint256 newShares)
	{
		if (amount <= 0) return 0; // cannot deposit 0
		uint256 tvl = _getAndUpdateTVL();
		require(amount + tvl <= getMaxTvl(), "HLP: OVER_MAX_TVL");
		newShares = totalSupply() == 0 ? amount : (totalSupply() * amount) / tvl;
		_underlying.transferFrom(vault(), address(this), amount);
		_increasePosition(amount);
		emit Deposit(msg.sender, amount);
	}

	// can pass type(uint256).max to withdraw full amount
	function _withdraw(uint256 amount)
		internal
		override
		checkPrice(0)
		nonReentrant
		returns (uint256 burnShares)
	{
		if (amount == 0) return 0;
		uint256 tvl = _getAndUpdateTVL();
		if (tvl == 0) return 0;

		uint256 reserves = _underlying.balanceOf(address(this));

		// if we can not withdraw straight out of reserves
		if (reserves < amount) {
			// add .5% to withdraw amount for tx fees & slippage etc
			uint256 withdrawAmnt = amount == type(uint256).max
				? tvl
				: min(tvl, (amount * 1005) / 1000);

			// decrease current position
			withdrawAmnt = withdrawAmnt >= tvl
				? _closePosition()
				: _decreasePosition(withdrawAmnt - reserves) + reserves;

			// use the minimum of the two
			amount = min(withdrawAmnt, amount);
		}
		// grab current tvl to account for fees and slippage
		(tvl, , , , , ) = getTVL();

		// round up to keep price precision and leave less dust
		burnShares = min(((amount + 1) * totalSupply()) / tvl, totalSupply());

		_underlying.safeTransferFrom(address(this), vault(), amount);
		// require(tvl > 0, "no funds in vault");
		emit Withdraw(msg.sender, amount);
	}

	// decreases position based on current desired balance
	// ** does not rebalance remaining portfolio
	// ** may return slighly less then desired amount
	// ** make sure to update lending positions before calling this
	function _decreasePosition(uint256 amount) internal returns (uint256) {
		uint256 removeLpAmnt = _totalToLp(amount);
		(uint256 underlyingLp, ) = _getLPBalances();
		uint256 shortPosition = _getBorrowBalance();
		uint256 removeShortLp = _underlyingToShort(removeLpAmnt);

		if (removeLpAmnt >= underlyingLp || removeShortLp >= shortPosition) return _closePosition();

		// remove lp
		(uint256 availableUnderlying, uint256 shortBalance) = _decreaseLpTo(
			underlyingLp - removeLpAmnt
		);

		_repay(shortBalance);

		// this might remove less collateral than desired if we hit the limit
		// this happens when position is close to empty
		availableUnderlying += _removeCollateral(amount - availableUnderlying);
		return availableUnderlying;
	}

	// increases the position based on current desired balance
	// ** does not rebalance remaining portfolio
	function _increasePosition(uint256 amount) internal {
		if (amount < MINIMUM_LIQUIDITY) return; // avoid imprecision
		uint256 amntUnderlying = _totalToLp(amount);
		uint256 amntShort = _underlyingToShort(amntUnderlying);
		_lend(amount - amntUnderlying);
		_borrow(amntShort);
		uint256 liquidity = _addLiquidity(amntUnderlying, amntShort);
		_depositIntoFarm(liquidity);
	}

	// use the return of the function to estimate pending harvest via staticCall
	function harvest(
		HarvestSwapParms[] calldata uniParams,
		HarvestSwapParms[] calldata lendingParams
	)
		external
		onlyAuth
		checkPrice(0)
		nonReentrant
		returns (uint256[] memory farmHarvest, uint256[] memory lendHarvest)
	{
		(uint256 startTvl, , , , , ) = getTVL();
		if (uniParams.length != 0) farmHarvest = _harvestFarm(uniParams);
		if (lendingParams.length != 0) lendHarvest = _harvestLending(lendingParams);

		// compound our lp position disreguarding the borrowTarget param
		_increaseLpPosition(type(uint256).max);
		emit Harvest(startTvl);
	}

	// MANAGER + OWNER METHODS
	// Backwards compatability
	function rebalance() external pure {
		require(false, "MUST_USE_SLIPPAGE");
	}

	function rebalance(uint256 maxSlippage) external onlyAuth checkPrice(maxSlippage) nonReentrant {
		// call this first to ensure we use an updated borrowBalance when computing offset
		uint256 tvl = _getAndUpdateTVL();
		uint256 positionOffset = getPositionOffset();

		// don't rebalance unless we exceeded the threshold
		require(positionOffset > rebalanceThreshold, "HLP: REB-THRESH"); // maybe next time...

		if (tvl == 0) return;
		uint256 targetUnderlyingLP = _totalToLp(tvl);

		// add .1% room for fees
		_rebalancePosition((targetUnderlyingLP * 999) / 1000, tvl - targetUnderlyingLP);
		emit Rebalance(_shortToUnderlying(1e18), positionOffset, tvl);
	}

	function closePosition(uint256 maxSlippage) public checkPrice(maxSlippage) onlyAuth {
		_closePosition();
	}

	function _closePosition() internal returns (uint256) {
		_decreaseLpTo(0);
		uint256 shortPosition = _updateAndGetBorrowBalance();
		uint256 shortBalance = _short.balanceOf(address(this));
		if (shortPosition > shortBalance) {
			pair()._swapTokensForExactTokens(
				shortPosition - shortBalance,
				address(_underlying),
				address(_short)
			);
		} else if (shortBalance > shortPosition) {
			pair()._swapExactTokensForTokens(
				shortBalance - shortPosition,
				address(_short),
				address(_underlying)
			);
		}
		_repay(_short.balanceOf(address(this)));
		uint256 collateralBalance = _updateAndGetCollateralBalance();
		_redeem(collateralBalance);
		return _underlying.balanceOf(address(this));
	}

	function _decreaseLpTo(uint256 targetUnderlyingLP)
		internal
		returns (uint256 underlyingRemove, uint256 shortRemove)
	{
		(uint256 underlyingLp, ) = _getLPBalances();
		if (targetUnderlyingLP >= underlyingLp) return (0, 0); // nothing to withdraw
		uint256 liquidity = _getLiquidity();
		uint256 targetLiquidity = (liquidity * targetUnderlyingLP) / underlyingLp;
		uint256 removeLp = liquidity - targetLiquidity;
		uint256 liquidityBalance = pair().balanceOf(address(this));
		if (removeLp > liquidityBalance) _withdrawFromFarm(removeLp - liquidityBalance);
		return removeLp == 0 ? (0, 0) : _removeLiquidity(removeLp);
	}

	function _rebalancePosition(uint256 targetUnderlyingLP, uint256 targetCollateral) internal {
		uint256 targetBorrow = _underlyingToShort(targetUnderlyingLP);
		// we already updated tvl
		uint256 currentBorrow = _getBorrowBalance();

		// borrow funds or repay loan
		if (targetBorrow > currentBorrow) {
			// remove extra lp (we may need to remove more in order to add more collateral)
			_decreaseLpTo(
				_needUnderlying(targetUnderlyingLP, targetCollateral) > 0 ? 0 : targetUnderlyingLP
			);
			// add collateral
			_adjustCollateral(targetCollateral);
			_borrow(targetBorrow - currentBorrow);
		} else if (targetBorrow < currentBorrow) {
			// remove all of lp so we can repay loan
			_decreaseLpTo(0);
			uint256 repayAmnt = min(_short.balanceOf(address(this)), currentBorrow - targetBorrow);
			if (repayAmnt > 0) _repay(repayAmnt);
			// remove extra collateral
			_adjustCollateral(targetCollateral);
		}
		_increaseLpPosition(targetBorrow);
	}

	///////////////////////////
	//// INCREASE LP POSITION
	///////////////////////
	function _increaseLpPosition(uint256 targetBorrow) internal {
		uint256 underlyingBalance = _underlying.balanceOf(address(this));
		uint256 shortBalance = _short.balanceOf(address(this));

		// here we make sure we don't add extra lp
		(, uint256 shortLP) = _getLPBalances();

		if (targetBorrow < shortLP) return;

		uint256 addShort = min(
			(shortBalance + _underlyingToShort(underlyingBalance)) / 2,
			targetBorrow - shortLP
		);

		uint256 addUnderlying = _shortToUnderlying(addShort);

		// buy or sell underlying
		if (addUnderlying < underlyingBalance) {
			shortBalance += pair()._swapExactTokensForTokens(
				underlyingBalance - addUnderlying,
				address(_underlying),
				address(_short)
			);
			underlyingBalance = addUnderlying;
		} else if (shortBalance > addShort) {
			// swap extra tokens back (this may end up using more gas)
			underlyingBalance += pair()._swapExactTokensForTokens(
				shortBalance - addShort,
				address(_short),
				address(_underlying)
			);
			shortBalance = addShort;
		}

		// compute final lp amounts
		uint256 amntShort = shortBalance;
		uint256 amntUnderlying = _shortToUnderlying(amntShort);
		if (underlyingBalance < amntUnderlying) {
			amntUnderlying = underlyingBalance;
			amntShort = _underlyingToShort(amntUnderlying);
		}

		if (amntUnderlying == 0) return;

		// add liquidity
		// don't need to use min with underlying and short because we did oracle check
		// amounts are exact because we used swap price above
		uint256 liquidity = _addLiquidity(amntUnderlying, amntShort);
		_depositIntoFarm(liquidity);
	}

	function _needUnderlying(uint256 tragetUnderlying, uint256 targetCollateral)
		internal
		view
		returns (uint256)
	{
		uint256 collateralBalance = _getCollateralBalance();
		if (targetCollateral < collateralBalance) return 0;
		(uint256 underlyingLp, ) = _getLPBalances();
		uint256 uBalance = tragetUnderlying > underlyingLp ? tragetUnderlying - underlyingLp : 0;
		uint256 addCollateral = targetCollateral - collateralBalance;
		if (uBalance >= addCollateral) return 0;
		return addCollateral - uBalance;
	}

	// TVL

	function getMaxTvl() public view override returns (uint256) {
		return min(_maxTvl, _borrowToTotal(_oraclePriceOfShort(_maxBorrow())));
	}

	// TODO should we compute pending farm & lending rewards here?
	function _getAndUpdateTVL() internal returns (uint256 tvl) {
		uint256 collateralBalance = _updateAndGetCollateralBalance();
		uint256 shortPosition = _updateAndGetBorrowBalance();
		uint256 borrowBalance = _shortToUnderlying(shortPosition);
		uint256 shortP = _short.balanceOf(address(this));
		uint256 shortBalance = shortP == 0 ? 0 : _shortToUnderlying(shortP);
		(uint256 underlyingLp, ) = _getLPBalances();
		uint256 underlyingBalance = _underlying.balanceOf(address(this));
		tvl =
			collateralBalance +
			underlyingLp *
			2 -
			borrowBalance +
			underlyingBalance +
			shortBalance;
	}

	// for security this method should return cached value only
	// this is used by vault to track balance,
	// so this value should only be updated after oracle price check
	function balanceOfUnderlying() public view override returns (uint256) {
		return _cachedBalanceOfUnderlying;
	}

	function getTotalTVL() public view returns (uint256 tvl) {
		(tvl, , , , , ) = getTVL();
	}

	function getTVL()
		public
		view
		returns (
			uint256 tvl,
			uint256 collateralBalance,
			uint256 borrowPosition,
			uint256 borrowBalance,
			uint256 lpBalance,
			uint256 underlyingBalance
		)
	{
		collateralBalance = _getCollateralBalance();
		borrowPosition = _getBorrowBalance();
		borrowBalance = _shortToUnderlying(borrowPosition);

		uint256 shortPosition = _short.balanceOf(address(this));
		uint256 shortBalance = shortPosition == 0 ? 0 : _shortToUnderlying(shortPosition);

		(uint256 underlyingLp, uint256 shortLp) = _getLPBalances();
		lpBalance = underlyingLp + _shortToUnderlying(shortLp);
		underlyingBalance = _underlying.balanceOf(address(this));

		tvl = collateralBalance + lpBalance - borrowBalance + underlyingBalance + shortBalance;
	}

	function getPositionOffset() public view returns (uint256 positionOffset) {
		(, uint256 shortLp) = _getLPBalances();
		uint256 borrowBalance = _getBorrowBalance();
		uint256 shortBalance = shortLp + _short.balanceOf(address(this));

		if (shortBalance == borrowBalance) return 0;
		// if short lp > 0 and borrowBalance is 0 we are off by inf, returning 100% should be enough
		if (borrowBalance == 0) return 10000;

		// this is the % by which our position has moved from beeing balanced
		positionOffset = shortBalance > borrowBalance
			? ((shortBalance - borrowBalance) * BPS_ADJUST) / borrowBalance
			: ((borrowBalance - shortBalance) * BPS_ADJUST) / borrowBalance;
	}

	function getPriceOffset() public view returns (uint256 offset) {
		uint256 minPrice = _shortToUnderlying(1e18);
		uint256 maxPrice = _oraclePriceOfShort(1e18);
		(minPrice, maxPrice) = maxPrice > minPrice ? (minPrice, maxPrice) : (maxPrice, minPrice);
		offset = ((maxPrice - minPrice) * BPS_ADJUST) / maxPrice;
	}

	// UTILS

	function _totalToLp(uint256 total) internal view returns (uint256) {
		uint256 cRatio = getCollateralRatio();
		return (total * cRatio) / (BPS_ADJUST + cRatio);
	}

	function _borrowToTotal(uint256 amount) internal view returns (uint256) {
		uint256 cRatio = getCollateralRatio();
		return (amount * (BPS_ADJUST + cRatio)) / cRatio;
	}

	// this is the current uniswap price
	function _shortToUnderlying(uint256 amount) internal view returns (uint256) {
		return amount == 0 ? 0 : _quote(amount, address(_short), address(_underlying));
	}

	// this is the current uniswap price
	function _underlyingToShort(uint256 amount) internal view returns (uint256) {
		return amount == 0 ? 0 : _quote(amount, address(_underlying), address(_short));
	}

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

File 30 of 34 : CompMultiFarm.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../../interfaces/forks/IClaimReward.sol";
import "./CompoundFarm.sol";

// import "hardhat/console.sol";

abstract contract CompMultiFarm is CompoundFarm {
	// BenQi has two two token rewards
	// pid 0 is Qi token and pid 1 is AVAX (not wrapped)
	function _harvestLending(HarvestSwapParms[] calldata swapParams)
		internal
		override
		returns (uint256[] memory harvested)
	{
		// farm token on id 0
		IClaimReward(address(comptroller())).claimReward(0, payable(address(this)));
		harvested = new uint256[](1);
		harvested[0] = _farmToken.balanceOf(address(this));

		if (harvested[0] > 0) {
			_swap(lendFarmRouter(), swapParams[0], address(_farmToken), harvested[0]);
			emit HarvestedToken(address(_farmToken), harvested[0]);
		}

		// base token rewards on id 1
		IClaimReward(address(comptroller())).claimReward(1, payable(address(this)));

		uint256 avaxBalance = address(this).balance;
		if (avaxBalance > 0) {
			IWETH(address(short())).deposit{ value: avaxBalance }();
			emit HarvestedToken(address(short()), avaxBalance);
		}
	}
}

File 31 of 34 : Compound.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../../interfaces/compound/ICTokenInterfaces.sol";
import "../../interfaces/compound/IComptroller.sol";
import "../../interfaces/compound/ICompPriceOracle.sol";
import "../../interfaces/compound/IComptroller.sol";

import "../../mixins/ICompound.sol";

// import "hardhat/console.sol";

abstract contract Compound is ICompound {
	using SafeERC20 for IERC20;

	ICTokenErc20 private _cTokenLend;
	ICTokenErc20 private _cTokenBorrow;

	IComptroller private _comptroller;
	ICompPriceOracle private _oracle;

	function __Compound_init_(
		address comptroller_,
		address cTokenLend_,
		address cTokenBorrow_
	) internal {
		_cTokenLend = ICTokenErc20(cTokenLend_);
		_cTokenBorrow = ICTokenErc20(cTokenBorrow_);
		_comptroller = IComptroller(comptroller_);
		_oracle = ICompPriceOracle(ComptrollerV1Storage(comptroller_).oracle());
		_enterMarket();
	}

	function _addLendingApprovals() internal override {
		// ensure USDC approval - assume we trust USDC
		underlying().safeApprove(address(_cTokenLend), type(uint256).max);
		short().safeApprove(address(_cTokenBorrow), type(uint256).max);
	}

	function cTokenLend() public view override returns (ICTokenErc20) {
		return _cTokenLend;
	}

	function cTokenBorrow() public view override returns (ICTokenErc20) {
		return _cTokenBorrow;
	}

	function oracle() public view override returns (ICompPriceOracle) {
		return _oracle;
	}

	function comptroller() public view override returns (IComptroller) {
		return _comptroller;
	}
}

File 32 of 34 : CompoundFarm.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import "../../mixins/ICompound.sol";
import "../../mixins/IFarmable.sol";
import "../../interfaces/uniswap/IUniswapV2Pair.sol";

// import "hardhat/console.sol";

abstract contract CompoundFarm is ICompound, IFarmable {
	using SafeERC20 for IERC20;

	IUniswapV2Router01 private _router; // use router here
	IERC20 _farmToken;

	function __CompoundFarm_init_(address router_, address token_) internal initializer {
		_farmToken = IERC20(token_);
		_router = IUniswapV2Router01(router_);
		_farmToken.safeApprove(address(_router), type(uint256).max);
	}

	function lendFarmRouter() public view override returns (IUniswapV2Router01) {
		return _router;
	}

	function _harvestLending(HarvestSwapParms[] calldata swapParams)
		internal
		virtual
		override
		returns (uint256[] memory harvested)
	{
		// comp token rewards
		ICTokenErc20[] memory cTokens = new ICTokenErc20[](2);
		cTokens[0] = cTokenLend();
		cTokens[1] = cTokenBorrow();
		comptroller().claimComp(address(this), cTokens);

		harvested = new uint256[](1);
		harvested[0] = _farmToken.balanceOf(address(this));
		if (harvested[0] == 0) return harvested;

		if (address(_router) != address(0))
			_swap(_router, swapParams[0], address(_farmToken), harvested[0]);
		emit HarvestedToken(address(_farmToken), harvested[0]);
	}
}

File 33 of 34 : MasterChefFarm.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import { IMasterChef } from "../../interfaces/uniswap/IStakingRewards.sol";
import "../../interfaces/uniswap/IUniswapV2Pair.sol";

import "../../mixins/IFarmableLp.sol";
import "../../mixins/IUniLp.sol";
import "../../interfaces/uniswap/IWETH.sol";

// import "hardhat/console.sol";

abstract contract MasterChefFarm is IFarmableLp, IUniLp {
	using SafeERC20 for IERC20;

	IMasterChef private _farm;
	IUniswapV2Router01 private _router;
	IERC20 private _farmToken;
	IUniswapV2Pair private _pair;
	uint256 private _farmId;

	function __MasterChefFarm_init_(
		address pair_,
		address farm_,
		address router_,
		address farmToken_,
		uint256 farmPid_
	) internal initializer {
		_farm = IMasterChef(farm_);
		_router = IUniswapV2Router01(router_);
		_farmToken = IERC20(farmToken_);
		_pair = IUniswapV2Pair(pair_);
		_farmId = farmPid_;
	}

	// assumption that _router and _farm are trusted
	function _addFarmApprovals() internal override {
		IERC20(address(_pair)).safeApprove(address(_farm), type(uint256).max);
		if (_farmToken.allowance(address(this), address(_router)) == 0)
			_farmToken.safeApprove(address(_router), type(uint256).max);
	}

	function farmRouter() public view override returns (IUniswapV2Router01) {
		return _router;
	}

	function pair() public view override returns (IUniswapV2Pair) {
		return _pair;
	}

	function _withdrawFromFarm(uint256 amount) internal override {
		_farm.withdraw(_farmId, amount);
	}

	function _depositIntoFarm(uint256 amount) internal override {
		_farm.deposit(_farmId, amount);
	}

	function _harvestFarm(HarvestSwapParms[] calldata swapParams)
		internal
		override
		returns (uint256[] memory harvested)
	{
		_farm.deposit(_farmId, 0);
		harvested = new uint256[](1);
		harvested[0] = _farmToken.balanceOf(address(this));
		if (harvested[0] == 0) return harvested;

		_swap(_router, swapParams[0], address(_farmToken), harvested[0]);
		emit HarvestedToken(address(_farmToken), harvested[0]);

		uint256 avaxBalance = address(this).balance;
		if (avaxBalance > 0) {
			IWETH(address(short())).deposit{ value: avaxBalance }();
			emit HarvestedToken(address(short()), avaxBalance);
		}
	}

	function _getFarmLp() internal view override returns (uint256) {
		(uint256 lp, ) = _farm.userInfo(_farmId, address(this));
		return lp;
	}

	function _getLiquidity() internal view override returns (uint256) {
		uint256 farmLp = _getFarmLp();
		uint256 poolLp = _pair.balanceOf(address(this));
		return farmLp + poolLp;
	}
}

File 34 of 34 : USDCmovrSOLARwell.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../HedgedLP.sol";
import "../adapters/Compound.sol";
import "../adapters/MasterChefFarm.sol";
import "../adapters/CompMultiFarm.sol";

// import "hardhat/console.sol";

contract USDCmovrSOLARwell is HedgedLP, Compound, CompMultiFarm, MasterChefFarm {
	// HedgedLP should allways be intialized last
	constructor(Config memory config) BaseStrategy(config.vault, config.symbol, config.name) {
		__MasterChefFarm_init_(
			config.uniPair,
			config.uniFarm,
			config.farmRouter,
			config.farmToken,
			config.farmId
		);

		__Compound_init_(config.comptroller, config.cTokenLend, config.cTokenBorrow);

		__CompoundFarm_init_(config.lendRewardRouter, config.lendRewardToken);

		__HedgedLP_init_(config.underlying, config.short, config.maxTvl);
	}

	// if borrow token is treated as ETH
	function _isBase(uint8) internal pure override(ICompound) returns (bool) {
		return true;
	}
}

Settings
{
  "evmVersion": "london",
  "libraries": {
    "src/strategies/implementations/USDCmovrSOLARwell.sol:USDCmovrSOLARwell": {
      "UniUtils": "0x92dBEa6fa85A1cd839b604D1F2852ABfb7Fa2897"
    }
  },
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 1
  },
  "remappings": [],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract ABI

[{"inputs":[{"components":[{"internalType":"address","name":"underlying","type":"address"},{"internalType":"address","name":"short","type":"address"},{"internalType":"address","name":"cTokenLend","type":"address"},{"internalType":"address","name":"cTokenBorrow","type":"address"},{"internalType":"address","name":"uniPair","type":"address"},{"internalType":"address","name":"uniFarm","type":"address"},{"internalType":"address","name":"farmToken","type":"address"},{"internalType":"uint256","name":"farmId","type":"uint256"},{"internalType":"address","name":"farmRouter","type":"address"},{"internalType":"address","name":"comptroller","type":"address"},{"internalType":"address","name":"lendRewardRouter","type":"address"},{"internalType":"address","name":"lendRewardToken","type":"address"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"maxTvl","type":"uint256"}],"internalType":"struct Config","name":"config","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"contract IERC20[]","name":"tokens","type":"address[]"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"harvested","type":"uint256"}],"name":"Harvest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"HarvestedToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"isManager","type":"bool"}],"name":"ManagerUpdate","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":false,"internalType":"uint256","name":"shortPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tvlBeforeRebalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"positionOffset","type":"uint256"}],"name":"Rebalance","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"startLoanHealth","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"updatedLoanHealth","type":"uint256"}],"name":"RebalanceLoan","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"loanHealth","type":"uint256"}],"name":"SetMaxPriceMismatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"loanHealth","type":"uint256"}],"name":"SetMaxTvl","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"loanHealth","type":"uint256"}],"name":"SetRebalanceThreshold","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"collateralRatio","type":"uint256"}],"name":"SetSafeCollateralRaio","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"}],"name":"VaultUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"loanHealth","type":"uint256"}],"name":"setMinLoanHealth","type":"event"},{"inputs":[],"name":"BASE_UNIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cTokenBorrow","outputs":[{"internalType":"contract ICTokenErc20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cTokenLend","outputs":[{"internalType":"contract ICTokenErc20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxSlippage","type":"uint256"}],"name":"closePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"comptroller","outputs":[{"internalType":"contract IComptroller","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"farmRouter","outputs":[{"internalType":"contract IUniswapV2Router01","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCollateralRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxTvl","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPositionOffset","outputs":[{"internalType":"uint256","name":"positionOffset","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPriceOffset","outputs":[{"internalType":"uint256","name":"offset","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPricePerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTVL","outputs":[{"internalType":"uint256","name":"tvl","type":"uint256"},{"internalType":"uint256","name":"collateralBalance","type":"uint256"},{"internalType":"uint256","name":"borrowPosition","type":"uint256"},{"internalType":"uint256","name":"borrowBalance","type":"uint256"},{"internalType":"uint256","name":"lpBalance","type":"uint256"},{"internalType":"uint256","name":"underlyingBalance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalTVL","outputs":[{"internalType":"uint256","name":"tvl","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUnderlyingShortReserves","outputs":[{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct HarvestSwapParms[]","name":"uniParams","type":"tuple[]"},{"components":[{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct HarvestSwapParms[]","name":"lendingParams","type":"tuple[]"}],"name":"harvest","outputs":[{"internalType":"uint256[]","name":"farmHarvest","type":"uint256[]"},{"internalType":"uint256[]","name":"lendHarvest","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isCEther","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"isIntialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"isManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastHarvest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lendFarmRouter","outputs":[{"internalType":"contract IUniswapV2Router01","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"loanHealth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPriceMismatch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minLoanHealth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"errCode","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"contract ICompPriceOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pair","outputs":[{"internalType":"contract IUniswapV2Pair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebalance","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxSlippage","type":"uint256"}],"name":"rebalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rebalanceLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rebalanceThreshold","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"redeemUnderlying","outputs":[{"internalType":"uint256","name":"errCode","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"safeCollateralRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"bool","name":"_isManager","type":"bool"}],"name":"setManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxPriceMismatch_","type":"uint256"}],"name":"setMaxPriceMismatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxTvl_","type":"uint256"}],"name":"setMaxTvl","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minLoanHealth_","type":"uint256"}],"name":"setMinLoanHeath","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"rebalanceThreshold_","type":"uint16"}],"name":"setRebalanceThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"safeCollateralRatio_","type":"uint256"}],"name":"setSafeCollateralRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"}],"name":"setVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"short","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60806040526096600c55670e6ed27d66680000600d55600e805461ffff19166101901790556120d06010553480156200003757600080fd5b506040516200604f3803806200604f8339810160408190526200005a9162000e03565b6101808101516101a08201516101c0830151620000773362000147565b60018055600480546001600160a01b0319166001600160a01b0385161790558151620000ab90600790602085019062000c24565b508051620000c190600690602084019062000c24565b505050608082015160a083015161010084015160c085015160e0860151620000ea955062000197565b6200010a816101200151826040015183606001516200021c60201b60201c565b62000126816101400151826101600151620002e860201b60201c565b805160208201516101e0830151620001409291906200035d565b5062001330565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60025460ff1615620001c65760405162461bcd60e51b8152600401620001bd9062000fa5565b60405180910390fd5b601880546001600160a01b03199081166001600160a01b039687161790915560198054821694861694909417909355601a8054841692851692909217909155601b80549092169390921692909217909155601c55565b601280546001600160a01b038085166001600160a01b03199283161790925560138054848416908316179055601480549286169290911682179055604080516307dc0d1d60e41b81529051637dc0d1d0916004808201926020929091908290030181865afa15801562000293573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002b9919062000fca565b601580546001600160a01b0319166001600160a01b0392909216919091179055620002e36200050b565b505050565b60025460ff16156200030e5760405162461bcd60e51b8152600401620001bd9062000fa5565b601780546001600160a01b03199081166001600160a01b0384811691821790935560168054909216928516928317909155620003599160001962000607602090811b62001a3317901c565b5050565b60025460ff1615620003835760405162461bcd60e51b8152600401620001bd9062000fa5565b600a80546001600160a01b038086166001600160a01b03199283168117909355600b805491861691909216179055620003cf903060001962001a3362000607602090811b91909117901c565b620003d962000752565b620003e690600a620010fd565b600955620003f481620007c8565b7f5ceaf8b7b0d35f85ef4df565057cd318e70d9f8681f89425a2d5e09c1c70a7f9600d546040516200042891815260200190565b60405180910390a17f3e87fa3180c1babd204ce79375729d7a6694a2d2f0fb3e250f9138488ed066bb600c546040516200046491815260200190565b60405180910390a1600e5460405161ffff90911681527f36c98a54ec4f90fe58a67bf25cfc1691dbd53639eee3513536d83e8d34fb0a9b9060200160405180910390a17f4812bd1abd1ad4ea905335e3af941ec67d6d51ecb36ab58f23af0af081aac57b601054604051620004db91815260200190565b60405180910390a1620004ed62000870565b620004f7620008de565b50506002805461ff00191661010017905550565b6040805160028082526060820183526000926020830190803683375050601254919250506001600160a01b0316816000815181106200054e576200054e6200110e565b6001600160a01b03928316602091820292909201015260135416816001815181106200057e576200057e6200110e565b6001600160a01b039283166020918202929092010152601454604051631853304760e31b815291169063c299823890620005bd90849060040162001124565b6000604051808303816000875af1158015620005dd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262000359919081019062001173565b801580620006865750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e9062000640903090869060040162001223565b602060405180830381865afa1580156200065e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200068491906200123d565b155b620006fa5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401620001bd565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b17909152620002e3918591620009ba16565b600a546040805163313ce56760e01b815290516000926001600160a01b03169163313ce5679160048083019260209291908290030181865afa1580156200079d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007c3919062001257565b905090565b6000546001600160a01b0316331480620007f657503360009081526008602052604090205460ff1615156001145b620008355760405162461bcd60e51b815260206004820152600e60248201526d0a6e8e4c2e874409c9ebe82aaa8960931b6044820152606401620001bd565b600f8190556040518181527f13d3e08a22782064d3062f92ff1101a623b60e3bf91f236b5d1e9fdddfc12a129060200160405180910390a150565b601254620008b5906001600160a01b031660001962000897600a546001600160a01b031690565b6001600160a01b03166200060760201b62001a33179092919060201c565b601354620008dc906001600160a01b031660001962000897600b546001600160a01b031690565b565b601854601b546200090b916001600160a01b03918216911660001962000607602090811b62001a3317901c565b601a54601954604051636eb1769f60e11b81526001600160a01b039283169263dd62ed3e92620009449230929091169060040162001223565b602060405180830381865afa15801562000962573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200098891906200123d565b620008dc57601954601a54620008dc916001600160a01b03918216911660001962000607602090811b62001a3317901c565b600062000a16826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031662000a9860201b62001b73179092919060201c565b805190915015620002e3578080602001905181019062000a3791906200127c565b620002e35760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401620001bd565b606062000aa9848460008562000ab3565b90505b9392505050565b60608247101562000b165760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401620001bd565b843b62000b665760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620001bd565b600080866001600160a01b0316858760405162000b849190620012a0565b60006040518083038185875af1925050503d806000811462000bc3576040519150601f19603f3d011682016040523d82523d6000602084013e62000bc8565b606091505b50909250905062000bdb82828662000be6565b979650505050505050565b6060831562000bf757508162000aac565b82511562000c085782518084602001fd5b8160405162461bcd60e51b8152600401620001bd9190620012be565b82805462000c3290620012f3565b90600052602060002090601f01602090048101928262000c56576000855562000ca1565b82601f1062000c7157805160ff191683800117855562000ca1565b8280016001018555821562000ca1579182015b8281111562000ca157825182559160200191906001019062000c84565b5062000caf92915062000cb3565b5090565b5b8082111562000caf576000815560010162000cb4565b634e487b7160e01b600052604160045260246000fd5b60405161020081016001600160401b038111828210171562000d065762000d0662000cca565b60405290565b604051601f8201601f191681016001600160401b038111828210171562000d375762000d3762000cca565b604052919050565b80516001600160a01b038116811462000d5757600080fd5b919050565b60005b8381101562000d7957818101518382015260200162000d5f565b8381111562000d89576000848401525b50505050565b600082601f83011262000da157600080fd5b81516001600160401b0381111562000dbd5762000dbd62000cca565b62000dd2601f8201601f191660200162000d0c565b81815284602083860101111562000de857600080fd5b62000dfb82602083016020870162000d5c565b949350505050565b60006020828403121562000e1657600080fd5b81516001600160401b038082111562000e2e57600080fd5b90830190610200828603121562000e4457600080fd5b62000e4e62000ce0565b62000e598362000d3f565b815262000e696020840162000d3f565b602082015262000e7c6040840162000d3f565b604082015262000e8f6060840162000d3f565b606082015262000ea26080840162000d3f565b608082015262000eb560a0840162000d3f565b60a082015262000ec860c0840162000d3f565b60c082015260e083015160e082015261010062000ee781850162000d3f565b9082015261012062000efb84820162000d3f565b9082015261014062000f0f84820162000d3f565b9082015261016062000f2384820162000d3f565b9082015261018062000f3784820162000d3f565b908201526101a0838101518381111562000f5057600080fd5b62000f5e8882870162000d8f565b8284015250506101c0808401518381111562000f7957600080fd5b62000f878882870162000d8f565b91830191909152506101e09283015192810192909252509392505050565b6020808252600b908201526a125392551250531256915160aa1b604082015260600190565b60006020828403121562000fdd57600080fd5b62000aac8262000d3f565b634e487b7160e01b600052601160045260246000fd5b600181815b808511156200103f57816000190482111562001023576200102362000fe8565b808516156200103157918102915b93841c939080029062001003565b509250929050565b6000826200105857506001620010f7565b816200106757506000620010f7565b81600181146200108057600281146200108b57620010ab565b6001915050620010f7565b60ff8411156200109f576200109f62000fe8565b50506001821b620010f7565b5060208310610133831016604e8410600b8410161715620010d0575081810a620010f7565b620010dc838362000ffe565b8060001904821115620010f357620010f362000fe8565b0290505b92915050565b600062000aac60ff84168362001047565b634e487b7160e01b600052603260045260246000fd5b6020808252825182820181905260009190848201906040850190845b81811015620011675783516001600160a01b03168352928401929184019160010162001140565b50909695505050505050565b600060208083850312156200118757600080fd5b82516001600160401b03808211156200119f57600080fd5b818501915085601f830112620011b457600080fd5b815181811115620011c957620011c962000cca565b8060051b9150620011dc84830162000d0c565b8181529183018401918481019088841115620011f757600080fd5b938501935b838510156200121757845182529385019390850190620011fc565b98975050505050505050565b6001600160a01b0392831681529116602082015260400190565b6000602082840312156200125057600080fd5b5051919050565b6000602082840312156200126a57600080fd5b815160ff8116811462000aac57600080fd5b6000602082840312156200128f57600080fd5b8151801515811462000aac57600080fd5b60008251620012b481846020870162000d5c565b9190910192915050565b6020815260008251806020840152620012df81604085016020870162000d5c565b601f01601f19169190910160400192915050565b600181811c908216806200130857607f821691505b602082108114156200132a57634e487b7160e01b600052602260045260246000fd5b50919050565b614d0f80620013406000396000f3fe60806040526004361061025e5760003560e01c806306fdde031461026a5780630c021ae5146102955780630d55046c146102b85780630e962f00146102df57806314b0750b146102f55780631585e0b61461031757806318160ddd14610337578063313ce5671461034c578063358d6a041461037357806338bea4cb146103885780633af9e6691461039d5780633bf295cc146103bd5780633d68175c146103d25780633dcf1342146103e75780633dfe9f6a146104075780634880f9511461043557806354fd4d501461044a5780635fe3b5671461045f57806366be952d146104745780636817031b1461048a5780636f307dc3146104aa578063711326ce146104bf578063715018a6146104df5780637d7c2a1c146104f45780637da64483146105095780637dc0d1d0146105335780637ffe28e314610548578063852a12e31461055d57806386aceac71461057d5780638da5cb5b1461059357806395d89b41146105a857806397b3fcaa146105bd578063a0712d68146105ff578063a126d6011461061f578063a52602b91461063f578063a5e90eee14610654578063a8aa1b3114610674578063ac784ddc14610689578063b580a1281461069d578063c2946e24146106b2578063cb50087f146106c7578063cd377c53146106e7578063d539fe4b146106fc578063de747e5a14610711578063f1a392da14610731578063f20aea0f14610747578063f2fde38b14610775578063f3ae241514610795578063f4993018146107ce578063f9e40ac4146107ee578063fbfa77cf14610811578063fd6bac7014610826578063fec18b3a1461083b57600080fd5b3661026557005b600080fd5b34801561027657600080fd5b5061027f610850565b60405161028c91906144e0565b60405180910390f35b3480156102a157600080fd5b506102aa6108de565b60405190815260200161028c565b3480156102c457600080fd5b506019546001600160a01b03165b60405161028c91906144f3565b3480156102eb57600080fd5b506102aa60095481565b34801561030157600080fd5b50610315610310366004614507565b6108f3565b005b34801561032357600080fd5b50610315610332366004614507565b610967565b34801561034357600080fd5b506005546102aa565b34801561035857600080fd5b506103616109d1565b60405160ff909116815260200161028c565b34801561037f57600080fd5b506102aa610a44565b34801561039457600080fd5b506102d2610a69565b3480156103a957600080fd5b506102aa6103b8366004614535565b610a78565b3480156103c957600080fd5b506102aa610a89565b3480156103de57600080fd5b506102aa610b00565b3480156103f357600080fd5b50610315610402366004614596565b610b41565b34801561041357600080fd5b50600e546104229061ffff1681565b60405161ffff909116815260200161028c565b34801561044157600080fd5b506011546102aa565b34801561045657600080fd5b506102aa600181565b34801561046b57600080fd5b506102d2610ca8565b34801561048057600080fd5b506102aa600c5481565b34801561049657600080fd5b506103156104a5366004614535565b610cb7565b3480156104b657600080fd5b506102d2610d30565b3480156104cb57600080fd5b506103156104da366004614507565b610d3f565b3480156104eb57600080fd5b50610315610e31565b34801561050057600080fd5b50610315610e6c565b34801561051557600080fd5b506002546105239060ff1681565b604051901515815260200161028c565b34801561053f57600080fd5b506102d2610ea8565b34801561055457600080fd5b50610315610eb7565b34801561056957600080fd5b506102aa610578366004614507565b610fdb565b34801561058957600080fd5b506102aa600d5481565b34801561059f57600080fd5b506102d2611042565b3480156105b457600080fd5b5061027f611051565b3480156105c957600080fd5b506105d261105e565b604080519687526020870195909552938501929092526060840152608083015260a082015260c00161028c565b34801561060b57600080fd5b506102aa61061a366004614507565b6111e7565b34801561062b57600080fd5b5061031561063a366004614507565b611240565b34801561064b57600080fd5b506102d26112e9565b34801561066057600080fd5b5061031561066f3660046145f8565b6112f8565b34801561068057600080fd5b506102d2611386565b34801561069557600080fd5b506000610523565b3480156106a957600080fd5b506102aa611395565b3480156106be57600080fd5b506102aa611498565b3480156106d357600080fd5b506103156106e2366004614507565b611502565b3480156106f357600080fd5b506102aa61158e565b34801561070857600080fd5b506010546102aa565b34801561071d57600080fd5b5061031561072c366004614631565b6115be565b34801561073d57600080fd5b506102aa60035481565b34801561075357600080fd5b50610767610762366004614655565b611631565b60405161028c9291906146fb565b34801561078157600080fd5b50610315610790366004614535565b61177a565b3480156107a157600080fd5b506105236107b0366004614535565b6001600160a01b031660009081526008602052604090205460ff1690565b3480156107da57600080fd5b506103156107e9366004614507565b61181a565b3480156107fa57600080fd5b506108036119cf565b60405161028c929190614729565b34801561081d57600080fd5b506102d2611a06565b34801561083257600080fd5b506102d2611a15565b34801561084757600080fd5b506102d2611a24565b6006805461085d90614737565b80601f016020809104026020016040519081016040528092919081815260200182805461088990614737565b80156108d65780601f106108ab576101008083540402835291602001916108d6565b820191906000526020600020905b8154815290600101906020018083116108b957829003601f168201915b505050505081565b60006108e861105e565b509395945050505050565b336108fc611042565b6001600160a01b03161461092b5760405162461bcd60e51b81526004016109229061476c565b60405180910390fd5b60108190556040518181527f4812bd1abd1ad4ea905335e3af941ec67d6d51ecb36ab58f23af0af081aac57b906020015b60405180910390a150565b33610970611042565b6001600160a01b0316146109965760405162461bcd60e51b81526004016109229061476c565b600d8190556040518181527f5ceaf8b7b0d35f85ef4df565057cd318e70d9f8681f89425a2d5e09c1c70a7f99060200161095c565b60055490565b600a546040805163313ce56760e01b815290516000926001600160a01b03169163313ce5679160048083019260209291908290030181865afa158015610a1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a3f91906147a1565b905090565b6000610a3f600f54610a64610a5f610a5a611b8c565b611bf7565b611d03565b611d31565b600b546001600160a01b031690565b6000610a8360115490565b92915050565b600080610a97610a5a611d47565b905080610aa75761271091505090565b6000610ab1611d99565b90506000610abd611e8e565b610acf84670de0b6b3a76400006147da565b610ad991906147f9565b905080610aee83670de0b6b3a76400006147da565b610af891906147f9565b935050505090565b600080610b0c60115490565b905060055460001415610b2157505060095490565b600554600954610b3190836147da565b610b3b91906147f9565b91505090565b610b49611a06565b6001600160a01b0316336001600160a01b031614610b795760405162461bcd60e51b81526004016109229061481b565b60005b81811015610c4f576000838383818110610b9857610b98614846565b9050602002016020810190610bad9190614535565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610bdd91906144f3565b602060405180830381865afa158015610bfa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1e919061485c565b90508015610c3a57610c3a6001600160a01b0383168783611f14565b50508080610c4790614875565b915050610b7c565b504715610c6057610c603347611f33565b826001600160a01b03167f2b06144d62a3a5785ec284ed392b3d106610ae2ce7af270417c4ca38277571048383604051610c9b929190614890565b60405180910390a2505050565b6014546001600160a01b031690565b33610cc0611042565b6001600160a01b031614610ce65760405162461bcd60e51b81526004016109229061476c565b600480546001600160a01b0319166001600160a01b0383169081179091556040517fdabed91cf547ed2ee836d5787bae42fc3bca488166c65791051105490fbcf7ca90600090a250565b600a546001600160a01b031690565b610d47611042565b6001600160a01b0316336001600160a01b03161480610d7a57503360009081526008602052604090205460ff1615156001145b610d965760405162461bcd60e51b8152600401610922906148de565b610d9e611042565b6001600160a01b0316336001600160a01b03161480610dbf57508061012c10155b610dfc5760405162461bcd60e51b815260206004820152600e60248201526d484c503a20544f4f204c4152474560901b6044820152606401610922565b600c8190556040518181527f3e87fa3180c1babd204ce79375729d7a6694a2d2f0fb3e250f9138488ed066bb9060200161095c565b33610e3a611042565b6001600160a01b031614610e605760405162461bcd60e51b81526004016109229061476c565b610e6a6000611f84565b565b60405162461bcd60e51b81526020600482015260116024820152704d5553545f5553455f534c49505041474560781b6044820152606401610922565b6015546001600160a01b031690565b60026001541415610eda5760405162461bcd60e51b815260040161092290614906565b60026001556000610ee9610a89565b9050600d54811115610f295760405162461bcd60e51b8152602060048201526009602482015268484c503a205341464560b81b6044820152606401610922565b6000610f33611fd4565b5090506000600d54612710838561251c610f4d91906147da565b610f5791906147da565b610f6191906147f9565b610f6b91906147f9565b9050600080610f7983612095565b91509150610f86816121a3565b610f8f8261225a565b337fdacd0a02d11128b25d6c3de23e91f71aa9dd5620c6f5c69f35a18d15e116846886610fba610a89565b604051610fc8929190614729565b60405180910390a2505060018055505050565b6000610fe5611a06565b6001600160a01b0316336001600160a01b0316146110155760405162461bcd60e51b81526004016109229061481b565b60006110208361228f565b90508060056000828254611034919061493d565b909155506000949350505050565b6000546001600160a01b031690565b6007805461085d90614737565b60008060008060008061106f611d99565b9450611079611d47565b9350611084846124be565b600b546040516370a0823160e01b81529194506000916001600160a01b03909116906370a08231906110ba9030906004016144f3565b602060405180830381865afa1580156110d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110fb919061485c565b9050600081156111135761110e826124be565b611116565b60005b9050600080611123611fd4565b91509150611130816124be565b61113a9083614954565b600a546040516370a0823160e01b81529197506001600160a01b0316906370a082319061116b9030906004016144f3565b602060405180830381865afa158015611188573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ac919061485c565b94508285886111bb898d614954565b6111c5919061493d565b6111cf9190614954565b6111d99190614954565b995050505050909192939495565b60006111f1611a06565b6001600160a01b0316336001600160a01b0316146112215760405162461bcd60e51b81526004016109229061481b565b600061122c836124f1565b905080600560008282546110349190614954565b808061124b5750600c545b80611254611498565b11156112725760405162461bcd60e51b81526004016109229061496c565b61127a611042565b6001600160a01b0316336001600160a01b031614806112ad57503360009081526008602052604090205460ff1615156001145b6112c95760405162461bcd60e51b8152600401610922906148de565b6112d16126b0565b506112da61105e565b50505060119290925550505050565b6012546001600160a01b031690565b33611301611042565b6001600160a01b0316146113275760405162461bcd60e51b81526004016109229061476c565b6001600160a01b038216600081815260086020908152604091829020805460ff191685151590811790915591519182527f2458f684567d238b66deaa0126265bf3becabda0caaab7ebdda6b1794614a2d3910160405180910390a25050565b601b546001600160a01b031690565b6000806113a0611fd4565b91505060006113ad611d47565b600b546040516370a0823160e01b81529192506000916001600160a01b03909116906370a08231906113e39030906004016144f3565b602060405180830381865afa158015611400573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611424919061485c565b61142e9084614954565b905081811415611442576000935050505090565b8161145257612710935050505090565b8181116114805781612710611467838361493d565b61147191906147da565b61147b91906147f9565b610af8565b8161271061148e828461493d565b610aee91906147da565b6000806114ac670de0b6b3a76400006124be565b905060006114c1670de0b6b3a7640000611bf7565b90508181116114d15780826114d4565b81815b9092509050806127106114e7848361493d565b6114f191906147da565b6114fb91906147f9565b9250505090565b61150a611042565b6001600160a01b0316336001600160a01b0316148061153d57503360009081526008602052604090205460ff1615156001145b6115595760405162461bcd60e51b8152600401610922906148de565b600f8190556040518181527f13d3e08a22782064d3062f92ff1101a623b60e3bf91f236b5d1e9fdddfc12a129060200161095c565b6000670de0b6b3a76400006115a260105490565b6115aa611e8e565b6115b491906147da565b610a3f91906147f9565b336115c7611042565b6001600160a01b0316146115ed5760405162461bcd60e51b81526004016109229061476c565b600e805461ffff191661ffff83169081179091556040519081527f36c98a54ec4f90fe58a67bf25cfc1691dbd53639eee3513536d83e8d34fb0a9b9060200161095c565b60608061163c611042565b6001600160a01b0316336001600160a01b0316148061166f57503360009081526008602052604090205460ff1615156001145b61168b5760405162461bcd60e51b8152600401610922906148de565b600c5480611697611498565b11156116b55760405162461bcd60e51b81526004016109229061496c565b600260015414156116d85760405162461bcd60e51b815260040161092290614906565b600260015560006116e761105e565b5093945050891592506117049150505761170188886128c9565b93505b8415611717576117148686612b72565b92505b611722600019612de0565b6040518181527f80f97f878e16410266694f134ddf012f2be424f54f8b5cafa107eccc51d00d589060200160405180910390a1506001805561176261105e565b50505060119290925550929791965090945050505050565b33611783611042565b6001600160a01b0316146117a95760405162461bcd60e51b81526004016109229061476c565b6001600160a01b03811661180e5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610922565b61181781611f84565b50565b611822611042565b6001600160a01b0316336001600160a01b0316148061185557503360009081526008602052604090205460ff1615156001145b6118715760405162461bcd60e51b8152600401610922906148de565b808061187c5750600c545b80611885611498565b11156118a35760405162461bcd60e51b81526004016109229061496c565b600260015414156118c65760405162461bcd60e51b815260040161092290614906565b600260015560006118d5612fe1565b905060006118e1611395565b600e5490915061ffff16811161192b5760405162461bcd60e51b815260206004820152600f60248201526e09098a07440a48a845aa890a48aa69608b1b6044820152606401610922565b816119375750506119c3565b60006119428361315f565b905061196f6103e8611956836103e76147da565b61196091906147f9565b61196a838661493d565b613182565b7fe0b4077da7dfa5015ff10fab6a214f37acc1b23d745f30336942d17e07848c6b6119a1670de0b6b3a76400006124be565b6040805191825260208201859052810185905260600160405180910390a15050505b600180556112da61105e565b6000806119fd6119dd610d30565b6119e5610a69565b6119ed611386565b6001600160a01b031691906132ad565b90939092509050565b6004546001600160a01b031690565b6013546001600160a01b031690565b6016546001600160a01b031690565b801580611aad5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015611a87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aab919061485c565b155b611b185760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610922565b611b6e8363095ea7b360e01b8484604051602401611b37929190614999565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261336d565b505050565b6060611b82848460008561343f565b90505b9392505050565b6000611b96611a15565b6001600160a01b0316633b1d21a26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a3f919061485c565b6000611c01610ea8565b6001600160a01b031663fc57d4df611c176112e9565b6040518263ffffffff1660e01b8152600401611c3391906144f3565b602060405180830381865afa158015611c50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c74919061485c565b611c7c610ea8565b6001600160a01b031663fc57d4df611c92611a15565b6040518263ffffffff1660e01b8152600401611cae91906144f3565b602060405180830381865afa158015611ccb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cef919061485c565b611cf990846147da565b610a8391906147f9565b600080611d0e61158e565b905080611d1d81612710614954565b611d2790856147da565b611b8591906147f9565b6000818310611d405781611b85565b5090919050565b6000611d51611a15565b6001600160a01b03166395dd9193306040518263ffffffff1660e01b8152600401611d7c91906144f3565b602060405180830381865afa158015611bd3573d6000803e3d6000fd5b600080611da46112e9565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611dcf91906144f3565b602060405180830381865afa158015611dec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e10919061485c565b9050670de0b6b3a7640000611e236112e9565b6001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e84919061485c565b610b3190836147da565b600080611e99610ca8565b6001600160a01b0316638e8f294b611eaf6112e9565b6040518263ffffffff1660e01b8152600401611ecb91906144f3565b606060405180830381865afa158015611ee8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f0c91906149b2565b509392505050565b611b6e8363a9059cbb60e01b8484604051602401611b37929190614999565b600080600080600085875af1905080611b6e5760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610922565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000806000611fe1613567565b9050600080611fee6119cf565b915091506000611ffc611386565b6001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612039573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061205d919061485c565b90508061206a85856147da565b61207491906147f9565b95508061208185846147da565b61208b91906147f9565b9450505050509091565b60008060006120a2611fd4565b5090508084106120b85750600093849350915050565b60006120c2613567565b90506000826120d187846147da565b6120db91906147f9565b905060006120e9828461493d565b905060006120f5611386565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161212091906144f3565b602060405180830381865afa15801561213d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612161919061485c565b90508082111561217d5761217d612178828461493d565b6135f5565b81156121915761218c8261365d565b612195565b6000805b965096505050505050915091565b6121ab610a69565b6001600160a01b0316632e1a7d4d826040518263ffffffff1660e01b81526004016121d891815260200190565b600060405180830381600087803b1580156121f257600080fd5b505af1158015612206573d6000803e3d6000fd5b5050505061181781613753565b6020604051808303816000875af1158015612232573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612256919061485c565b5050565b6122626112e9565b6001600160a01b031663a0712d68826040518263ffffffff1660e01b815260040161221391815260200190565b6000600c548061229d611498565b11156122bb5760405162461bcd60e51b81526004016109229061496c565b600260015414156122de5760405162461bcd60e51b815260040161092290614906565b6002600155826122f157600091506124a0565b60006122fb612fe1565b90508061230c5760009250506124a0565b600a546040516370a0823160e01b81526000916001600160a01b0316906370a082319061233d9030906004016144f3565b602060405180830381865afa15801561235a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237e919061485c565b9050848110156123fb57600060001986146123b5576123b0836103e86123a6896103ed6147da565b610a6491906147f9565b6123b7565b825b9050828110156123e357816123d46123cf828461493d565b6137b1565b6123de9190614954565b6123eb565b6123eb6126b0565b90506123f78187611d31565b9550505b61240361105e565b50939550612442935085925061241b91506109cb9050565b612426886001614954565b61243091906147da565b61243a91906147f9565b600554611d31565b935061246430612450611a06565b600a546001600160a01b0316919088613850565b7f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a94243643386604051612495929190614999565b60405180910390a150505b600180556124ac61105e565b50505060119290925550919392505050565b600081156124e957600b54600a546124e49184916001600160a01b039182169116613871565b610a83565b600092915050565b6000600c54806124ff611498565b111561251d5760405162461bcd60e51b81526004016109229061496c565b600260015414156125405760405162461bcd60e51b815260040161092290614906565b60026001558261255357600091506124a0565b600061255d612fe1565b9050612567610a44565b6125718286614954565b11156125b35760405162461bcd60e51b81526020600482015260116024820152701213140e8813d5915497d3505617d51593607a1b6044820152606401610922565b600554156125df5780846125c660055490565b6125d091906147da565b6125da91906147f9565b6125e1565b835b600a549093506001600160a01b03166323b872dd6125fd611a06565b30876040518463ffffffff1660e01b815260040161261d939291906149f5565b6020604051808303816000875af115801561263c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126609190614a19565b5061266a8461389f565b7fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c338560405161269b929190614999565b60405180910390a150600180556124ac61105e565b60006126bc6000612095565b505060006126c86138f8565b600b546040516370a0823160e01b81529192506000916001600160a01b03909116906370a08231906126fe9030906004016144f3565b602060405180830381865afa15801561271b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061273f919061485c565b90508082111561278857612782612756828461493d565b600a54600b546001600160a01b039182169116612771611386565b6001600160a01b031692919061394c565b506127cb565b818111156127cb576127c961279d838361493d565b600b54600a546001600160a01b0391821691166127b8611386565b6001600160a01b0316929190613a2b565b505b600b546040516370a0823160e01b8152612843916001600160a01b0316906370a08231906127fd9030906004016144f3565b602060405180830381865afa15801561281a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061283e919061485c565b6121a3565b600061284d613a8c565b905061285881613ac1565b600a546040516370a0823160e01b81526001600160a01b03909116906370a08231906128889030906004016144f3565b602060405180830381865afa1580156128a5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af8919061485c565b601854601c54604051631c57762b60e31b81526060926001600160a01b03169163e2bbb158916128ff9190600090600401614729565b600060405180830381600087803b15801561291957600080fd5b505af115801561292d573d6000803e3d6000fd5b506001925061293a915050565b604051908082528060200260200182016040528015612963578160200160208202803683370190505b50601a546040516370a0823160e01b81529192506001600160a01b0316906370a08231906129959030906004016144f3565b602060405180830381865afa1580156129b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129d6919061485c565b816000815181106129e9576129e9614846565b60200260200101818152505080600081518110612a0857612a08614846565b602002602001015160001415612a1d57610a83565b601954612a7f906001600160a01b03168484600081612a3e57612a3e614846565b9050602002810190612a509190614a4c565b601a5484516001600160a01b03909116908590600090612a7257612a72614846565b6020026020010151613b3b565b601a5481516001600160a01b0390911690600080516020614cba833981519152908390600090612ab157612ab1614846565b6020026020010151604051612ac891815260200190565b60405180910390a2478015612b6b57612adf610a69565b6001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612b1957600080fd5b505af1158015612b2d573d6000803e3d6000fd5b5050505050612b3a610a69565b6001600160a01b0316600080516020614cba83398151915282604051612b6291815260200190565b60405180910390a25b5092915050565b6060612b7c610ca8565b6001600160a01b0316630952c5636000306040518363ffffffff1660e01b8152600401612baa929190614a6c565b600060405180830381600087803b158015612bc457600080fd5b505af1158015612bd8573d6000803e3d6000fd5b5060019250612be5915050565b604051908082528060200260200182016040528015612c0e578160200160208202803683370190505b506017546040516370a0823160e01b81529192506001600160a01b0316906370a0823190612c409030906004016144f3565b602060405180830381865afa158015612c5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c81919061485c565b81600081518110612c9457612c94614846565b602002602001018181525050600081600081518110612cb557612cb5614846565b60200260200101511115612d6757612d15612cce611a24565b84846000818110612ce157612ce1614846565b9050602002810190612cf39190614a4c565b60175484516001600160a01b03909116908590600090612a7257612a72614846565b60175481516001600160a01b0390911690600080516020614cba833981519152908390600090612d4757612d47614846565b6020026020010151604051612d5e91815260200190565b60405180910390a25b612d6f610ca8565b6001600160a01b0316630952c5636001306040518363ffffffff1660e01b8152600401612d9d929190614a6c565b600060405180830381600087803b158015612db757600080fd5b505af1158015612dcb573d6000803e3d6000fd5b504792505081159050612b6b57612adf610a69565b600a546040516370a0823160e01b81526000916001600160a01b0316906370a0823190612e119030906004016144f3565b602060405180830381865afa158015612e2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e52919061485c565b600b546040516370a0823160e01b81529192506000916001600160a01b03909116906370a0823190612e889030906004016144f3565b602060405180830381865afa158015612ea5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ec9919061485c565b90506000612ed5611fd4565b91505080841015612ee65750505050565b6000612f146002612ef686613ce0565b612f009086614954565b612f0a91906147f9565b610a64848861493d565b90506000612f21826124be565b905084811015612f6757612f53612f38828761493d565b600a54600b546001600160a01b0391821691166127b8611386565b612f5d9085614954565b9350809450612f8c565b81841115612f8c57612f7c61279d838661493d565b612f869086614954565b94508193505b836000612f98826124be565b905080871015612fb0575085612fad81613ce0565b91505b80612fbf575050505050505050565b6000612fcb8284613d06565b9050612fd681613da6565b505050505050505050565b600080612fec613a8c565b90506000612ff86138f8565b90506000613005826124be565b600b546040516370a0823160e01b81529192506000916001600160a01b03909116906370a082319061303b9030906004016144f3565b602060405180830381865afa158015613058573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061307c919061485c565b9050600081156130945761308f826124be565b613097565b60005b905060006130a3611fd4565b50600a546040516370a0823160e01b81529192506000916001600160a01b03909116906370a08231906130da9030906004016144f3565b602060405180830381865afa1580156130f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061311b919061485c565b905082818661312b8560026147da565b613135908b614954565b61313f919061493d565b6131499190614954565b6131539190614954565b97505050505050505090565b60008061316a61158e565b905061317881612710614954565b611d2782856147da565b600061318d83613ce0565b90506000613199611d47565b9050808211156131ea576131c560006131b28686613dd9565b116131bd5784612095565b60005b612095565b50506131d083613e4d565b506131e590506131e0828461493d565b613eaa565b61329e565b8082101561329e576131fc6000612095565b5050600b546040516370a0823160e01b8152600091613280916001600160a01b03909116906370a08231906132359030906004016144f3565b602060405180830381865afa158015613252573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613276919061485c565b610a64858561493d565b9050801561329157613291816121a3565b61329a84613e4d565b5050505b6132a782612de0565b50505050565b60008060006132bc8585613f65565b509050600080876001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015613300573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133249190614aa4565b506001600160701b031691506001600160701b03169150826001600160a01b0316876001600160a01b03161461335b57808261335e565b81815b90999098509650505050505050565b60006133c2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611b739092919063ffffffff16565b805190915015611b6e57808060200190518101906133e09190614a19565b611b6e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610922565b6060824710156134a05760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610922565b843b6134ee5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610922565b600080866001600160a01b0316858760405161350a9190614ae9565b60006040518083038185875af1925050503d8060008114613547576040519150601f19603f3d011682016040523d82523d6000602084013e61354c565b606091505b509150915061355c828286614048565b979650505050505050565b600080613572614081565b601b546040516370a0823160e01b81529192506000916001600160a01b03909116906370a08231906135a89030906004016144f3565b602060405180830381865afa1580156135c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135e9919061485c565b90506114fb8183614954565b601854601c54604051630441a3e760e41b81526001600160a01b039092169163441a3e7091613628918590600401614729565b600060405180830381600087803b15801561364257600080fd5b505af1158015613656573d6000803e3d6000fd5b5050505050565b60008061368461366b611386565b84613674611386565b6001600160a01b03169190611f14565b600061369e613691610d30565b613699610a69565b613f65565b5090506000806136ac611386565b6001600160a01b03166389afcb44306040518263ffffffff1660e01b81526004016136d791906144f3565b60408051808303816000875af11580156136f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137199190614afb565b91509150613725610d30565b6001600160a01b0316836001600160a01b031614613744578082613747565b81815b94509450505050915091565b61375b611a15565b6001600160a01b0316634e4d9fea826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561379557600080fd5b505af11580156137a9573d6000803e3d6000fd5b505050505050565b6000806137bd8361315f565b905060006137c9611fd4565b50905060006137d6611d47565b905060006137e384613ce0565b905082841015806137f45750818110155b1561380b576138016126b0565b9695505050505050565b60008061381b6131c0878761493d565b91509150613828816121a3565b61383a613835838a61493d565b6140fc565b6138449083614954565b98975050505050505050565b6132a7846323b872dd60e01b858585604051602401611b37939291906149f5565b60008361388057506000611b85565b60008061389085856119ed611386565b9150915061380186838361412f565b6103e88110156138ac5750565b60006138b78261315f565b905060006138c482613ce0565b90506138d86138d3838561493d565b61225a565b6138e181613eaa565b60006138ed8383613d06565b90506132a781613da6565b6000613902611a15565b6001600160a01b03166317bfdfbc306040518263ffffffff1660e01b815260040161392d91906144f3565b6020604051808303816000875af1158015611bd3573d6000803e3d6000fd5b60008061395b868686866141f1565b905060006139698486613f65565b509050600080826001600160a01b0316876001600160a01b03161461399057876000613994565b6000885b90925090506139ad6001600160a01b0388168a86611f14565b6040805160008152602081019182905263022c0d9f60e01b9091526001600160a01b038a169063022c0d9f906139ec9085908590309060248101614b1f565b600060405180830381600087803b158015613a0657600080fd5b505af1158015613a1a573d6000803e3d6000fd5b50959b9a5050505050505050505050565b600080613a3a868686866142b7565b90506000613a488486613f65565b509050600080826001600160a01b0316876001600160a01b031614613a6f57836000613a73565b6000845b90925090506139ad6001600160a01b0388168a8a611f14565b6000613a966112e9565b6001600160a01b0316633af9e669306040518263ffffffff1660e01b815260040161392d91906144f3565b6000613acb6112e9565b6001600160a01b031663852a12e3836040518263ffffffff1660e01b8152600401613af891815260200190565b6020604051808303816000875af1158015613b17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b6e919061485c565b6000613b478480614b4c565b6001613b538780614b4c565b613b5e92915061493d565b818110613b6d57613b6d614846565b9050602002016020810190613b829190614535565b90506001600160a01b038316613b988580614b4c565b6000818110613ba957613ba9614846565b9050602002016020810190613bbe9190614535565b6001600160a01b0316148015613bec5750613bd7610a69565b6001600160a01b0316816001600160a01b0316145b80613c0f5750613bfa610d30565b6001600160a01b0316816001600160a01b0316145b613c535760405162461bcd60e51b81526020600482015260156024820152740928cc2e4dac2c4d8ca7440aea49e9c8ebea082a89605b1b6044820152606401610922565b6001600160a01b0385166338ed1739836020870135613c728880614b4c565b308a604001356040518763ffffffff1660e01b8152600401613c9996959493929190614b95565b6000604051808303816000875af1158015613cb8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526137a99190810190614c08565b600081156124e957600a54600b546124e49184916001600160a01b039182169116613871565b6000613d1c613d13611386565b84613674610d30565b613d30613d27611386565b83613674610a69565b613d38611386565b6001600160a01b0316636a627842306040518263ffffffff1660e01b8152600401613d6391906144f3565b6020604051808303816000875af1158015613d82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b85919061485c565b601854601c54604051631c57762b60e31b81526001600160a01b039092169163e2bbb15891613628918590600401614729565b600080613de4611d99565b905080831015613df8576000915050610a83565b6000613e02611fd4565b5090506000818611613e15576000613e1f565b613e1f828761493d565b90506000613e2d848761493d565b9050808210613e43576000945050505050610a83565b61355c828261493d565b6000806000613e5a611d99565b905083811415613e705750600093849350915050565b838111613e9057613e89613e84828661493d565b614378565b6000613e9f565b6000613e9f613835868461493d565b909590945092505050565b613eb2611a15565b6001600160a01b031663c5ebeaec826040518263ffffffff1660e01b8152600401613edf91815260200190565b6020604051808303816000875af1158015613efe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f22919061485c565b50613f2b610a69565b6001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561379557600080fd5b600080826001600160a01b0316846001600160a01b03161415613fca5760405162461bcd60e51b815260206004820152601d60248201527f556e695574696c733a204944454e544943414c5f4144445245535345530000006044820152606401610922565b826001600160a01b0316846001600160a01b031610613fea578284613fed565b83835b90925090506001600160a01b0382166140415760405162461bcd60e51b8152602060048201526016602482015275556e695574696c733a205a45524f5f4144445245535360501b6044820152606401610922565b9250929050565b60608315614057575081611b85565b8251156140675782518084602001fd5b8160405162461bcd60e51b815260040161092291906144e0565b601854601c546040516393f1a40b60e01b8152600481019190915230602482015260009182916001600160a01b03909116906393f1a40b906044016040805180830381865afa1580156140d8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6b9190614afb565b600080614107614411565b90508281116141165780614118565b825b915081156141295761412982613ac1565b50919050565b60008084116141805760405162461bcd60e51b815260206004820152601d60248201527f556e695574696c733a20494e53554646494349454e545f414d4f554e540000006044820152606401610922565b6000831180156141905750600082115b6141dc5760405162461bcd60e51b815260206004820181905260248201527f556e695574696c733a20494e53554646494349454e545f4c49515549444954596044820152606401610922565b826141e783866147da565b611b8291906147f9565b600080841161424e5760405162461bcd60e51b8152602060048201526024808201527f556e695574696c733a20494e53554646494349454e545f4f55545055545f414d60448201526313d5539560e21b6064820152608401610922565b60008061425c8786866132ad565b9092509050600061426d87846147da565b614279906103e86147da565b90506000614287888461493d565b614293906103e56147da565b905061429f81836147f9565b6142aa906001614954565b9998505050505050505050565b60008084116143145760405162461bcd60e51b815260206004820152602360248201527f556e695574696c733a20494e53554646494349454e545f494e5055545f414d4f60448201526215539560ea1b6064820152608401610922565b6000806143228786866132ad565b90925090506000614335876103e56147da565b9050600061434383836147da565b9050600082614354866103e86147da565b61435e9190614954565b905061436a81836147f9565b9a9950505050505050505050565b600080614383610d30565b6001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016143ae91906144f3565b602060405180830381865afa1580156143cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143ef919061485c565b90508281116143fe5780614400565b825b91508115614129576141298261225a565b60008061441c611d99565b9050600061442b610a5a611d47565b905060006063614439611e8e565b61444b84670de0b6b3a76400006147da565b6144569060646147da565b61446091906147f9565b61446a91906147f9565b90508281111561447e576000935050505090565b610af8818461493d565b60005b838110156144a357818101518382015260200161448b565b838111156132a75750506000910152565b600081518084526144cc816020860160208601614488565b601f01601f19169290920160200192915050565b602081526000611b8560208301846144b4565b6001600160a01b0391909116815260200190565b60006020828403121561451957600080fd5b5035919050565b6001600160a01b038116811461181757600080fd5b60006020828403121561454757600080fd5b8135611b8581614520565b60008083601f84011261456457600080fd5b5081356001600160401b0381111561457b57600080fd5b6020830191508360208260051b850101111561404157600080fd5b6000806000604084860312156145ab57600080fd5b83356145b681614520565b925060208401356001600160401b038111156145d157600080fd5b6145dd86828701614552565b9497909650939450505050565b801515811461181757600080fd5b6000806040838503121561460b57600080fd5b823561461681614520565b91506020830135614626816145ea565b809150509250929050565b60006020828403121561464357600080fd5b813561ffff81168114611b8557600080fd5b6000806000806040858703121561466b57600080fd5b84356001600160401b038082111561468257600080fd5b61468e88838901614552565b909650945060208701359150808211156146a757600080fd5b506146b487828801614552565b95989497509550505050565b600081518084526020808501945080840160005b838110156146f0578151875295820195908201906001016146d4565b509495945050505050565b60408152600061470e60408301856146c0565b828103602084015261472081856146c0565b95945050505050565b918252602082015260400190565b600181811c9082168061474b57607f821691505b6020821081141561412957634e487b7160e01b600052602260045260246000fd5b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6000602082840312156147b357600080fd5b815160ff81168114611b8557600080fd5b634e487b7160e01b600052601160045260246000fd5b60008160001904831182151516156147f4576147f46147c4565b500290565b60008261481657634e487b7160e01b600052601260045260246000fd5b500490565b60208082526011908201527014dd1c985d0e8813d3931657d590555315607a1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561486e57600080fd5b5051919050565b6000600019821415614889576148896147c4565b5060010190565b60208082528181018390526000908460408401835b868110156148d35782356148b881614520565b6001600160a01b0316825291830191908301906001016148a5565b509695505050505050565b6020808252600e908201526d0a6e8e4c2e874409c9ebe82aaa8960931b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60008282101561494f5761494f6147c4565b500390565b60008219821115614967576149676147c4565b500190565b60208082526013908201527209098a07440a0a492868abe9a92a69a82a8869606b1b604082015260600190565b6001600160a01b03929092168252602082015260400190565b6000806000606084860312156149c757600080fd5b83516149d2816145ea565b6020850151604086015191945092506149ea816145ea565b809150509250925092565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600060208284031215614a2b57600080fd5b8151611b85816145ea565b634e487b7160e01b600052604160045260246000fd5b60008235605e19833603018112614a6257600080fd5b9190910192915050565b60ff9290921682526001600160a01b0316602082015260400190565b80516001600160701b0381168114614a9f57600080fd5b919050565b600080600060608486031215614ab957600080fd5b614ac284614a88565b9250614ad060208501614a88565b9150604084015163ffffffff811681146149ea57600080fd5b60008251614a62818460208701614488565b60008060408385031215614b0e57600080fd5b505080516020909101519092909150565b84815283602082015260018060a01b038316604082015260806060820152600061380160808301846144b4565b6000808335601e19843603018112614b6357600080fd5b8301803591506001600160401b03821115614b7d57600080fd5b6020019150600581901b360382131561404157600080fd5b868152602080820187905260a0604083018190528201859052600090869060c08401835b88811015614be7578335614bcc81614520565b6001600160a01b031682529282019290820190600101614bb9565b506001600160a01b0396909616606085015250505060800152949350505050565b60006020808385031215614c1b57600080fd5b82516001600160401b0380821115614c3257600080fd5b818501915085601f830112614c4657600080fd5b815181811115614c5857614c58614a36565b8060051b604051601f19603f83011681018181108582111715614c7d57614c7d614a36565b604052918252848201925083810185019188831115614c9b57600080fd5b938501935b8285101561384457845184529385019392850192614ca056fe3efad319b6afe1e0317f51df66abdc4d7a7c8b1cfda31f03440b4ad255af7245a2646970667358221220560a575531386b8f3fdd8f8afdf2fc19f99efd2998f041e7114e3138d3f5687064736f6c634300080a00330000000000000000000000000000000000000000000000000000000000000020000000000000000000000000e3f5a90f9cb311505cd691a46596599aa1a0ad7d00000000000000000000000098878b06940ae243284ca214f92bb71a2b032b8a000000000000000000000000d0670aee3698f66e2d4daf071eb9c690d978bfa80000000000000000000000006a1a771c7826596652dadc9145feaae62b1cd07f000000000000000000000000e537f70a8b62204832b8ba91940b77d3f79aeb810000000000000000000000000329867a8c457e9f75e25b0685011291cd30904f0000000000000000000000006bd193ee6d2104f14f94e2ca6efefae561a4334b000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000aa30ef758139ae4a7f798112902bf6d65612045f0000000000000000000000000b7a0eaa884849c6af7a129e899536dddca4905e000000000000000000000000aa30ef758139ae4a7f798112902bf6d65612045f000000000000000000000000bb8d88bcd9749636bc4d2be22aac4bb3b01a58f1000000000000000000000000c24d43093b44b7a9657571ddb79fedf014eaef7d00000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000240ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000011555344436d6f7672534f4c415277656c6c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001855534443204d4f565220534f4c4152204d6f6f6e77656c6c0000000000000000

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

0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000e3f5a90f9cb311505cd691a46596599aa1a0ad7d00000000000000000000000098878b06940ae243284ca214f92bb71a2b032b8a000000000000000000000000d0670aee3698f66e2d4daf071eb9c690d978bfa80000000000000000000000006a1a771c7826596652dadc9145feaae62b1cd07f000000000000000000000000e537f70a8b62204832b8ba91940b77d3f79aeb810000000000000000000000000329867a8c457e9f75e25b0685011291cd30904f0000000000000000000000006bd193ee6d2104f14f94e2ca6efefae561a4334b000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000aa30ef758139ae4a7f798112902bf6d65612045f0000000000000000000000000b7a0eaa884849c6af7a129e899536dddca4905e000000000000000000000000aa30ef758139ae4a7f798112902bf6d65612045f000000000000000000000000bb8d88bcd9749636bc4d2be22aac4bb3b01a58f1000000000000000000000000c24d43093b44b7a9657571ddb79fedf014eaef7d00000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000240ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000011555344436d6f7672534f4c415277656c6c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001855534443204d4f565220534f4c4152204d6f6f6e77656c6c0000000000000000

-----Decoded View---------------
Arg [0] : config (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]

-----Encoded View---------------
21 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [1] : 000000000000000000000000e3f5a90f9cb311505cd691a46596599aa1a0ad7d
Arg [2] : 00000000000000000000000098878b06940ae243284ca214f92bb71a2b032b8a
Arg [3] : 000000000000000000000000d0670aee3698f66e2d4daf071eb9c690d978bfa8
Arg [4] : 0000000000000000000000006a1a771c7826596652dadc9145feaae62b1cd07f
Arg [5] : 000000000000000000000000e537f70a8b62204832b8ba91940b77d3f79aeb81
Arg [6] : 0000000000000000000000000329867a8c457e9f75e25b0685011291cd30904f
Arg [7] : 0000000000000000000000006bd193ee6d2104f14f94e2ca6efefae561a4334b
Arg [8] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [9] : 000000000000000000000000aa30ef758139ae4a7f798112902bf6d65612045f
Arg [10] : 0000000000000000000000000b7a0eaa884849c6af7a129e899536dddca4905e
Arg [11] : 000000000000000000000000aa30ef758139ae4a7f798112902bf6d65612045f
Arg [12] : 000000000000000000000000bb8d88bcd9749636bc4d2be22aac4bb3b01a58f1
Arg [13] : 000000000000000000000000c24d43093b44b7a9657571ddb79fedf014eaef7d
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000200
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000240
Arg [16] : ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Arg [17] : 0000000000000000000000000000000000000000000000000000000000000011
Arg [18] : 555344436d6f7672534f4c415277656c6c000000000000000000000000000000
Arg [19] : 0000000000000000000000000000000000000000000000000000000000000018
Arg [20] : 55534443204d4f565220534f4c4152204d6f6f6e77656c6c0000000000000000


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
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.