Contract 0x81d8fdcf581b060abdb38bec45329ba366981269

Txn Hash Method
Block
From
To
Value [Txn Fee]
0xb94cb02d46e1b48109af8f2b18ea550783c1a8ab47e4da15da30ca28b82754b90x60806040146925742022-05-14 17:03:097 days 14 hrs ago0xc783ea213810f1d3429bd9c1bfd2ab20f0e1ead1 IN  Create: JoeLiquidator0 AVAX0.103421559051 27.54328349
[ Download CSV Export 
Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
JoeLiquidator

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at snowtrace.io on 2022-05-14
*/

// File: github/0xnivek/joe-liquidator/liquidator/contracts/libraries/SafeMath.sol


pragma solidity ^0.8.3;

// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol

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

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

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

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

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

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

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

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

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

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

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

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

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

// File: github/0xnivek/joe-liquidator/liquidator/contracts/lending/Exponential.sol


pragma solidity ^0.8.3;

/**
 * @title Exponential module for storing fixed-precision decimals
 * @author Compound
 * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.
 *         Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:
 *         `Exp({mantissa: 5100000000000000000})`.
 */
contract Exponential {
    uint256 constant expScale = 1e18;
    uint256 constant doubleScale = 1e36;
    uint256 constant halfExpScale = expScale / 2;
    uint256 constant mantissaOne = expScale;

    struct Exp {
        uint256 mantissa;
    }

    /**
     * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.
     */
    function mul_ScalarTruncate(Exp memory a, uint256 scalar)
        internal
        pure
        returns (uint256)
    {
        Exp memory product = mul_(a, scalar);
        return truncate(product);
    }

    function mul_(Exp memory a, uint256 b) internal pure returns (Exp memory) {
        return Exp({mantissa: mul_(a.mantissa, b)});
    }

    function mul_(uint256 a, uint256 b) internal pure returns (uint256) {
        return mul_(a, b, "multiplication overflow");
    }

    function mul_(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        if (a == 0 || b == 0) {
            return 0;
        }
        uint256 c = a * b;
        require(c / a == b, errorMessage);
        return c;
    }

    /**
     * @dev Truncates the given exp to a whole number value.
     *      For example, truncate(Exp{mantissa: 15 * expScale}) = 15
     */
    function truncate(Exp memory exp) internal pure returns (uint256) {
        // Note: We are not using careful math here as we're performing a division that cannot fail
        return exp.mantissa / expScale;
    }
}

// File: github/0xnivek/joe-liquidator/liquidator/contracts/lending/JoeRouter02.sol


pragma solidity ^0.8.3;

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

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

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

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

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

// File: github/0xnivek/joe-liquidator/liquidator/contracts/interfaces/WAVAXInterface.sol


pragma solidity ^0.8.3;

interface WAVAXInterface {
    function deposit() external payable;

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

    function withdraw(uint256) external;

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

    function approve(address guy, uint256 wad) external returns (bool);
}

// File: github/0xnivek/joe-liquidator/liquidator/contracts/interfaces/ERC3156FlashBorrowerInterface.sol


pragma solidity ^0.8.3;

interface ERC3156FlashBorrowerInterface {
    /**
     * @dev Receive a flash loan.
     * @param initiator The initiator of the loan.
     * @param token The loan currency.
     * @param amount The amount of tokens lent.
     * @param fee The additional amount of tokens to repay.
     * @param data Arbitrary data structure, intended to contain user-defined parameters.
     * @return The keccak256 hash of "ERC3156FlashBorrower.onFlashLoan"
     */
    function onFlashLoan(
        address initiator,
        address token,
        uint256 amount,
        uint256 fee,
        bytes calldata data
    ) external returns (bytes32);
}

// File: github/0xnivek/joe-liquidator/liquidator/contracts/lending/JTokenInterfaces.sol


pragma solidity ^0.8.3;


interface JTokenStorage {
    function totalBorrows() external view returns (uint256);

    /**
     * @notice Block timestamp that interest was last accrued at
     */
    function accrualBlockTimestamp() external view returns (uint256);
}

interface JTokenInterface is JTokenStorage {
    function balanceOf(address owner) external view returns (uint256);

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

    function borrowRatePerSecond() external view returns (uint256);

    function supplyRatePerSecond() external view returns (uint256);

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

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

    function accrueInterest() external returns (uint256);

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

interface JToken is JTokenInterface {}

interface JErc20Storage {
    function underlying() external returns (address);
}

interface JErc20Interface is JErc20Storage {
    function liquidateBorrow(
        address borrower,
        uint256 repayAmount,
        JTokenInterface jTokenCollateral
    ) external returns (uint256);

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

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

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

interface JWrappedNativeInterface is JErc20Interface {
    function flashLoan(
        ERC3156FlashBorrowerInterface receiver,
        address initiator,
        uint256 amount,
        bytes calldata data
    ) external returns (bool);

    function liquidateBorrowNative(
        address borrower,
        JTokenInterface jTokenCollateral
    ) external payable returns (uint256);

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

    function mintNative() external payable returns (uint256);

    function borrowNative(uint256 borrowAmount) external returns (uint256);
}

interface JWrappedNativeDelegator is JTokenInterface, JWrappedNativeInterface {}

interface JCollateralCapErc20Interface is JErc20Interface {
    function flashLoan(
        ERC3156FlashBorrowerInterface receiver,
        address initiator,
        uint256 amount,
        bytes calldata data
    ) external returns (bool);
}

interface JCollateralCapErc20Delegator is
    JTokenInterface,
    JCollateralCapErc20Interface
{}

// File: github/0xnivek/joe-liquidator/liquidator/contracts/lending/PriceOracle.sol


pragma solidity ^0.8.3;


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

// File: github/0xnivek/joe-liquidator/liquidator/contracts/lending/JoetrollerInterface.sol


pragma solidity ^0.8.3;



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

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

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

interface Joetroller is JoetrollerV1Storage {
    function enterMarkets(address[] calldata jTokens)
        external
        returns (uint256[] memory);

    function isMarketListed(address jTokenAddress) external view returns (bool);

    function checkMembership(address account, JToken jToken)
        external
        view
        returns (bool);

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

    function liquidateBorrowAllowed(
        address jTokenBorrowed,
        address jTokenCollateral,
        address liquidator,
        address borrower,
        uint256 repayAmount
    ) external returns (uint256);

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

// File: github/0xnivek/joe-liquidator/liquidator/contracts/interfaces/ERC3156FlashLenderInterface.sol


pragma solidity ^0.8.3;


interface ERC3156FlashLenderInterface {
    /**
     * @dev The amount of currency available to be lent.
     * @param token The loan currency.
     * @return The amount of `token` that can be borrowed.
     */
    function maxFlashLoan(address token) external view returns (uint256);

    /**
     * @dev The fee to be charged for a given loan.
     * @param token The loan currency.
     * @param amount The amount of tokens lent.
     * @return The amount of `token` to be charged for the loan, on top of the returned principal.
     */
    function flashFee(address token, uint256 amount)
        external
        view
        returns (uint256);

    /**
     * @dev Initiate a flash loan.
     * @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
     * @param token The loan currency.
     * @param amount The amount of tokens lent.
     * @param data Arbitrary data structure, intended to contain user-defined parameters.
     */
    function flashLoan(
        ERC3156FlashBorrowerInterface receiver,
        address token,
        uint256 amount,
        bytes calldata data
    ) external returns (bool);
}

// File: github/0xnivek/joe-liquidator/liquidator/contracts/interfaces/ERC20Interface.sol


pragma solidity ^0.8.3;

interface ERC20 {
    function approve(address spender, uint256 amount) external;

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

// File: github/0xnivek/joe-liquidator/liquidator/contracts/JoeLiquidator.sol


pragma solidity ^0.8.3;

// import "hardhat/console.sol";











/**
 * @notice Contract that performs liquidation of underwater accounts in the jToken markets
 */
contract JoeLiquidator is ERC3156FlashBorrowerInterface, Exponential {
    using SafeMath for uint256;

    /// @notice Addresses of Banker Joe contracts
    address public joetrollerAddress;
    address public joeRouter02Address;
    address public jUSDCAddress;
    address public jWETHAddress;

    /// @notice Addresses of ERC20 contracts
    address public constant WAVAX = 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7;
    address public constant WETH = 0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB;
    address public constant USDC = 0xA7D7079b0FEaD91F3e65f86E8915Cb59c1a4C664;

    struct LiquidationLocalVars {
        address jRepayTokenAddress;
        address jSeizeTokenAddress;
        address borrowerToLiquidate;
        uint256 repayAmount;
    }

    /// @notice Emitted upon successful liquidation
    event LiquidationEvent(
        address indexed _borrowerLiquidated,
        address _jRepayToken,
        address _jSeizeToken,
        uint256 _repayAmount,
        uint256 _profitedAVAX
    );

    constructor(
        address _joetrollerAddress,
        address _joeRouter02Address,
        address _jUSDCAddress,
        address _jWETHAddress
    ) {
        joetrollerAddress = _joetrollerAddress;
        joeRouter02Address = _joeRouter02Address;
        jUSDCAddress = _jUSDCAddress;
        jWETHAddress = _jWETHAddress;
    }

    /// @dev Need to implement receive function in order for this contract to receive AVAX.
    /// We need to receive AVAX when we liquidating a native borrow position.
    receive() external payable {}

    /**
     * @notice Ensure that we can liquidate the borrower
     * @dev A borrower is liquidatable if:
     *      1. Their `liquidity` is zero
     *      2. Their `shortfall` is non-zero
     */
    modifier isLiquidatable(address _borrowerToLiquidate) {
        (, uint256 liquidity, uint256 shortfall) = Joetroller(joetrollerAddress)
            .getAccountLiquidity(_borrowerToLiquidate);
        require(
            liquidity == 0,
            "JoeLiquidator: Cannot liquidate account with non-zero liquidity"
        );
        require(
            shortfall != 0,
            "JoeLiquidator: Cannot liquidate account with zero shortfall"
        );
        _;
    }

    /**
     * @notice Liquidates a borrower with a given jToken to repay and
     * jToken to seize.
     * @param _borrowerToLiquidate: Address of the borrower to liquidate
     * @param _jRepayTokenAddress: Address of the jToken to repay
     * @param _jSeizeTokenAddress: Address of the jToken to seize
     */
    function liquidate(
        address _borrowerToLiquidate,
        address _jRepayTokenAddress,
        address _jSeizeTokenAddress
    ) external isLiquidatable(_borrowerToLiquidate) {
        uint256 amountToRepay = getAmountToRepay(
            _borrowerToLiquidate,
            _jRepayTokenAddress,
            _jSeizeTokenAddress
        );
        doFlashloan(
            _borrowerToLiquidate,
            _jRepayTokenAddress,
            _jSeizeTokenAddress,
            amountToRepay
        );
    }

    /**
     * @dev Calculates amount of the borrow position to repay
     * @param _borrowerToLiquidate: Address of the borrower to liquidate
     * @param _jRepayTokenAddress: Address of the jToken to repay
     * @param _jSeizeTokenAddress: Address of the jToken to seize
     * @return the amount of jRepayToken to repay
     */
    function getAmountToRepay(
        address _borrowerToLiquidate,
        address _jRepayTokenAddress,
        address _jSeizeTokenAddress
    ) internal view returns (uint256) {
        // Inspired from https://github.com/haydenshively/Nantucket/blob/538bd999c9cc285efb403c876e5f4c3d467a2d68/contracts/FlashLiquidator.sol#L121-L144
        Joetroller joetroller = Joetroller(joetrollerAddress);
        PriceOracle priceOracle = joetroller.oracle();

        uint256 closeFactor = joetroller.closeFactorMantissa();
        uint256 liquidationIncentive = joetroller
            .liquidationIncentiveMantissa();

        uint256 repayTokenUnderlyingPrice = priceOracle.getUnderlyingPrice(
            JToken(_jRepayTokenAddress)
        );
        uint256 seizeTokenUnderlyingPrice = priceOracle.getUnderlyingPrice(
            JToken(_jSeizeTokenAddress)
        );

        uint256 maxRepayAmount = (JTokenInterface(_jRepayTokenAddress)
            .borrowBalanceStored(_borrowerToLiquidate) * closeFactor) /
            uint256(10**18);
        uint256 maxSeizeAmount = (_getBalanceOfUnderlying(
            _jSeizeTokenAddress,
            _borrowerToLiquidate
        ) * uint256(10**18)) / liquidationIncentive;

        uint256 maxRepayAmountInUSD = maxRepayAmount *
            repayTokenUnderlyingPrice;
        uint256 maxSeizeAmountInUSD = maxSeizeAmount *
            seizeTokenUnderlyingPrice;

        uint256 maxAmountInUSD = (maxRepayAmountInUSD < maxSeizeAmountInUSD)
            ? maxRepayAmountInUSD
            : maxSeizeAmountInUSD;

        return maxAmountInUSD / repayTokenUnderlyingPrice;
    }

    /**
     * @dev Gets an account's balanceOfUnderlying (i.e. supply balance) for a given jToken
     * @param _jTokenAddress The address of a jToken contract
     * @param _account The address the account to lookup
     * @return the account's balanceOfUnderlying in jToken
     */
    function _getBalanceOfUnderlying(address _jTokenAddress, address _account)
        internal
        view
        returns (uint256)
    {
        // From https://github.com/traderjoe-xyz/joe-lending/blob/main/contracts/JToken.sol#L128
        JTokenInterface jToken = JTokenInterface(_jTokenAddress);
        Exp memory exchangeRate = Exp({mantissa: jToken.exchangeRateStored()});
        return mul_ScalarTruncate(exchangeRate, jToken.balanceOf(_account));
    }

    /**
     * @notice Performs flash loan from:
     * - jWETH if _jRepayTokenAddress == jUSDC
     * - jUSDC otherwise
     * Upon receiving the flash loan, the tokens are swapped to the tokens needed
     * to repay the borrow position and perform liquidation.
     * @param _borrowerToLiquidate The address of the borrower to liquidate
     * @param _jRepayTokenAddress The address of the jToken contract to borrow from
     * @param _jSeizeTokenAddress The address of the jToken contract to seize collateral from
     * @param _repayAmount The amount of the tokens to repay
     */
    function doFlashloan(
        address _borrowerToLiquidate,
        address _jRepayTokenAddress,
        address _jSeizeTokenAddress,
        uint256 _repayAmount
    ) internal {
        // See if the underlying repay token is USDC
        address underlyingRepayToken = JErc20Storage(_jRepayTokenAddress)
            .underlying();
        bool isRepayTokenUSDC = underlyingRepayToken == USDC;

        // Calculate the amount we need to flash loan
        uint256 flashLoanAmount = _getFlashLoanAmount(
            underlyingRepayToken,
            _repayAmount,
            isRepayTokenUSDC
        );

        // Calculate which jToken to flash loan from.
        // We will only ever flash loan from jUSDC or jWETH.
        JCollateralCapErc20Delegator jTokenToFlashLoan = _getJTokenToFlashLoan(
            isRepayTokenUSDC
        );

        bytes memory data = abi.encode(
            msg.sender, // initiator
            _borrowerToLiquidate, // borrowerToLiquidate
            _jRepayTokenAddress, // jRepayTokenAddress
            _jSeizeTokenAddress, // jSeizeTokenAddress
            jTokenToFlashLoan.underlying(), // flashLoanedTokenAddress
            flashLoanAmount, // flashLoanAmount
            _repayAmount // repayAmount
        );

        // Perform flash loan
        jTokenToFlashLoan.flashLoan(this, msg.sender, flashLoanAmount, data);
    }

    /**
     * @dev Calculates the amount needed to flash loan in order to repay
     * `_repayAmount` of the borrow position.
     * @param _underlyingRepayToken The token of the borrow position to repay
     * @param _repayAmount The amount of the borrow position to repay
     * @param _isRepayTokenUSDC Whether the token of the borrow position to repay is USDC
     * @return The flash loan amount required to repay the borrow position for liquidation.
     */
    function _getFlashLoanAmount(
        address _underlyingRepayToken,
        uint256 _repayAmount,
        bool _isRepayTokenUSDC
    ) internal view returns (uint256) {
        address[] memory path = new address[](2);

        // If the underlying repay token is USDC, we will flash loan from jWETH,
        // else we will flash loan jUSDC.
        if (_isRepayTokenUSDC) {
            path[0] = WETH;
        } else {
            path[0] = USDC;
        }
        path[1] = _underlyingRepayToken;
        return
            JoeRouter02(joeRouter02Address).getAmountsIn(_repayAmount, path)[0];
    }

    /**
     * @dev Gets the jToken to flash loan.
     * We always flash loan from jUSDC unless the repay token is USDC in which case we
     * flash loan from jWETH.
     * @param _isRepayTokenUSDC Whether the token of the borrow position to repay is USDC
     * @return The jToken to flash loan
     */
    function _getJTokenToFlashLoan(bool _isRepayTokenUSDC)
        internal
        view
        returns (JCollateralCapErc20Delegator)
    {
        if (_isRepayTokenUSDC) {
            return JCollateralCapErc20Delegator(jWETHAddress);
        } else {
            return JCollateralCapErc20Delegator(jUSDCAddress);
        }
    }

    /**
     * @dev Called by a jToken upon request of a flash loan
     * @param _initiator The address that initiated this flash loan
     * @param _flashLoanTokenAddress The address of the flash loan jToken's underlying asset
     * @param _flashLoanAmount The flash loan amount granted
     * @param _flashLoanFee The fee for this flash loan
     * @param _data The encoded data sent for this flash loan
     */
    function onFlashLoan(
        address _initiator,
        address _flashLoanTokenAddress,
        uint256 _flashLoanAmount,
        uint256 _flashLoanFee,
        bytes calldata _data
    ) external override returns (bytes32) {
        require(
            Joetroller(joetrollerAddress).isMarketListed(msg.sender),
            "JoeLiquidator: Untrusted message sender calling onFlashLoan"
        );

        LiquidationLocalVars
            memory liquidationLocalVars = _getLiquidationLocalVars(
                _initiator,
                _flashLoanTokenAddress,
                _flashLoanAmount,
                _data
            );

        uint256 flashLoanAmountToRepay = _flashLoanAmount.add(_flashLoanFee);

        // ********************************************************************
        // Our custom logic begins here...
        // ********************************************************************
        JErc20Interface jRepayToken = JErc20Interface(
            liquidationLocalVars.jRepayTokenAddress
        );

        // Swap token that we flash loaned to the token we need to repay the borrow
        // position
        _swapFlashLoanTokenToRepayToken(
            _flashLoanTokenAddress,
            _flashLoanAmount,
            jRepayToken.underlying(),
            liquidationLocalVars.repayAmount
        );

        // Perform liquidation using the underlying repay token we swapped for and
        // receive jSeizeTokens in return.
        _liquidateBorrow(
            jRepayToken,
            liquidationLocalVars.borrowerToLiquidate,
            liquidationLocalVars.repayAmount,
            JTokenInterface(liquidationLocalVars.jSeizeTokenAddress)
        );

        // Redeem jSeizeTokens for underlying seize tokens
        _redeemSeizeToken(liquidationLocalVars.jSeizeTokenAddress);

        // Swap enough seize tokens to flash loan tokens so we can repay flash loan
        // amount + flash loan fee
        _swapSeizeTokenToFlashLoanToken(
            liquidationLocalVars.jSeizeTokenAddress,
            _flashLoanTokenAddress,
            flashLoanAmountToRepay
        );

        // Convert any remaining seized token to native AVAX, unless it already is
        // AVAX, and send to liquidator
        uint256 profitedAVAX = _swapRemainingSeizedTokenToAVAX(
            _initiator,
            liquidationLocalVars.jSeizeTokenAddress
        );

        require(
            profitedAVAX > 0,
            "JoeLiquidator: Expected to have profited from liquidation"
        );

        // ********************************************************************
        // Our custom logic ends here...
        // ********************************************************************

        // Approve flash loan lender to retrieve loan amount + fee from us
        _approveFlashLoanToken(_flashLoanTokenAddress, flashLoanAmountToRepay);

        // Emit event to indicate successful liquidation
        emit LiquidationEvent(
            liquidationLocalVars.borrowerToLiquidate,
            liquidationLocalVars.jRepayTokenAddress,
            liquidationLocalVars.jSeizeTokenAddress,
            liquidationLocalVars.repayAmount,
            profitedAVAX
        );

        return keccak256("ERC3156FlashBorrowerInterface.onFlashLoan");
    }

    /**
     * @dev Decodes the encoded `_data` and packs relevant data needed to perform
     * liquidation into a `LiquidationLocalVars` struct.
     * @param _initiator The address that initiated this flash loan
     * @param _flashLoanTokenAddress The address of the flash loan jToken's underlying asset
     * @param _flashLoanAmount The amount flash loaned
     * @param _data The encoded data sent for this flash loan
     * @return relevant decoded data needed to perform liquidation
     */
    function _getLiquidationLocalVars(
        address _initiator,
        address _flashLoanTokenAddress,
        uint256 _flashLoanAmount,
        bytes calldata _data
    ) internal pure returns (LiquidationLocalVars memory) {
        (
            address initiator,
            address borrowerToLiquidate,
            address jRepayTokenAddress,
            address jSeizeTokenAddress,
            address flashLoanedTokenAddress,
            uint256 flashLoanAmount,
            uint256 repayAmount
        ) = abi.decode(
                _data,
                (address, address, address, address, address, uint256, uint256)
            );

        // Validate encoded data
        require(
            _initiator == initiator,
            "JoeLiquidator: Untrusted loan initiator"
        );
        require(
            _flashLoanTokenAddress == flashLoanedTokenAddress,
            "JoeLiquidator: Encoded data (flashLoanedTokenAddress) does not match"
        );
        require(
            _flashLoanAmount == flashLoanAmount,
            "JoeLiquidator: Encoded data (flashLoanAmount) does not match"
        );

        LiquidationLocalVars
            memory liquidationLocalVars = LiquidationLocalVars({
                borrowerToLiquidate: borrowerToLiquidate,
                jRepayTokenAddress: jRepayTokenAddress,
                jSeizeTokenAddress: jSeizeTokenAddress,
                repayAmount: repayAmount
            });
        return liquidationLocalVars;
    }

    /**
     * @dev Swaps the flash loan token to the token needed to repay the borrow position
     * @param _flashLoanedTokenAddress The address of the flash loan jToken's underlying asset
     * @param _flashLoanAmount The amount flash loaned
     * @param _jRepayTokenUnderlyingAddress The address of the jToken to repay's underlying asset
     * @param _repayAmount The amount of the borrow position to repay
     */
    function _swapFlashLoanTokenToRepayToken(
        address _flashLoanedTokenAddress,
        uint256 _flashLoanAmount,
        address _jRepayTokenUnderlyingAddress,
        uint256 _repayAmount
    ) internal {
        // Approve JoeRouter to transfer our flash loaned token so that we can swap for
        // the underlying repay token
        ERC20(_flashLoanedTokenAddress).approve(
            joeRouter02Address,
            _flashLoanAmount
        );

        address[] memory swapPath = new address[](2);
        swapPath[0] = _flashLoanedTokenAddress;
        swapPath[1] = _jRepayTokenUnderlyingAddress;

        bool isRepayNative = _jRepayTokenUnderlyingAddress == WAVAX;

        // Swap flashLoanedToken to jRepayTokenUnderlying
        if (isRepayNative) {
            JoeRouter02(joeRouter02Address).swapExactTokensForAVAX(
                _flashLoanAmount, // amountIn
                _repayAmount, // amountOutMin
                swapPath, // path
                address(this), // to
                block.timestamp // deadline
            );
        } else {
            JoeRouter02(joeRouter02Address).swapExactTokensForTokens(
                _flashLoanAmount, // amountIn
                _repayAmount, // amountOutMin
                swapPath, // path
                address(this), // to
                block.timestamp // deadline
            );
        }
    }

    /**
     * @dev Performs liquidation given:
     * - a borrower
     * - a borrow position to repay
     * - a supply position to seize
     * @param _jRepayToken The jToken to repay for liquidation
     * @param _borrowerToLiquidate The borrower to liquidate
     * @param _repayAmount The amount of _jRepayToken's underlying assset to repay
     * @param _jSeizeToken The jToken to seize collateral from
     */
    function _liquidateBorrow(
        JErc20Interface _jRepayToken,
        address _borrowerToLiquidate,
        uint256 _repayAmount,
        JTokenInterface _jSeizeToken
    ) internal {
        bool isRepayNative = _jRepayToken.underlying() == WAVAX;

        // We should have at least `_repayAmount` of underlying repay tokens from
        // swapping the flash loan tokens.
        uint256 repayTokenBalance = isRepayNative
            ? address(this).balance
            : ERC20(_jRepayToken.underlying()).balanceOf(address(this));
        require(
            repayTokenBalance >= _repayAmount,
            "JoeLiquidator: Expected to have enough underlying repay token to liquidate borrow position."
        );

        uint256 err;
        if (isRepayNative) {
            // Perform liquidation and receive jAVAX in return
            err = JWrappedNativeInterface(address(_jRepayToken))
                .liquidateBorrowNative{value: _repayAmount}(
                _borrowerToLiquidate,
                _jSeizeToken
            );
        } else {
            // Approve repay jToken to take our underlying repay tokens so that we
            // can perform liquidation
            ERC20(_jRepayToken.underlying()).approve(
                address(_jRepayToken),
                _repayAmount
            );

            // Perform liquidation and receive jSeizeTokens in return
            err = _jRepayToken.liquidateBorrow(
                _borrowerToLiquidate,
                _repayAmount,
                _jSeizeToken
            );
        }
        require(
            err == 0,
            "JoeLiquidator: Error occurred trying to liquidateBorrow"
        );
    }

    /**
     * @dev Seizes collateral from a jToken market after having successfully performed
     * liquidation
     * @param _jSeizeTokenAddress The address of the jToken to seize collateral from
     */
    function _redeemSeizeToken(address _jSeizeTokenAddress) internal {
        // Get amount of jSeizeToken's we have
        uint256 amountOfJSeizeTokensToRedeem = JTokenInterface(
            _jSeizeTokenAddress
        ).balanceOf(address(this));

        JErc20Interface jSeizeToken = JErc20Interface(_jSeizeTokenAddress);

        bool isSeizeNative = jSeizeToken.underlying() == WAVAX;

        // Redeem `amountOfJSeizeTokensToRedeem` jSeizeTokens for underlying seize tokens
        uint256 err;
        if (isSeizeNative) {
            err = JWrappedNativeInterface(_jSeizeTokenAddress).redeemNative(
                amountOfJSeizeTokensToRedeem
            );
        } else {
            err = jSeizeToken.redeem(amountOfJSeizeTokensToRedeem);
        }

        require(
            err == 0,
            "JoeLiquidator: Error occurred trying to redeem underlying seize tokens"
        );
    }

    /**
     * @dev Swaps enough of the seized collateral to flash loan tokens in order
     * to repay the flash loan amount + flash loan fee
     * @param _jSeizeTokenAddress The address of the jToken to seize collateral from
     * @param _flashLoanTokenAddress The address of the flash loan jToken's underlying asset
     * @param _flashLoanAmountToRepay The flash loan amount + flash loan fee to repay
     */
    function _swapSeizeTokenToFlashLoanToken(
        address _jSeizeTokenAddress,
        address _flashLoanTokenAddress,
        uint256 _flashLoanAmountToRepay
    ) internal {
        JErc20Storage jSeizeToken = JErc20Storage(_jSeizeTokenAddress);
        address jSeizeTokenUnderlyingAddress = jSeizeToken.underlying();

        // Calculate amount of underlying seize token we need
        // to swap in order to pay back the flash loan amount + fee
        address[] memory swapPath = new address[](2);
        swapPath[0] = jSeizeTokenUnderlyingAddress;
        swapPath[1] = _flashLoanTokenAddress;

        uint256 amountOfSeizeTokenToSwap = JoeRouter02(joeRouter02Address)
            .getAmountsIn(_flashLoanAmountToRepay, swapPath)[0];

        bool isSeizeNative = jSeizeTokenUnderlyingAddress == WAVAX;

        // Perform the swap to flash loan tokens!
        if (isSeizeNative) {
            JoeRouter02(joeRouter02Address).swapExactAVAXForTokens{
                value: amountOfSeizeTokenToSwap
            }(
                _flashLoanAmountToRepay, // amountOutMin
                swapPath, // path
                address(this), // to
                block.timestamp // deadline
            );
        } else {
            // Approve router to transfer `amountOfSeizeTokenToSwap` underlying
            // seize tokens
            ERC20 seizeToken = ERC20(jSeizeTokenUnderlyingAddress);
            seizeToken.approve(joeRouter02Address, amountOfSeizeTokenToSwap);

            // Swap seized token to flash loan token
            JoeRouter02(joeRouter02Address).swapExactTokensForTokens(
                amountOfSeizeTokenToSwap, // amountIn
                _flashLoanAmountToRepay, // amountOutMin
                swapPath, // path
                address(this), // to
                block.timestamp // deadline
            );
        }

        // Check we received enough flash loan tokens from the swap to repay the flash loan
        ERC20 flashLoanToken = ERC20(_flashLoanTokenAddress);
        require(
            flashLoanToken.balanceOf(address(this)) >= _flashLoanAmountToRepay,
            "JoeLiquidator: Expected to have enough tokens to repay flash loan after swapping seized tokens."
        );
    }

    /**
     * @dev Swaps all remaining of the seized collateral to AVAX, unless
     * the seized collateral is already AVAX, and sends it to the initiator.
     * @param _initiator The initiator of the flash loan, aka the liquidator
     * @param _jSeizeTokenAddress The address of jToken collateral was seized from
     * @return The AVAX received as profit from performing the liquidation.
     */
    function _swapRemainingSeizedTokenToAVAX(
        address _initiator,
        address _jSeizeTokenAddress
    ) internal returns (uint256) {
        JErc20Storage jSeizeToken = JErc20Storage(_jSeizeTokenAddress);
        address jSeizeTokenUnderlyingAddress = jSeizeToken.underlying();

        bool isSeizeNative = jSeizeTokenUnderlyingAddress == WAVAX;
        if (isSeizeNative) {
            // The seized collateral was AVAX so we can do a simple transfer to the liquidator
            uint256 profitedAVAX = address(this).balance;

            (bool success, ) = _initiator.call{value: profitedAVAX}("");
            require(
                success,
                "JoeLiquidator: Failed to transfer native AVAX to liquidator"
            );

            return profitedAVAX;
        } else {
            // Swap seized token to AVAX
            ERC20 seizeToken = ERC20(jSeizeTokenUnderlyingAddress);
            uint256 remainingSeizeAmount = seizeToken.balanceOf(address(this));

            require(
                remainingSeizeAmount > 0,
                "JoeLiquidator: Expected to have remaining seize amount in order to have profited from liquidation"
            );

            seizeToken.approve(joeRouter02Address, remainingSeizeAmount);

            address[] memory swapPath = new address[](2);
            swapPath[0] = jSeizeTokenUnderlyingAddress;
            swapPath[1] = WAVAX;

            uint256[] memory amounts = JoeRouter02(joeRouter02Address)
                .swapExactTokensForAVAX(
                    remainingSeizeAmount, // amountIn
                    0, // amountOutMin
                    swapPath, // path
                    _initiator, // to
                    block.timestamp // deadline
                );

            // Return profitted AVAX
            return amounts[1];
        }
    }

    /**
     * @notice Approves the flash loan jToken to retrieve the flash loan amount + fee.
     * @param _flashLoanTokenAddress The address of the flash loan jToken's underlying asset
     * @param _flashLoanAmountToRepay The flash loan amount to repay
     */
    function _approveFlashLoanToken(
        address _flashLoanTokenAddress,
        uint256 _flashLoanAmountToRepay
    ) internal {
        ERC20 flashLoanToken = ERC20(_flashLoanTokenAddress);

        // Ensure we have enough to repay flash loan
        require(
            flashLoanToken.balanceOf(address(this)) >= _flashLoanAmountToRepay,
            "JoeLiquidator: Expected to have enough tokens to repay flash loan after swapping seized tokens."
        );

        // Approve flash loan lender to retrieve loan amount + fee from us
        flashLoanToken.approve(msg.sender, _flashLoanAmountToRepay);
    }
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"_joetrollerAddress","type":"address"},{"internalType":"address","name":"_joeRouter02Address","type":"address"},{"internalType":"address","name":"_jUSDCAddress","type":"address"},{"internalType":"address","name":"_jWETHAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_borrowerLiquidated","type":"address"},{"indexed":false,"internalType":"address","name":"_jRepayToken","type":"address"},{"indexed":false,"internalType":"address","name":"_jSeizeToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"_repayAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_profitedAVAX","type":"uint256"}],"name":"LiquidationEvent","type":"event"},{"inputs":[],"name":"USDC","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WAVAX","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"jUSDCAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"jWETHAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"joeRouter02Address","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"joetrollerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrowerToLiquidate","type":"address"},{"internalType":"address","name":"_jRepayTokenAddress","type":"address"},{"internalType":"address","name":"_jSeizeTokenAddress","type":"address"}],"name":"liquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_initiator","type":"address"},{"internalType":"address","name":"_flashLoanTokenAddress","type":"address"},{"internalType":"uint256","name":"_flashLoanAmount","type":"uint256"},{"internalType":"uint256","name":"_flashLoanFee","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"onFlashLoan","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60806040523480156200001157600080fd5b5060405162004387380380620043878339818101604052810190620000379190620001ae565b836000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050505062000220565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620001768262000149565b9050919050565b620001888162000169565b81146200019457600080fd5b50565b600081519050620001a8816200017d565b92915050565b60008060008060808587031215620001cb57620001ca62000144565b5b6000620001db8782880162000197565b9450506020620001ee8782880162000197565b9350506040620002018782880162000197565b9250506060620002148782880162000197565b91505092959194509250565b61415780620002306000396000f3fe60806040526004361061008a5760003560e01c806389a302711161005957806389a3027114610154578063ad5c46481461017f578063c62d2751146101aa578063ca5ce2ec146101d5578063e62fbf6a146101fe57610091565b8063218377a01461009657806323e30c8b146100c157806373b295c2146100fe578063897857b81461012957610091565b3661009157005b600080fd5b3480156100a257600080fd5b506100ab610229565b6040516100b89190612b52565b60405180910390f35b3480156100cd57600080fd5b506100e860048036038101906100e39190612c48565b61024f565b6040516100f59190612cfb565b60405180910390f35b34801561010a57600080fd5b50610113610522565b6040516101209190612b52565b60405180910390f35b34801561013557600080fd5b5061013e61053a565b60405161014b9190612b52565b60405180910390f35b34801561016057600080fd5b5061016961055e565b6040516101769190612b52565b60405180910390f35b34801561018b57600080fd5b50610194610576565b6040516101a19190612b52565b60405180910390f35b3480156101b657600080fd5b506101bf61058e565b6040516101cc9190612b52565b60405180910390f35b3480156101e157600080fd5b506101fc60048036038101906101f79190612d16565b6105b4565b005b34801561020a57600080fd5b50610213610711565b6040516102209190612b52565b60405180910390f35b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633d98a1e5336040518263ffffffff1660e01b81526004016102ab9190612b52565b60206040518083038186803b1580156102c357600080fd5b505afa1580156102d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102fb9190612da1565b61033a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161033190612e51565b60405180910390fd5b60006103498888888787610737565b90506000610360868861090090919063ffffffff16565b90506000826000015190506103fa89898373ffffffffffffffffffffffffffffffffffffffff16636f307dc36040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156103b857600080fd5b505af11580156103cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103f09190612e86565b8660600151610916565b61041281846040015185606001518660200151610c62565b61041f83602001516110ea565b61042e83602001518a846113b4565b600061043e8b8560200151611932565b905060008111610483576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161047a90612f25565b60405180910390fd5b61048d8a84611e16565b836040015173ffffffffffffffffffffffffffffffffffffffff167f1683d07b2bca5806ccc25a2d5ecdad3343784e4ed273236e2a53890b4f1d95a6856000015186602001518760600151856040516104e99493929190612f54565b60405180910390a27f7968ba28153757de2da7bce4c2ba9ebaf94445061f3050de1b0de5c34bb7d5d89450505050509695505050505050565b73b31f66aa3c1e785363f0875a1b74e27b85fd66c781565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b73a7d7079b0fead91f3e65f86e8915cb59c1a4c66481565b7349d5c2bdffac6ce2bfdb6640f4f80f226bc10bab81565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b8260008060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635ec88c79846040518263ffffffff1660e01b81526004016106119190612b52565b60606040518083038186803b15801561062957600080fd5b505afa15801561063d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106619190612fae565b9250925050600082146106a9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106a090613073565b60405180910390fd5b60008114156106ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106e490613105565b60405180910390fd5b60006106fa878787611f58565b905061070887878784612348565b50505050505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61073f612a94565b600080600080600080600089898101906107599190613163565b96509650965096509650965096508673ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff16146107d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107cc90613277565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff168c73ffffffffffffffffffffffffffffffffffffffff1614610843576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161083a9061332f565b60405180910390fd5b818b14610885576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161087c906133c1565b60405180910390fd5b600060405180608001604052808773ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018873ffffffffffffffffffffffffffffffffffffffff168152602001838152509050809850505050505050505095945050505050565b6000818361090e9190613410565b905092915050565b8373ffffffffffffffffffffffffffffffffffffffff1663095ea7b3600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16856040518363ffffffff1660e01b8152600401610973929190613466565b600060405180830381600087803b15801561098d57600080fd5b505af11580156109a1573d6000803e3d6000fd5b505050506000600267ffffffffffffffff8111156109c2576109c161348f565b5b6040519080825280602002602001820160405280156109f05781602001602082028036833780820191505090505b5090508481600081518110610a0857610a076134be565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508281600181518110610a5757610a566134be565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600073b31f66aa3c1e785363f0875a1b74e27b85fd66c773ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161490508015610b9e57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663676528d186858530426040518663ffffffff1660e01b8152600401610b419594939291906135ab565b600060405180830381600087803b158015610b5b57600080fd5b505af1158015610b6f573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610b989190613725565b50610c5a565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338ed173986858530426040518663ffffffff1660e01b8152600401610c019594939291906135ab565b600060405180830381600087803b158015610c1b57600080fd5b505af1158015610c2f573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610c589190613725565b505b505050505050565b600073b31f66aa3c1e785363f0875a1b74e27b85fd66c773ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16636f307dc36040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610cd757600080fd5b505af1158015610ceb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d0f9190612e86565b73ffffffffffffffffffffffffffffffffffffffff16149050600081610e3c578573ffffffffffffffffffffffffffffffffffffffff16636f307dc36040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610d7757600080fd5b505af1158015610d8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610daf9190612e86565b73ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610de79190612b52565b60206040518083038186803b158015610dff57600080fd5b505afa158015610e13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e37919061376e565b610e3e565b475b905083811015610e83576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e7a90613833565b60405180910390fd5b60008215610f20578673ffffffffffffffffffffffffffffffffffffffff1663291727a48688876040518463ffffffff1660e01b8152600401610ec79291906138b2565b6020604051808303818588803b158015610ee057600080fd5b505af1158015610ef4573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610f19919061376e565b905061109e565b8673ffffffffffffffffffffffffffffffffffffffff16636f307dc36040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610f6857600080fd5b505af1158015610f7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa09190612e86565b73ffffffffffffffffffffffffffffffffffffffff1663095ea7b388876040518363ffffffff1660e01b8152600401610fda929190613466565b600060405180830381600087803b158015610ff457600080fd5b505af1158015611008573d6000803e3d6000fd5b505050508673ffffffffffffffffffffffffffffffffffffffff1663f5e3c4628787876040518463ffffffff1660e01b8152600401611049939291906138db565b602060405180830381600087803b15801561106357600080fd5b505af1158015611077573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061109b919061376e565b90505b600081146110e1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110d890613984565b60405180910390fd5b50505050505050565b60008173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016111259190612b52565b60206040518083038186803b15801561113d57600080fd5b505afa158015611151573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611175919061376e565b90506000829050600073b31f66aa3c1e785363f0875a1b74e27b85fd66c773ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16636f307dc36040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156111f157600080fd5b505af1158015611205573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112299190612e86565b73ffffffffffffffffffffffffffffffffffffffff16149050600081156112dc578473ffffffffffffffffffffffffffffffffffffffff16634bf03edf856040518263ffffffff1660e01b815260040161128391906139a4565b602060405180830381600087803b15801561129d57600080fd5b505af11580156112b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d5919061376e565b905061136a565b8273ffffffffffffffffffffffffffffffffffffffff1663db006a75856040518263ffffffff1660e01b815260040161131591906139a4565b602060405180830381600087803b15801561132f57600080fd5b505af1158015611343573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611367919061376e565b90505b600081146113ad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113a490613a57565b60405180910390fd5b5050505050565b600083905060008173ffffffffffffffffffffffffffffffffffffffff16636f307dc36040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561140357600080fd5b505af1158015611417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061143b9190612e86565b90506000600267ffffffffffffffff81111561145a5761145961348f565b5b6040519080825280602002602001820160405280156114885781602001602082028036833780820191505090505b50905081816000815181106114a05761149f6134be565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505084816001815181106114ef576114ee6134be565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631f00ca7486846040518363ffffffff1660e01b8152600401611588929190613a77565b60006040518083038186803b1580156115a057600080fd5b505afa1580156115b4573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906115dd9190613725565b6000815181106115f0576115ef6134be565b5b60200260200101519050600073b31f66aa3c1e785363f0875a1b74e27b85fd66c773ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16149050801561170657600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a2a1623d83888630426040518663ffffffff1660e01b81526004016116a99493929190613aa7565b6000604051808303818588803b1580156116c257600080fd5b505af11580156116d6573d6000803e3d6000fd5b50505050506040513d6000823e3d601f19601f820116820180604052508101906117009190613725565b50611857565b60008490508073ffffffffffffffffffffffffffffffffffffffff1663095ea7b3600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16856040518363ffffffff1660e01b8152600401611768929190613466565b600060405180830381600087803b15801561178257600080fd5b505af1158015611796573d6000803e3d6000fd5b50505050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338ed173984898730426040518663ffffffff1660e01b81526004016117fd9594939291906135ab565b600060405180830381600087803b15801561181757600080fd5b505af115801561182b573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906118549190613725565b50505b6000879050868173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016118969190612b52565b60206040518083038186803b1580156118ae57600080fd5b505afa1580156118c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118e6919061376e565b1015611927576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161191e90613b8b565b60405180910390fd5b505050505050505050565b60008082905060008173ffffffffffffffffffffffffffffffffffffffff16636f307dc36040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561198257600080fd5b505af1158015611996573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ba9190612e86565b9050600073b31f66aa3c1e785363f0875a1b74e27b85fd66c773ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161490508015611ac757600047905060008773ffffffffffffffffffffffffffffffffffffffff1682604051611a3490613bdc565b60006040518083038185875af1925050503d8060008114611a71576040519150601f19603f3d011682016040523d82523d6000602084013e611a76565b606091505b5050905080611aba576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ab190613c63565b60405180910390fd5b8195505050505050611e10565b600082905060008173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401611b079190612b52565b60206040518083038186803b158015611b1f57600080fd5b505afa158015611b33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b57919061376e565b905060008111611b9c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b9390613d41565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1663095ea7b3600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b8152600401611bf9929190613466565b600060405180830381600087803b158015611c1357600080fd5b505af1158015611c27573d6000803e3d6000fd5b505050506000600267ffffffffffffffff811115611c4857611c4761348f565b5b604051908082528060200260200182016040528015611c765781602001602082028036833780820191505090505b5090508481600081518110611c8e57611c8d6134be565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073b31f66aa3c1e785363f0875a1b74e27b85fd66c781600181518110611cf157611cf06134be565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663676528d1846000858e426040518663ffffffff1660e01b8152600401611d91959493929190613d9c565b600060405180830381600087803b158015611dab57600080fd5b505af1158015611dbf573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611de89190613725565b905080600181518110611dfe57611dfd6134be565b5b60200260200101519750505050505050505b92915050565b6000829050818173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401611e559190612b52565b60206040518083038186803b158015611e6d57600080fd5b505afa158015611e81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea5919061376e565b1015611ee6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611edd90613b8b565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1663095ea7b333846040518363ffffffff1660e01b8152600401611f21929190613466565b600060405180830381600087803b158015611f3b57600080fd5b505af1158015611f4f573d6000803e3d6000fd5b50505050505050565b60008060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008173ffffffffffffffffffffffffffffffffffffffff16637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b158015611fc657600080fd5b505afa158015611fda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ffe9190613e34565b905060008273ffffffffffffffffffffffffffffffffffffffff1663e87554466040518163ffffffff1660e01b815260040160206040518083038186803b15801561204857600080fd5b505afa15801561205c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612080919061376e565b905060008373ffffffffffffffffffffffffffffffffffffffff16634ada90af6040518163ffffffff1660e01b815260040160206040518083038186803b1580156120ca57600080fd5b505afa1580156120de573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612102919061376e565b905060008373ffffffffffffffffffffffffffffffffffffffff1663fc57d4df896040518263ffffffff1660e01b815260040161213f9190613e82565b60206040518083038186803b15801561215757600080fd5b505afa15801561216b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218f919061376e565b905060008473ffffffffffffffffffffffffffffffffffffffff1663fc57d4df896040518263ffffffff1660e01b81526004016121cc9190613e82565b60206040518083038186803b1580156121e457600080fd5b505afa1580156121f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061221c919061376e565b90506000670de0b6b3a7640000858b73ffffffffffffffffffffffffffffffffffffffff166395dd91938e6040518263ffffffff1660e01b81526004016122639190612b52565b60206040518083038186803b15801561227b57600080fd5b505afa15801561228f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122b3919061376e565b6122bd9190613e9d565b6122c79190613f26565b9050600084670de0b6b3a76400006122df8c8f61257b565b6122e99190613e9d565b6122f39190613f26565b9050600084836123039190613e9d565b9050600084836123139190613e9d565b905060008183106123245781612326565b825b905086816123349190613f26565b9b5050505050505050505050509392505050565b60008373ffffffffffffffffffffffffffffffffffffffff16636f307dc36040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561239257600080fd5b505af11580156123a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ca9190612e86565b9050600073a7d7079b0fead91f3e65f86e8915cb59c1a4c66473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614905060006124208385846126ad565b9050600061242d836128f4565b90506000338989898573ffffffffffffffffffffffffffffffffffffffff16636f307dc36040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561247d57600080fd5b505af1158015612491573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124b59190612e86565b878b6040516020016124cd9796959493929190613f57565b60405160208183030381529060405290508173ffffffffffffffffffffffffffffffffffffffff16635cffe9de303386856040518563ffffffff1660e01b815260040161251d949392919061406f565b602060405180830381600087803b15801561253757600080fd5b505af115801561254b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061256f9190612da1565b50505050505050505050565b600080839050600060405180602001604052808373ffffffffffffffffffffffffffffffffffffffff1663182df0f56040518163ffffffff1660e01b815260040160206040518083038186803b1580156125d457600080fd5b505afa1580156125e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061260c919061376e565b81525090506126a3818373ffffffffffffffffffffffffffffffffffffffff166370a08231876040518263ffffffff1660e01b815260040161264e9190612b52565b60206040518083038186803b15801561266657600080fd5b505afa15801561267a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061269e919061376e565b612951565b9250505092915050565b600080600267ffffffffffffffff8111156126cb576126ca61348f565b5b6040519080825280602002602001820160405280156126f95781602001602082028036833780820191505090505b509050821561276a577349d5c2bdffac6ce2bfdb6640f4f80f226bc10bab8160008151811061272b5761272a6134be565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506127ce565b73a7d7079b0fead91f3e65f86e8915cb59c1a4c66481600081518110612793576127926134be565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b84816001815181106127e3576127e26134be565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631f00ca7485836040518363ffffffff1660e01b815260040161287a929190613a77565b60006040518083038186803b15801561289257600080fd5b505afa1580156128a6573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906128cf9190613725565b6000815181106128e2576128e16134be565b5b60200260200101519150509392505050565b6000811561292657600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905061294c565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b919050565b60008061295e8484612972565b90506129698161299e565b91505092915050565b61297a612afe565b60405180602001604052806129938560000151856129bf565b815250905092915050565b6000670de0b6b3a764000082600001516129b89190613f26565b9050919050565b6000612a0183836040518060400160405280601781526020017f6d756c7469706c69636174696f6e206f766572666c6f77000000000000000000815250612a09565b905092915050565b600080841480612a195750600083145b15612a275760009050612a8d565b60008385612a359190613e9d565b9050838582612a449190613f26565b148390612a87576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a7e91906140ff565b60405180910390fd5b50809150505b9392505050565b6040518060800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b6040518060200160405280600081525090565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612b3c82612b11565b9050919050565b612b4c81612b31565b82525050565b6000602082019050612b676000830184612b43565b92915050565b6000604051905090565b600080fd5b600080fd5b612b8a81612b31565b8114612b9557600080fd5b50565b600081359050612ba781612b81565b92915050565b6000819050919050565b612bc081612bad565b8114612bcb57600080fd5b50565b600081359050612bdd81612bb7565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f840112612c0857612c07612be3565b5b8235905067ffffffffffffffff811115612c2557612c24612be8565b5b602083019150836001820283011115612c4157612c40612bed565b5b9250929050565b60008060008060008060a08789031215612c6557612c64612b77565b5b6000612c7389828a01612b98565b9650506020612c8489828a01612b98565b9550506040612c9589828a01612bce565b9450506060612ca689828a01612bce565b935050608087013567ffffffffffffffff811115612cc757612cc6612b7c565b5b612cd389828a01612bf2565b92509250509295509295509295565b6000819050919050565b612cf581612ce2565b82525050565b6000602082019050612d106000830184612cec565b92915050565b600080600060608486031215612d2f57612d2e612b77565b5b6000612d3d86828701612b98565b9350506020612d4e86828701612b98565b9250506040612d5f86828701612b98565b9150509250925092565b60008115159050919050565b612d7e81612d69565b8114612d8957600080fd5b50565b600081519050612d9b81612d75565b92915050565b600060208284031215612db757612db6612b77565b5b6000612dc584828501612d8c565b91505092915050565b600082825260208201905092915050565b7f4a6f654c697175696461746f723a20556e74727573746564206d65737361676560008201527f2073656e6465722063616c6c696e67206f6e466c6173684c6f616e0000000000602082015250565b6000612e3b603b83612dce565b9150612e4682612ddf565b604082019050919050565b60006020820190508181036000830152612e6a81612e2e565b9050919050565b600081519050612e8081612b81565b92915050565b600060208284031215612e9c57612e9b612b77565b5b6000612eaa84828501612e71565b91505092915050565b7f4a6f654c697175696461746f723a20457870656374656420746f20686176652060008201527f70726f66697465642066726f6d206c69717569646174696f6e00000000000000602082015250565b6000612f0f603983612dce565b9150612f1a82612eb3565b604082019050919050565b60006020820190508181036000830152612f3e81612f02565b9050919050565b612f4e81612bad565b82525050565b6000608082019050612f696000830187612b43565b612f766020830186612b43565b612f836040830185612f45565b612f906060830184612f45565b95945050505050565b600081519050612fa881612bb7565b92915050565b600080600060608486031215612fc757612fc6612b77565b5b6000612fd586828701612f99565b9350506020612fe686828701612f99565b9250506040612ff786828701612f99565b9150509250925092565b7f4a6f654c697175696461746f723a2043616e6e6f74206c69717569646174652060008201527f6163636f756e742077697468206e6f6e2d7a65726f206c697175696469747900602082015250565b600061305d603f83612dce565b915061306882613001565b604082019050919050565b6000602082019050818103600083015261308c81613050565b9050919050565b7f4a6f654c697175696461746f723a2043616e6e6f74206c69717569646174652060008201527f6163636f756e742077697468207a65726f2073686f727466616c6c0000000000602082015250565b60006130ef603b83612dce565b91506130fa82613093565b604082019050919050565b6000602082019050818103600083015261311e816130e2565b9050919050565b600061313082612b11565b9050919050565b61314081613125565b811461314b57600080fd5b50565b60008135905061315d81613137565b92915050565b600080600080600080600060e0888a03121561318257613181612b77565b5b60006131908a828b0161314e565b97505060206131a18a828b0161314e565b96505060406131b28a828b0161314e565b95505060606131c38a828b0161314e565b94505060806131d48a828b0161314e565b93505060a06131e58a828b01612bce565b92505060c06131f68a828b01612bce565b91505092959891949750929550565b7f4a6f654c697175696461746f723a20556e74727573746564206c6f616e20696e60008201527f69746961746f7200000000000000000000000000000000000000000000000000602082015250565b6000613261602783612dce565b915061326c82613205565b604082019050919050565b6000602082019050818103600083015261329081613254565b9050919050565b7f4a6f654c697175696461746f723a20456e636f64656420646174612028666c6160008201527f73684c6f616e6564546f6b656e416464726573732920646f6573206e6f74206d60208201527f6174636800000000000000000000000000000000000000000000000000000000604082015250565b6000613319604483612dce565b915061332482613297565b606082019050919050565b600060208201905081810360008301526133488161330c565b9050919050565b7f4a6f654c697175696461746f723a20456e636f64656420646174612028666c6160008201527f73684c6f616e416d6f756e742920646f6573206e6f74206d6174636800000000602082015250565b60006133ab603c83612dce565b91506133b68261334f565b604082019050919050565b600060208201905081810360008301526133da8161339e565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061341b82612bad565b915061342683612bad565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111561345b5761345a6133e1565b5b828201905092915050565b600060408201905061347b6000830185612b43565b6134886020830184612f45565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61352281612b31565b82525050565b60006135348383613519565b60208301905092915050565b6000602082019050919050565b6000613558826134ed565b61356281856134f8565b935061356d83613509565b8060005b8381101561359e5781516135858882613528565b975061359083613540565b925050600181019050613571565b5085935050505092915050565b600060a0820190506135c06000830188612f45565b6135cd6020830187612f45565b81810360408301526135df818661354d565b90506135ee6060830185612b43565b6135fb6080830184612f45565b9695505050505050565b6000601f19601f8301169050919050565b61361f82613605565b810181811067ffffffffffffffff8211171561363e5761363d61348f565b5b80604052505050565b6000613651612b6d565b905061365d8282613616565b919050565b600067ffffffffffffffff82111561367d5761367c61348f565b5b602082029050602081019050919050565b60006136a161369c84613662565b613647565b905080838252602082019050602084028301858111156136c4576136c3612bed565b5b835b818110156136ed57806136d98882612f99565b8452602084019350506020810190506136c6565b5050509392505050565b600082601f83011261370c5761370b612be3565b5b815161371c84826020860161368e565b91505092915050565b60006020828403121561373b5761373a612b77565b5b600082015167ffffffffffffffff81111561375957613758612b7c565b5b613765848285016136f7565b91505092915050565b60006020828403121561378457613783612b77565b5b600061379284828501612f99565b91505092915050565b7f4a6f654c697175696461746f723a20457870656374656420746f20686176652060008201527f656e6f75676820756e6465726c79696e6720726570617920746f6b656e20746f60208201527f206c697175696461746520626f72726f7720706f736974696f6e2e0000000000604082015250565b600061381d605b83612dce565b91506138288261379b565b606082019050919050565b6000602082019050818103600083015261384c81613810565b9050919050565b6000819050919050565b600061387861387361386e84612b11565b613853565b612b11565b9050919050565b600061388a8261385d565b9050919050565b600061389c8261387f565b9050919050565b6138ac81613891565b82525050565b60006040820190506138c76000830185612b43565b6138d460208301846138a3565b9392505050565b60006060820190506138f06000830186612b43565b6138fd6020830185612f45565b61390a60408301846138a3565b949350505050565b7f4a6f654c697175696461746f723a204572726f72206f6363757272656420747260008201527f79696e6720746f206c6971756964617465426f72726f77000000000000000000602082015250565b600061396e603783612dce565b915061397982613912565b604082019050919050565b6000602082019050818103600083015261399d81613961565b9050919050565b60006020820190506139b96000830184612f45565b92915050565b7f4a6f654c697175696461746f723a204572726f72206f6363757272656420747260008201527f79696e6720746f2072656465656d20756e6465726c79696e67207365697a652060208201527f746f6b656e730000000000000000000000000000000000000000000000000000604082015250565b6000613a41604683612dce565b9150613a4c826139bf565b606082019050919050565b60006020820190508181036000830152613a7081613a34565b9050919050565b6000604082019050613a8c6000830185612f45565b8181036020830152613a9e818461354d565b90509392505050565b6000608082019050613abc6000830187612f45565b8181036020830152613ace818661354d565b9050613add6040830185612b43565b613aea6060830184612f45565b95945050505050565b7f4a6f654c697175696461746f723a20457870656374656420746f20686176652060008201527f656e6f75676820746f6b656e7320746f20726570617920666c617368206c6f6160208201527f6e206166746572207377617070696e67207365697a656420746f6b656e732e00604082015250565b6000613b75605f83612dce565b9150613b8082613af3565b606082019050919050565b60006020820190508181036000830152613ba481613b68565b9050919050565b600081905092915050565b50565b6000613bc6600083613bab565b9150613bd182613bb6565b600082019050919050565b6000613be782613bb9565b9150819050919050565b7f4a6f654c697175696461746f723a204661696c656420746f207472616e73666560008201527f72206e6174697665204156415820746f206c697175696461746f720000000000602082015250565b6000613c4d603b83612dce565b9150613c5882613bf1565b604082019050919050565b60006020820190508181036000830152613c7c81613c40565b9050919050565b7f4a6f654c697175696461746f723a20457870656374656420746f20686176652060008201527f72656d61696e696e67207365697a6520616d6f756e7420696e206f726465722060208201527f746f20686176652070726f66697465642066726f6d206c69717569646174696f60408201527f6e00000000000000000000000000000000000000000000000000000000000000606082015250565b6000613d2b606183612dce565b9150613d3682613c83565b608082019050919050565b60006020820190508181036000830152613d5a81613d1e565b9050919050565b6000819050919050565b6000613d86613d81613d7c84613d61565b613853565b612bad565b9050919050565b613d9681613d6b565b82525050565b600060a082019050613db16000830188612f45565b613dbe6020830187613d8d565b8181036040830152613dd0818661354d565b9050613ddf6060830185612b43565b613dec6080830184612f45565b9695505050505050565b6000613e0182612b31565b9050919050565b613e1181613df6565b8114613e1c57600080fd5b50565b600081519050613e2e81613e08565b92915050565b600060208284031215613e4a57613e49612b77565b5b6000613e5884828501613e1f565b91505092915050565b6000613e6c8261387f565b9050919050565b613e7c81613e61565b82525050565b6000602082019050613e976000830184613e73565b92915050565b6000613ea882612bad565b9150613eb383612bad565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615613eec57613eeb6133e1565b5b828202905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000613f3182612bad565b9150613f3c83612bad565b925082613f4c57613f4b613ef7565b5b828204905092915050565b600060e082019050613f6c600083018a612b43565b613f796020830189612b43565b613f866040830188612b43565b613f936060830187612b43565b613fa06080830186612b43565b613fad60a0830185612f45565b613fba60c0830184612f45565b98975050505050505050565b6000613fd18261387f565b9050919050565b613fe181613fc6565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015614021578082015181840152602081019050614006565b83811115614030576000848401525b50505050565b600061404182613fe7565b61404b8185613ff2565b935061405b818560208601614003565b61406481613605565b840191505092915050565b60006080820190506140846000830187613fd8565b6140916020830186612b43565b61409e6040830185612f45565b81810360608301526140b08184614036565b905095945050505050565b600081519050919050565b60006140d1826140bb565b6140db8185612dce565b93506140eb818560208601614003565b6140f481613605565b840191505092915050565b6000602082019050818103600083015261411981846140c6565b90509291505056fea264697066735822122030f82ddb7939846bbf3111eb31139576c8a2ba5ac7c4a223a48dead1d332665964736f6c63430008090033000000000000000000000000dc13687554205e5b89ac783db14bb5bba4a1edac00000000000000000000000060ae616a2155ee3d9a68541ba4544862310933d4000000000000000000000000ed6aaf91a2b084bd594dbd1245be3691f9f637ac000000000000000000000000929f5cab61dfec79a5431a7734a68d714c4633fa

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

000000000000000000000000dc13687554205e5b89ac783db14bb5bba4a1edac00000000000000000000000060ae616a2155ee3d9a68541ba4544862310933d4000000000000000000000000ed6aaf91a2b084bd594dbd1245be3691f9f637ac000000000000000000000000929f5cab61dfec79a5431a7734a68d714c4633fa

-----Decoded View---------------
Arg [0] : _joetrollerAddress (address): 0xdc13687554205e5b89ac783db14bb5bba4a1edac
Arg [1] : _joeRouter02Address (address): 0x60ae616a2155ee3d9a68541ba4544862310933d4
Arg [2] : _jUSDCAddress (address): 0xed6aaf91a2b084bd594dbd1245be3691f9f637ac
Arg [3] : _jWETHAddress (address): 0x929f5cab61dfec79a5431a7734a68d714c4633fa

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000dc13687554205e5b89ac783db14bb5bba4a1edac
Arg [1] : 00000000000000000000000060ae616a2155ee3d9a68541ba4544862310933d4
Arg [2] : 000000000000000000000000ed6aaf91a2b084bd594dbd1245be3691f9f637ac
Arg [3] : 000000000000000000000000929f5cab61dfec79a5431a7734a68d714c4633fa


Deployed ByteCode Sourcemap

18192:26664:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18467:27;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;28326:3385;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;18549:74;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;18354:32;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;18710:73;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;18630;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;18433:27;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;20824:524;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;18393:33;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;18467:27;;;;;;;;;;;;;:::o;28326:3385::-;28549:7;28602:17;;;;;;;;;;;28591:44;;;28636:10;28591:56;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;28569:165;;;;;;;;;;;;:::i;:::-;;;;;;;;;28747:61;28811:168;28854:10;28883:22;28924:16;28959:5;;28811:24;:168::i;:::-;28747:232;;28992:30;29025:35;29046:13;29025:16;:20;;:35;;;;:::i;:::-;28992:68;;29279:27;29339:20;:39;;;29279:110;;29508:196;29554:22;29591:16;29622:11;:22;;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;29661:20;:32;;;29508:31;:196::i;:::-;29845:226;29876:11;29902:20;:40;;;29957:20;:32;;;30020:20;:39;;;29845:16;:226::i;:::-;30144:58;30162:20;:39;;;30144:17;:58::i;:::-;30336:170;30382:20;:39;;;30436:22;30473;30336:31;:170::i;:::-;30644:20;30667:121;30713:10;30738:20;:39;;;30667:31;:121::i;:::-;30644:144;;30838:1;30823:12;:16;30801:123;;;;;;;;;;;;:::i;:::-;;;;;;;;;31219:70;31242:22;31266;31219;:70::i;:::-;31396:20;:40;;;31365:264;;;31451:20;:39;;;31505:20;:39;;;31559:20;:32;;;31606:12;31365:264;;;;;;;;;:::i;:::-;;;;;;;;31649:54;31642:61;;;;;;28326:3385;;;;;;;;:::o;18549:74::-;18581:42;18549:74;:::o;18354:32::-;;;;;;;;;;;;:::o;18710:73::-;18741:42;18710:73;:::o;18630:::-;18661:42;18630:73;:::o;18433:27::-;;;;;;;;;;;;;:::o;20824:524::-;20989:20;20077:17;20096;20128;;;;;;;;;;20117:63;;;20181:20;20117:85;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;20074:128;;;;;20248:1;20235:9;:14;20213:127;;;;;;;;;;;;:::i;:::-;;;;;;;;;20386:1;20373:9;:14;;20351:123;;;;;;;;;;;;:::i;:::-;;;;;;;;;21022:21:::1;21046:130;21077:20;21112:19;21146;21046:16;:130::i;:::-;21022:154;;21187:153;21213:20;21248:19;21282;21316:13;21187:11;:153::i;:::-;21011:337;20063:431:::0;;20824:524;;;;:::o;18393:33::-;;;;;;;;;;;;;:::o;32228:1528::-;32428:27;;:::i;:::-;32483:17;32515:27;32557:26;32598;32639:31;32685:23;32723:19;32785:5;;32756:131;;;;;;;:::i;:::-;32468:419;;;;;;;;;;;;;;32970:9;32956:23;;:10;:23;;;32934:112;;;;;;;;;;;;:::i;:::-;;;;;;;;;33105:23;33079:49;;:22;:49;;;33057:167;;;;;;;;;;;;:::i;:::-;;;;;;;;;33277:15;33257:16;:35;33235:145;;;;;;;;;;;;:::i;:::-;;;;;;;;;33393:61;33457:253;;;;;;;;33576:18;33457:253;;;;;;33633:18;33457:253;;;;;;33518:19;33457:253;;;;;;33683:11;33457:253;;;33393:317;;33728:20;33721:27;;;;;;;;;;32228:1528;;;;;;;:::o;2941:98::-;2999:7;3030:1;3026;:5;;;;:::i;:::-;3019:12;;2941:98;;;;:::o;34193:1423::-;34552:24;34546:39;;;34600:18;;;;;;;;;;;34633:16;34546:114;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;34673:25;34715:1;34701:16;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;34673:44;;34742:24;34728:8;34737:1;34728:11;;;;;;;;:::i;:::-;;;;;;;:38;;;;;;;;;;;34791:29;34777:8;34786:1;34777:11;;;;;;;;:::i;:::-;;;;;;;:43;;;;;;;;;;;34833:18;18581:42;34854:38;;:29;:38;;;34833:59;;34968:13;34964:645;;;35010:18;;;;;;;;;;;34998:54;;;35071:16;35118:12;35165:8;35208:4;35238:15;34998:282;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;34964:645;;;35325:18;;;;;;;;;;;35313:56;;;35388:16;35435:12;35482:8;35525:4;35555:15;35313:284;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;34964:645;34407:1209;;34193:1423;;;;:::o;36052:1727::-;36253:18;18581:42;36274:34;;:12;:23;;;:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:34;;;36253:55;;36448:25;36476:13;:123;;36548:12;:23;;;:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;36542:42;;;36593:4;36542:57;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;36476:123;;;36505:21;36476:123;36448:151;;36653:12;36632:17;:33;;36610:174;;;;;;;;;;;;:::i;:::-;;;;;;;;;36797:11;36823:13;36819:829;;;36955:12;36923:86;;;37017:12;37049:20;37088:12;36923:192;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;36917:198;;36819:829;;;37278:12;:23;;;:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;37272:40;;;37339:12;37371;37272:126;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37492:12;:28;;;37539:20;37578:12;37609;37492:144;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;37486:150;;36819:829;37687:1;37680:3;:8;37658:113;;;;;;;;;;;;:::i;:::-;;;;;;;;;36242:1537;;;36052:1727;;;;:::o;37999:926::-;38123:36;38192:19;38162:70;;;38241:4;38162:85;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;38123:124;;38260:27;38306:19;38260:66;;38339:18;18581:42;38360:33;;:11;:22;;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:33;;;38339:54;;38497:11;38523:13;38519:258;;;38583:19;38559:57;;;38635:28;38559:119;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;38553:125;;38519:258;;;38717:11;:18;;;38736:28;38717:48;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;38711:54;;38519:258;38818:1;38811:3;:8;38789:128;;;;;;;;;;;;:::i;:::-;;;;;;;;;38064:861;;;;37999:926;:::o;39355:2287::-;39544:25;39586:19;39544:62;;39617:36;39656:11;:22;;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;39617:63;;39825:25;39867:1;39853:16;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;39825:44;;39894:28;39880:8;39889:1;39880:11;;;;;;;;:::i;:::-;;;;;;;:42;;;;;;;;;;;39947:22;39933:8;39942:1;39933:11;;;;;;;;:::i;:::-;;;;;;;:36;;;;;;;;;;;39982:32;40029:18;;;;;;;;;;;40017:58;;;40076:23;40101:8;40017:93;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;40111:1;40017:96;;;;;;;;:::i;:::-;;;;;;;;39982:131;;40126:18;18581:42;40147:37;;:28;:37;;;40126:58;;40252:13;40248:1007;;;40294:18;;;;;;;;;;;40282:54;;;40362:24;40420:23;40478:8;40521:4;40551:15;40282:311;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;40248:1007;;;40736:16;40761:28;40736:54;;40805:10;:18;;;40824;;;;;;;;;;;40844:24;40805:64;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40952:18;;;;;;;;;;;40940:56;;;41015:24;41070:23;41128:8;41171:4;41201:15;40940:303;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;40611:644;40248:1007;41360:20;41389:22;41360:52;;41488:23;41445:14;:24;;;41478:4;41445:39;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:66;;41423:211;;;;;;;;;;;;:::i;:::-;;;;;;;;;39533:2109;;;;;;39355:2287;;;:::o;42059:1888::-;42192:7;42212:25;42254:19;42212:62;;42285:36;42324:11;:22;;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;42285:63;;42361:18;18581:42;42382:37;;:28;:37;;;42361:58;;42434:13;42430:1510;;;42560:20;42583:21;42560:44;;42622:12;42640:10;:15;;42663:12;42640:40;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;42621:59;;;42721:7;42695:128;;;;;;;;;;;;:::i;:::-;;;;;;;;;42847:12;42840:19;;;;;;;;;42430:1510;42934:16;42959:28;42934:54;;43003:28;43034:10;:20;;;43063:4;43034:35;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;43003:66;;43135:1;43112:20;:24;43086:183;;;;;;;;;;;;:::i;:::-;;;;;;;;;43286:10;:18;;;43305;;;;;;;;;;;43325:20;43286:60;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;43363:25;43405:1;43391:16;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;43363:44;;43436:28;43422:8;43431:1;43422:11;;;;;;;;:::i;:::-;;;;;;;:42;;;;;;;;;;;18581;43479:8;43488:1;43479:11;;;;;;;;:::i;:::-;;;;;;;:19;;;;;;;;;;;43515:24;43554:18;;;;;;;;;;;43542:72;;;43637:20;43692:1;43732:8;43771:10;43810:15;43542:314;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;43515:341;;43918:7;43926:1;43918:10;;;;;;;;:::i;:::-;;;;;;;;43911:17;;;;;;;;;42059:1888;;;;;:::o;44225:628::-;44367:20;44396:22;44367:52;;44551:23;44508:14;:24;;;44541:4;44508:39;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:66;;44486:211;;;;;;;;;;;;:::i;:::-;;;;;;;;;44786:14;:22;;;44809:10;44821:23;44786:59;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;44356:497;44225:628;;:::o;21696:1655::-;21867:7;22042:21;22077:17;;;;;;;;;;22042:53;;22106:23;22132:10;:17;;;:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;22106:45;;22164:19;22186:10;:30;;;:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;22164:54;;22229:28;22260:10;:53;;;:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;22229:86;;22328:33;22364:11;:30;;;22416:19;22364:83;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;22328:119;;22458:33;22494:11;:30;;;22546:19;22494:83;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;22458:119;;22590:22;22747:6;22711:11;22632:19;22616:70;;;22687:20;22616:92;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:106;;;;:::i;:::-;22615:139;;;;:::i;:::-;22590:164;;22765:22;22916:20;22905:6;22791:103;22829:19;22863:20;22791:23;:103::i;:::-;:121;;;;:::i;:::-;22790:146;;;;:::i;:::-;22765:171;;22949:27;23009:25;22979:14;:55;;;;:::i;:::-;22949:85;;23045:27;23105:25;23075:14;:55;;;;:::i;:::-;23045:85;;23143:22;23191:19;23169;:41;23168:113;;23262:19;23168:113;;;23227:19;23168:113;23143:138;;23318:25;23301:14;:42;;;;:::i;:::-;23294:49;;;;;;;;;;;;;21696:1655;;;;;:::o;24727:1407::-;24975:28;25020:19;25006:59;;;:61;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;24975:92;;25078:21;18741:42;25102:28;;:20;:28;;;25078:52;;25198:23;25224:123;25258:20;25293:12;25320:16;25224:19;:123::i;:::-;25198:149;;25477:46;25526:63;25562:16;25526:21;:63::i;:::-;25477:112;;25602:17;25647:10;25685:20;25743:19;25799;25855:17;:28;;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;25927:15;25976:12;25622:392;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;25602:412;;26058:17;:27;;;26086:4;26092:10;26104:15;26121:4;26058:68;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;24910:1224;;;;;24727:1407;;;;:::o;23650:471::-;23775:7;23898:22;23939:14;23898:56;;23965:23;23991:44;;;;;;;;24006:6;:25;;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;23991:44;;;23965:70;;24053:60;24072:12;24086:6;:16;;;24103:8;24086:26;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;24053:18;:60::i;:::-;24046:67;;;;23650:471;;;;:::o;26615:619::-;26778:7;26798:21;26836:1;26822:16;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26798:40;;26980:17;26976:111;;;18661:42;27014:4;27019:1;27014:7;;;;;;;;:::i;:::-;;;;;;;:14;;;;;;;;;;;26976:111;;;18741:42;27061:4;27066:1;27061:7;;;;;;;;:::i;:::-;;;;;;;:14;;;;;;;;;;;26976:111;27107:21;27097:4;27102:1;27097:7;;;;;;;;:::i;:::-;;;;;;;:31;;;;;;;;;;;27171:18;;;;;;;;;;;27159:44;;;27204:12;27218:4;27159:64;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;27224:1;27159:67;;;;;;;;:::i;:::-;;;;;;;;27139:87;;;26615:619;;;;;:::o;27555:339::-;27660:28;27710:17;27706:181;;;27780:12;;;;;;;;;;;27744:49;;;;27706:181;27862:12;;;;;;;;;;;27826:49;;27555:339;;;;:::o;7921:212::-;8029:7;8054:18;8075:15;8080:1;8083:6;8075:4;:15::i;:::-;8054:36;;8108:17;8117:7;8108:8;:17::i;:::-;8101:24;;;7921:212;;;;:::o;8141:136::-;8203:10;;:::i;:::-;8233:36;;;;;;;;8248:19;8253:1;:10;;;8265:1;8248:4;:19::i;:::-;8233:36;;;8226:43;;8141:136;;;;:::o;8878:216::-;8935:7;7610:4;9063:3;:12;;;:23;;;;:::i;:::-;9056:30;;8878:216;;;:::o;8285:131::-;8344:7;8371:37;8376:1;8379;8371:37;;;;;;;;;;;;;;;;;:4;:37::i;:::-;8364:44;;8285:131;;;;:::o;8424:296::-;8545:7;8574:1;8569;:6;:16;;;;8584:1;8579;:6;8569:16;8565:57;;;8609:1;8602:8;;;;8565:57;8632:9;8648:1;8644;:5;;;;:::i;:::-;8632:17;;8677:1;8672;8668;:5;;;;:::i;:::-;:10;8680:12;8660:33;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;8711:1;8704:8;;;8424:296;;;;;;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;:::o;7:126:1:-;44:7;84:42;77:5;73:54;62:65;;7:126;;;:::o;139:96::-;176:7;205:24;223:5;205:24;:::i;:::-;194:35;;139:96;;;:::o;241:118::-;328:24;346:5;328:24;:::i;:::-;323:3;316:37;241:118;;:::o;365:222::-;458:4;496:2;485:9;481:18;473:26;;509:71;577:1;566:9;562:17;553:6;509:71;:::i;:::-;365:222;;;;:::o;593:75::-;626:6;659:2;653:9;643:19;;593:75;:::o;674:117::-;783:1;780;773:12;797:117;906:1;903;896:12;920:122;993:24;1011:5;993:24;:::i;:::-;986:5;983:35;973:63;;1032:1;1029;1022:12;973:63;920:122;:::o;1048:139::-;1094:5;1132:6;1119:20;1110:29;;1148:33;1175:5;1148:33;:::i;:::-;1048:139;;;;:::o;1193:77::-;1230:7;1259:5;1248:16;;1193:77;;;:::o;1276:122::-;1349:24;1367:5;1349:24;:::i;:::-;1342:5;1339:35;1329:63;;1388:1;1385;1378:12;1329:63;1276:122;:::o;1404:139::-;1450:5;1488:6;1475:20;1466:29;;1504:33;1531:5;1504:33;:::i;:::-;1404:139;;;;:::o;1549:117::-;1658:1;1655;1648:12;1672:117;1781:1;1778;1771:12;1795:117;1904:1;1901;1894:12;1931:552;1988:8;1998:6;2048:3;2041:4;2033:6;2029:17;2025:27;2015:122;;2056:79;;:::i;:::-;2015:122;2169:6;2156:20;2146:30;;2199:18;2191:6;2188:30;2185:117;;;2221:79;;:::i;:::-;2185:117;2335:4;2327:6;2323:17;2311:29;;2389:3;2381:4;2373:6;2369:17;2359:8;2355:32;2352:41;2349:128;;;2396:79;;:::i;:::-;2349:128;1931:552;;;;;:::o;2489:1109::-;2595:6;2603;2611;2619;2627;2635;2684:3;2672:9;2663:7;2659:23;2655:33;2652:120;;;2691:79;;:::i;:::-;2652:120;2811:1;2836:53;2881:7;2872:6;2861:9;2857:22;2836:53;:::i;:::-;2826:63;;2782:117;2938:2;2964:53;3009:7;3000:6;2989:9;2985:22;2964:53;:::i;:::-;2954:63;;2909:118;3066:2;3092:53;3137:7;3128:6;3117:9;3113:22;3092:53;:::i;:::-;3082:63;;3037:118;3194:2;3220:53;3265:7;3256:6;3245:9;3241:22;3220:53;:::i;:::-;3210:63;;3165:118;3350:3;3339:9;3335:19;3322:33;3382:18;3374:6;3371:30;3368:117;;;3404:79;;:::i;:::-;3368:117;3517:64;3573:7;3564:6;3553:9;3549:22;3517:64;:::i;:::-;3499:82;;;;3293:298;2489:1109;;;;;;;;:::o;3604:77::-;3641:7;3670:5;3659:16;;3604:77;;;:::o;3687:118::-;3774:24;3792:5;3774:24;:::i;:::-;3769:3;3762:37;3687:118;;:::o;3811:222::-;3904:4;3942:2;3931:9;3927:18;3919:26;;3955:71;4023:1;4012:9;4008:17;3999:6;3955:71;:::i;:::-;3811:222;;;;:::o;4039:619::-;4116:6;4124;4132;4181:2;4169:9;4160:7;4156:23;4152:32;4149:119;;;4187:79;;:::i;:::-;4149:119;4307:1;4332:53;4377:7;4368:6;4357:9;4353:22;4332:53;:::i;:::-;4322:63;;4278:117;4434:2;4460:53;4505:7;4496:6;4485:9;4481:22;4460:53;:::i;:::-;4450:63;;4405:118;4562:2;4588:53;4633:7;4624:6;4613:9;4609:22;4588:53;:::i;:::-;4578:63;;4533:118;4039:619;;;;;:::o;4664:90::-;4698:7;4741:5;4734:13;4727:21;4716:32;;4664:90;;;:::o;4760:116::-;4830:21;4845:5;4830:21;:::i;:::-;4823:5;4820:32;4810:60;;4866:1;4863;4856:12;4810:60;4760:116;:::o;4882:137::-;4936:5;4967:6;4961:13;4952:22;;4983:30;5007:5;4983:30;:::i;:::-;4882:137;;;;:::o;5025:345::-;5092:6;5141:2;5129:9;5120:7;5116:23;5112:32;5109:119;;;5147:79;;:::i;:::-;5109:119;5267:1;5292:61;5345:7;5336:6;5325:9;5321:22;5292:61;:::i;:::-;5282:71;;5238:125;5025:345;;;;:::o;5376:169::-;5460:11;5494:6;5489:3;5482:19;5534:4;5529:3;5525:14;5510:29;;5376:169;;;;:::o;5551:246::-;5691:34;5687:1;5679:6;5675:14;5668:58;5760:29;5755:2;5747:6;5743:15;5736:54;5551:246;:::o;5803:366::-;5945:3;5966:67;6030:2;6025:3;5966:67;:::i;:::-;5959:74;;6042:93;6131:3;6042:93;:::i;:::-;6160:2;6155:3;6151:12;6144:19;;5803:366;;;:::o;6175:419::-;6341:4;6379:2;6368:9;6364:18;6356:26;;6428:9;6422:4;6418:20;6414:1;6403:9;6399:17;6392:47;6456:131;6582:4;6456:131;:::i;:::-;6448:139;;6175:419;;;:::o;6600:143::-;6657:5;6688:6;6682:13;6673:22;;6704:33;6731:5;6704:33;:::i;:::-;6600:143;;;;:::o;6749:351::-;6819:6;6868:2;6856:9;6847:7;6843:23;6839:32;6836:119;;;6874:79;;:::i;:::-;6836:119;6994:1;7019:64;7075:7;7066:6;7055:9;7051:22;7019:64;:::i;:::-;7009:74;;6965:128;6749:351;;;;:::o;7106:244::-;7246:34;7242:1;7234:6;7230:14;7223:58;7315:27;7310:2;7302:6;7298:15;7291:52;7106:244;:::o;7356:366::-;7498:3;7519:67;7583:2;7578:3;7519:67;:::i;:::-;7512:74;;7595:93;7684:3;7595:93;:::i;:::-;7713:2;7708:3;7704:12;7697:19;;7356:366;;;:::o;7728:419::-;7894:4;7932:2;7921:9;7917:18;7909:26;;7981:9;7975:4;7971:20;7967:1;7956:9;7952:17;7945:47;8009:131;8135:4;8009:131;:::i;:::-;8001:139;;7728:419;;;:::o;8153:118::-;8240:24;8258:5;8240:24;:::i;:::-;8235:3;8228:37;8153:118;;:::o;8277:553::-;8454:4;8492:3;8481:9;8477:19;8469:27;;8506:71;8574:1;8563:9;8559:17;8550:6;8506:71;:::i;:::-;8587:72;8655:2;8644:9;8640:18;8631:6;8587:72;:::i;:::-;8669;8737:2;8726:9;8722:18;8713:6;8669:72;:::i;:::-;8751;8819:2;8808:9;8804:18;8795:6;8751:72;:::i;:::-;8277:553;;;;;;;:::o;8836:143::-;8893:5;8924:6;8918:13;8909:22;;8940:33;8967:5;8940:33;:::i;:::-;8836:143;;;;:::o;8985:663::-;9073:6;9081;9089;9138:2;9126:9;9117:7;9113:23;9109:32;9106:119;;;9144:79;;:::i;:::-;9106:119;9264:1;9289:64;9345:7;9336:6;9325:9;9321:22;9289:64;:::i;:::-;9279:74;;9235:128;9402:2;9428:64;9484:7;9475:6;9464:9;9460:22;9428:64;:::i;:::-;9418:74;;9373:129;9541:2;9567:64;9623:7;9614:6;9603:9;9599:22;9567:64;:::i;:::-;9557:74;;9512:129;8985:663;;;;;:::o;9654:250::-;9794:34;9790:1;9782:6;9778:14;9771:58;9863:33;9858:2;9850:6;9846:15;9839:58;9654:250;:::o;9910:366::-;10052:3;10073:67;10137:2;10132:3;10073:67;:::i;:::-;10066:74;;10149:93;10238:3;10149:93;:::i;:::-;10267:2;10262:3;10258:12;10251:19;;9910:366;;;:::o;10282:419::-;10448:4;10486:2;10475:9;10471:18;10463:26;;10535:9;10529:4;10525:20;10521:1;10510:9;10506:17;10499:47;10563:131;10689:4;10563:131;:::i;:::-;10555:139;;10282:419;;;:::o;10707:246::-;10847:34;10843:1;10835:6;10831:14;10824:58;10916:29;10911:2;10903:6;10899:15;10892:54;10707:246;:::o;10959:366::-;11101:3;11122:67;11186:2;11181:3;11122:67;:::i;:::-;11115:74;;11198:93;11287:3;11198:93;:::i;:::-;11316:2;11311:3;11307:12;11300:19;;10959:366;;;:::o;11331:419::-;11497:4;11535:2;11524:9;11520:18;11512:26;;11584:9;11578:4;11574:20;11570:1;11559:9;11555:17;11548:47;11612:131;11738:4;11612:131;:::i;:::-;11604:139;;11331:419;;;:::o;11756:104::-;11801:7;11830:24;11848:5;11830:24;:::i;:::-;11819:35;;11756:104;;;:::o;11866:138::-;11947:32;11973:5;11947:32;:::i;:::-;11940:5;11937:43;11927:71;;11994:1;11991;11984:12;11927:71;11866:138;:::o;12010:155::-;12064:5;12102:6;12089:20;12080:29;;12118:41;12153:5;12118:41;:::i;:::-;12010:155;;;;:::o;12171:1283::-;12324:6;12332;12340;12348;12356;12364;12372;12421:3;12409:9;12400:7;12396:23;12392:33;12389:120;;;12428:79;;:::i;:::-;12389:120;12548:1;12573:61;12626:7;12617:6;12606:9;12602:22;12573:61;:::i;:::-;12563:71;;12519:125;12683:2;12709:61;12762:7;12753:6;12742:9;12738:22;12709:61;:::i;:::-;12699:71;;12654:126;12819:2;12845:61;12898:7;12889:6;12878:9;12874:22;12845:61;:::i;:::-;12835:71;;12790:126;12955:2;12981:61;13034:7;13025:6;13014:9;13010:22;12981:61;:::i;:::-;12971:71;;12926:126;13091:3;13118:61;13171:7;13162:6;13151:9;13147:22;13118:61;:::i;:::-;13108:71;;13062:127;13228:3;13255:53;13300:7;13291:6;13280:9;13276:22;13255:53;:::i;:::-;13245:63;;13199:119;13357:3;13384:53;13429:7;13420:6;13409:9;13405:22;13384:53;:::i;:::-;13374:63;;13328:119;12171:1283;;;;;;;;;;:::o;13460:226::-;13600:34;13596:1;13588:6;13584:14;13577:58;13669:9;13664:2;13656:6;13652:15;13645:34;13460:226;:::o;13692:366::-;13834:3;13855:67;13919:2;13914:3;13855:67;:::i;:::-;13848:74;;13931:93;14020:3;13931:93;:::i;:::-;14049:2;14044:3;14040:12;14033:19;;13692:366;;;:::o;14064:419::-;14230:4;14268:2;14257:9;14253:18;14245:26;;14317:9;14311:4;14307:20;14303:1;14292:9;14288:17;14281:47;14345:131;14471:4;14345:131;:::i;:::-;14337:139;;14064:419;;;:::o;14489:292::-;14629:34;14625:1;14617:6;14613:14;14606:58;14698:34;14693:2;14685:6;14681:15;14674:59;14767:6;14762:2;14754:6;14750:15;14743:31;14489:292;:::o;14787:366::-;14929:3;14950:67;15014:2;15009:3;14950:67;:::i;:::-;14943:74;;15026:93;15115:3;15026:93;:::i;:::-;15144:2;15139:3;15135:12;15128:19;;14787:366;;;:::o;15159:419::-;15325:4;15363:2;15352:9;15348:18;15340:26;;15412:9;15406:4;15402:20;15398:1;15387:9;15383:17;15376:47;15440:131;15566:4;15440:131;:::i;:::-;15432:139;;15159:419;;;:::o;15584:247::-;15724:34;15720:1;15712:6;15708:14;15701:58;15793:30;15788:2;15780:6;15776:15;15769:55;15584:247;:::o;15837:366::-;15979:3;16000:67;16064:2;16059:3;16000:67;:::i;:::-;15993:74;;16076:93;16165:3;16076:93;:::i;:::-;16194:2;16189:3;16185:12;16178:19;;15837:366;;;:::o;16209:419::-;16375:4;16413:2;16402:9;16398:18;16390:26;;16462:9;16456:4;16452:20;16448:1;16437:9;16433:17;16426:47;16490:131;16616:4;16490:131;:::i;:::-;16482:139;;16209:419;;;:::o;16634:180::-;16682:77;16679:1;16672:88;16779:4;16776:1;16769:15;16803:4;16800:1;16793:15;16820:305;16860:3;16879:20;16897:1;16879:20;:::i;:::-;16874:25;;16913:20;16931:1;16913:20;:::i;:::-;16908:25;;17067:1;16999:66;16995:74;16992:1;16989:81;16986:107;;;17073:18;;:::i;:::-;16986:107;17117:1;17114;17110:9;17103:16;;16820:305;;;;:::o;17131:332::-;17252:4;17290:2;17279:9;17275:18;17267:26;;17303:71;17371:1;17360:9;17356:17;17347:6;17303:71;:::i;:::-;17384:72;17452:2;17441:9;17437:18;17428:6;17384:72;:::i;:::-;17131:332;;;;;:::o;17469:180::-;17517:77;17514:1;17507:88;17614:4;17611:1;17604:15;17638:4;17635:1;17628:15;17655:180;17703:77;17700:1;17693:88;17800:4;17797:1;17790:15;17824:4;17821:1;17814:15;17841:114;17908:6;17942:5;17936:12;17926:22;;17841:114;;;:::o;17961:184::-;18060:11;18094:6;18089:3;18082:19;18134:4;18129:3;18125:14;18110:29;;17961:184;;;;:::o;18151:132::-;18218:4;18241:3;18233:11;;18271:4;18266:3;18262:14;18254:22;;18151:132;;;:::o;18289:108::-;18366:24;18384:5;18366:24;:::i;:::-;18361:3;18354:37;18289:108;;:::o;18403:179::-;18472:10;18493:46;18535:3;18527:6;18493:46;:::i;:::-;18571:4;18566:3;18562:14;18548:28;;18403:179;;;;:::o;18588:113::-;18658:4;18690;18685:3;18681:14;18673:22;;18588:113;;;:::o;18737:732::-;18856:3;18885:54;18933:5;18885:54;:::i;:::-;18955:86;19034:6;19029:3;18955:86;:::i;:::-;18948:93;;19065:56;19115:5;19065:56;:::i;:::-;19144:7;19175:1;19160:284;19185:6;19182:1;19179:13;19160:284;;;19261:6;19255:13;19288:63;19347:3;19332:13;19288:63;:::i;:::-;19281:70;;19374:60;19427:6;19374:60;:::i;:::-;19364:70;;19220:224;19207:1;19204;19200:9;19195:14;;19160:284;;;19164:14;19460:3;19453:10;;18861:608;;;18737:732;;;;:::o;19475:815::-;19730:4;19768:3;19757:9;19753:19;19745:27;;19782:71;19850:1;19839:9;19835:17;19826:6;19782:71;:::i;:::-;19863:72;19931:2;19920:9;19916:18;19907:6;19863:72;:::i;:::-;19982:9;19976:4;19972:20;19967:2;19956:9;19952:18;19945:48;20010:108;20113:4;20104:6;20010:108;:::i;:::-;20002:116;;20128:72;20196:2;20185:9;20181:18;20172:6;20128:72;:::i;:::-;20210:73;20278:3;20267:9;20263:19;20254:6;20210:73;:::i;:::-;19475:815;;;;;;;;:::o;20296:102::-;20337:6;20388:2;20384:7;20379:2;20372:5;20368:14;20364:28;20354:38;;20296:102;;;:::o;20404:281::-;20487:27;20509:4;20487:27;:::i;:::-;20479:6;20475:40;20617:6;20605:10;20602:22;20581:18;20569:10;20566:34;20563:62;20560:88;;;20628:18;;:::i;:::-;20560:88;20668:10;20664:2;20657:22;20447:238;20404:281;;:::o;20691:129::-;20725:6;20752:20;;:::i;:::-;20742:30;;20781:33;20809:4;20801:6;20781:33;:::i;:::-;20691:129;;;:::o;20826:311::-;20903:4;20993:18;20985:6;20982:30;20979:56;;;21015:18;;:::i;:::-;20979:56;21065:4;21057:6;21053:17;21045:25;;21125:4;21119;21115:15;21107:23;;20826:311;;;:::o;21160:732::-;21267:5;21292:81;21308:64;21365:6;21308:64;:::i;:::-;21292:81;:::i;:::-;21283:90;;21393:5;21422:6;21415:5;21408:21;21456:4;21449:5;21445:16;21438:23;;21509:4;21501:6;21497:17;21489:6;21485:30;21538:3;21530:6;21527:15;21524:122;;;21557:79;;:::i;:::-;21524:122;21672:6;21655:231;21689:6;21684:3;21681:15;21655:231;;;21764:3;21793:48;21837:3;21825:10;21793:48;:::i;:::-;21788:3;21781:61;21871:4;21866:3;21862:14;21855:21;;21731:155;21715:4;21710:3;21706:14;21699:21;;21655:231;;;21659:21;21273:619;;21160:732;;;;;:::o;21915:385::-;21997:5;22046:3;22039:4;22031:6;22027:17;22023:27;22013:122;;22054:79;;:::i;:::-;22013:122;22164:6;22158:13;22189:105;22290:3;22282:6;22275:4;22267:6;22263:17;22189:105;:::i;:::-;22180:114;;22003:297;21915:385;;;;:::o;22306:554::-;22401:6;22450:2;22438:9;22429:7;22425:23;22421:32;22418:119;;;22456:79;;:::i;:::-;22418:119;22597:1;22586:9;22582:17;22576:24;22627:18;22619:6;22616:30;22613:117;;;22649:79;;:::i;:::-;22613:117;22754:89;22835:7;22826:6;22815:9;22811:22;22754:89;:::i;:::-;22744:99;;22547:306;22306:554;;;;:::o;22866:351::-;22936:6;22985:2;22973:9;22964:7;22960:23;22956:32;22953:119;;;22991:79;;:::i;:::-;22953:119;23111:1;23136:64;23192:7;23183:6;23172:9;23168:22;23136:64;:::i;:::-;23126:74;;23082:128;22866:351;;;;:::o;23223:315::-;23363:34;23359:1;23351:6;23347:14;23340:58;23432:34;23427:2;23419:6;23415:15;23408:59;23501:29;23496:2;23488:6;23484:15;23477:54;23223:315;:::o;23544:366::-;23686:3;23707:67;23771:2;23766:3;23707:67;:::i;:::-;23700:74;;23783:93;23872:3;23783:93;:::i;:::-;23901:2;23896:3;23892:12;23885:19;;23544:366;;;:::o;23916:419::-;24082:4;24120:2;24109:9;24105:18;24097:26;;24169:9;24163:4;24159:20;24155:1;24144:9;24140:17;24133:47;24197:131;24323:4;24197:131;:::i;:::-;24189:139;;23916:419;;;:::o;24341:60::-;24369:3;24390:5;24383:12;;24341:60;;;:::o;24407:142::-;24457:9;24490:53;24508:34;24517:24;24535:5;24517:24;:::i;:::-;24508:34;:::i;:::-;24490:53;:::i;:::-;24477:66;;24407:142;;;:::o;24555:126::-;24605:9;24638:37;24669:5;24638:37;:::i;:::-;24625:50;;24555:126;;;:::o;24687:149::-;24760:9;24793:37;24824:5;24793:37;:::i;:::-;24780:50;;24687:149;;;:::o;24842:177::-;24952:60;25006:5;24952:60;:::i;:::-;24947:3;24940:73;24842:177;;:::o;25025:378::-;25169:4;25207:2;25196:9;25192:18;25184:26;;25220:71;25288:1;25277:9;25273:17;25264:6;25220:71;:::i;:::-;25301:95;25392:2;25381:9;25377:18;25368:6;25301:95;:::i;:::-;25025:378;;;;;:::o;25409:488::-;25581:4;25619:2;25608:9;25604:18;25596:26;;25632:71;25700:1;25689:9;25685:17;25676:6;25632:71;:::i;:::-;25713:72;25781:2;25770:9;25766:18;25757:6;25713:72;:::i;:::-;25795:95;25886:2;25875:9;25871:18;25862:6;25795:95;:::i;:::-;25409:488;;;;;;:::o;25903:242::-;26043:34;26039:1;26031:6;26027:14;26020:58;26112:25;26107:2;26099:6;26095:15;26088:50;25903:242;:::o;26151:366::-;26293:3;26314:67;26378:2;26373:3;26314:67;:::i;:::-;26307:74;;26390:93;26479:3;26390:93;:::i;:::-;26508:2;26503:3;26499:12;26492:19;;26151:366;;;:::o;26523:419::-;26689:4;26727:2;26716:9;26712:18;26704:26;;26776:9;26770:4;26766:20;26762:1;26751:9;26747:17;26740:47;26804:131;26930:4;26804:131;:::i;:::-;26796:139;;26523:419;;;:::o;26948:222::-;27041:4;27079:2;27068:9;27064:18;27056:26;;27092:71;27160:1;27149:9;27145:17;27136:6;27092:71;:::i;:::-;26948:222;;;;:::o;27176:294::-;27316:34;27312:1;27304:6;27300:14;27293:58;27385:34;27380:2;27372:6;27368:15;27361:59;27454:8;27449:2;27441:6;27437:15;27430:33;27176:294;:::o;27476:366::-;27618:3;27639:67;27703:2;27698:3;27639:67;:::i;:::-;27632:74;;27715:93;27804:3;27715:93;:::i;:::-;27833:2;27828:3;27824:12;27817:19;;27476:366;;;:::o;27848:419::-;28014:4;28052:2;28041:9;28037:18;28029:26;;28101:9;28095:4;28091:20;28087:1;28076:9;28072:17;28065:47;28129:131;28255:4;28129:131;:::i;:::-;28121:139;;27848:419;;;:::o;28273:483::-;28444:4;28482:2;28471:9;28467:18;28459:26;;28495:71;28563:1;28552:9;28548:17;28539:6;28495:71;:::i;:::-;28613:9;28607:4;28603:20;28598:2;28587:9;28583:18;28576:48;28641:108;28744:4;28735:6;28641:108;:::i;:::-;28633:116;;28273:483;;;;;:::o;28762:704::-;28989:4;29027:3;29016:9;29012:19;29004:27;;29041:71;29109:1;29098:9;29094:17;29085:6;29041:71;:::i;:::-;29159:9;29153:4;29149:20;29144:2;29133:9;29129:18;29122:48;29187:108;29290:4;29281:6;29187:108;:::i;:::-;29179:116;;29305:72;29373:2;29362:9;29358:18;29349:6;29305:72;:::i;:::-;29387;29455:2;29444:9;29440:18;29431:6;29387:72;:::i;:::-;28762:704;;;;;;;:::o;29472:319::-;29612:34;29608:1;29600:6;29596:14;29589:58;29681:34;29676:2;29668:6;29664:15;29657:59;29750:33;29745:2;29737:6;29733:15;29726:58;29472:319;:::o;29797:366::-;29939:3;29960:67;30024:2;30019:3;29960:67;:::i;:::-;29953:74;;30036:93;30125:3;30036:93;:::i;:::-;30154:2;30149:3;30145:12;30138:19;;29797:366;;;:::o;30169:419::-;30335:4;30373:2;30362:9;30358:18;30350:26;;30422:9;30416:4;30412:20;30408:1;30397:9;30393:17;30386:47;30450:131;30576:4;30450:131;:::i;:::-;30442:139;;30169:419;;;:::o;30594:147::-;30695:11;30732:3;30717:18;;30594:147;;;;:::o;30747:114::-;;:::o;30867:398::-;31026:3;31047:83;31128:1;31123:3;31047:83;:::i;:::-;31040:90;;31139:93;31228:3;31139:93;:::i;:::-;31257:1;31252:3;31248:11;31241:18;;30867:398;;;:::o;31271:379::-;31455:3;31477:147;31620:3;31477:147;:::i;:::-;31470:154;;31641:3;31634:10;;31271:379;;;:::o;31656:246::-;31796:34;31792:1;31784:6;31780:14;31773:58;31865:29;31860:2;31852:6;31848:15;31841:54;31656:246;:::o;31908:366::-;32050:3;32071:67;32135:2;32130:3;32071:67;:::i;:::-;32064:74;;32147:93;32236:3;32147:93;:::i;:::-;32265:2;32260:3;32256:12;32249:19;;31908:366;;;:::o;32280:419::-;32446:4;32484:2;32473:9;32469:18;32461:26;;32533:9;32527:4;32523:20;32519:1;32508:9;32504:17;32497:47;32561:131;32687:4;32561:131;:::i;:::-;32553:139;;32280:419;;;:::o;32705:358::-;32845:34;32841:1;32833:6;32829:14;32822:58;32914:34;32909:2;32901:6;32897:15;32890:59;32983:34;32978:2;32970:6;32966:15;32959:59;33052:3;33047:2;33039:6;33035:15;33028:28;32705:358;:::o;33069:367::-;33211:3;33232:67;33296:2;33291:3;33232:67;:::i;:::-;33225:74;;33308:93;33397:3;33308:93;:::i;:::-;33426:3;33421;33417:13;33410:20;;33069:367;;;:::o;33442:419::-;33608:4;33646:2;33635:9;33631:18;33623:26;;33695:9;33689:4;33685:20;33681:1;33670:9;33666:17;33659:47;33723:131;33849:4;33723:131;:::i;:::-;33715:139;;33442:419;;;:::o;33867:85::-;33912:7;33941:5;33930:16;;33867:85;;;:::o;33958:158::-;34016:9;34049:61;34067:42;34076:32;34102:5;34076:32;:::i;:::-;34067:42;:::i;:::-;34049:61;:::i;:::-;34036:74;;33958:158;;;:::o;34122:147::-;34217:45;34256:5;34217:45;:::i;:::-;34212:3;34205:58;34122:147;;:::o;34275:831::-;34538:4;34576:3;34565:9;34561:19;34553:27;;34590:71;34658:1;34647:9;34643:17;34634:6;34590:71;:::i;:::-;34671:80;34747:2;34736:9;34732:18;34723:6;34671:80;:::i;:::-;34798:9;34792:4;34788:20;34783:2;34772:9;34768:18;34761:48;34826:108;34929:4;34920:6;34826:108;:::i;:::-;34818:116;;34944:72;35012:2;35001:9;34997:18;34988:6;34944:72;:::i;:::-;35026:73;35094:3;35083:9;35079:19;35070:6;35026:73;:::i;:::-;34275:831;;;;;;;;:::o;35112:115::-;35168:7;35197:24;35215:5;35197:24;:::i;:::-;35186:35;;35112:115;;;:::o;35233:160::-;35325:43;35362:5;35325:43;:::i;:::-;35318:5;35315:54;35305:82;;35383:1;35380;35373:12;35305:82;35233:160;:::o;35399:181::-;35475:5;35506:6;35500:13;35491:22;;35522:52;35568:5;35522:52;:::i;:::-;35399:181;;;;:::o;35586:389::-;35675:6;35724:2;35712:9;35703:7;35699:23;35695:32;35692:119;;;35730:79;;:::i;:::-;35692:119;35850:1;35875:83;35950:7;35941:6;35930:9;35926:22;35875:83;:::i;:::-;35865:93;;35821:147;35586:389;;;;:::o;35981:140::-;36045:9;36078:37;36109:5;36078:37;:::i;:::-;36065:50;;35981:140;;;:::o;36127:159::-;36228:51;36273:5;36228:51;:::i;:::-;36223:3;36216:64;36127:159;;:::o;36292:250::-;36399:4;36437:2;36426:9;36422:18;36414:26;;36450:85;36532:1;36521:9;36517:17;36508:6;36450:85;:::i;:::-;36292:250;;;;:::o;36548:348::-;36588:7;36611:20;36629:1;36611:20;:::i;:::-;36606:25;;36645:20;36663:1;36645:20;:::i;:::-;36640:25;;36833:1;36765:66;36761:74;36758:1;36755:81;36750:1;36743:9;36736:17;36732:105;36729:131;;;36840:18;;:::i;:::-;36729:131;36888:1;36885;36881:9;36870:20;;36548:348;;;;:::o;36902:180::-;36950:77;36947:1;36940:88;37047:4;37044:1;37037:15;37071:4;37068:1;37061:15;37088:185;37128:1;37145:20;37163:1;37145:20;:::i;:::-;37140:25;;37179:20;37197:1;37179:20;:::i;:::-;37174:25;;37218:1;37208:35;;37223:18;;:::i;:::-;37208:35;37265:1;37262;37258:9;37253:14;;37088:185;;;;:::o;37279:886::-;37540:4;37578:3;37567:9;37563:19;37555:27;;37592:71;37660:1;37649:9;37645:17;37636:6;37592:71;:::i;:::-;37673:72;37741:2;37730:9;37726:18;37717:6;37673:72;:::i;:::-;37755;37823:2;37812:9;37808:18;37799:6;37755:72;:::i;:::-;37837;37905:2;37894:9;37890:18;37881:6;37837:72;:::i;:::-;37919:73;37987:3;37976:9;37972:19;37963:6;37919:73;:::i;:::-;38002;38070:3;38059:9;38055:19;38046:6;38002:73;:::i;:::-;38085;38153:3;38142:9;38138:19;38129:6;38085:73;:::i;:::-;37279:886;;;;;;;;;;:::o;38171:148::-;38243:9;38276:37;38307:5;38276:37;:::i;:::-;38263:50;;38171:148;;;:::o;38325:175::-;38434:59;38487:5;38434:59;:::i;:::-;38429:3;38422:72;38325:175;;:::o;38506:98::-;38557:6;38591:5;38585:12;38575:22;;38506:98;;;:::o;38610:168::-;38693:11;38727:6;38722:3;38715:19;38767:4;38762:3;38758:14;38743:29;;38610:168;;;;:::o;38784:307::-;38852:1;38862:113;38876:6;38873:1;38870:13;38862:113;;;38961:1;38956:3;38952:11;38946:18;38942:1;38937:3;38933:11;38926:39;38898:2;38895:1;38891:10;38886:15;;38862:113;;;38993:6;38990:1;38987:13;38984:101;;;39073:1;39064:6;39059:3;39055:16;39048:27;38984:101;38833:258;38784:307;;;:::o;39097:360::-;39183:3;39211:38;39243:5;39211:38;:::i;:::-;39265:70;39328:6;39323:3;39265:70;:::i;:::-;39258:77;;39344:52;39389:6;39384:3;39377:4;39370:5;39366:16;39344:52;:::i;:::-;39421:29;39443:6;39421:29;:::i;:::-;39416:3;39412:39;39405:46;;39187:270;39097:360;;;;:::o;39463:684::-;39680:4;39718:3;39707:9;39703:19;39695:27;;39732:93;39822:1;39811:9;39807:17;39798:6;39732:93;:::i;:::-;39835:72;39903:2;39892:9;39888:18;39879:6;39835:72;:::i;:::-;39917;39985:2;39974:9;39970:18;39961:6;39917:72;:::i;:::-;40036:9;40030:4;40026:20;40021:2;40010:9;40006:18;39999:48;40064:76;40135:4;40126:6;40064:76;:::i;:::-;40056:84;;39463:684;;;;;;;:::o;40153:99::-;40205:6;40239:5;40233:12;40223:22;;40153:99;;;:::o;40258:364::-;40346:3;40374:39;40407:5;40374:39;:::i;:::-;40429:71;40493:6;40488:3;40429:71;:::i;:::-;40422:78;;40509:52;40554:6;40549:3;40542:4;40535:5;40531:16;40509:52;:::i;:::-;40586:29;40608:6;40586:29;:::i;:::-;40581:3;40577:39;40570:46;;40350:272;40258:364;;;;:::o;40628:313::-;40741:4;40779:2;40768:9;40764:18;40756:26;;40828:9;40822:4;40818:20;40814:1;40803:9;40799:17;40792:47;40856:78;40929:4;40920:6;40856:78;:::i;:::-;40848:86;;40628:313;;;;:::o

Swarm Source

ipfs://30f82ddb7939846bbf3111eb31139576c8a2ba5ac7c4a223a48dead1d3326659
Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.