ETH Price: $3,205.33 (+5.68%)

Contract

0x74369645D6b1eC466b9e573bE8c516f5a4945d16
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Withdraw Liquidi...177785682023-07-26 16:52:47537 days ago1690390367IN
0x74369645...5a4945d16
0 ETH0.0045531332.88600796
Approve177785462023-07-26 16:48:23537 days ago1690390103IN
0x74369645...5a4945d16
0 ETH0.0019046541.13455224
Open Swap133463732021-10-03 13:02:201199 days ago1633266140IN
0x74369645...5a4945d16
0 ETH0.0106871231
Approve132801992021-09-23 5:49:571209 days ago1632376197IN
0x74369645...5a4945d16
0 ETH0.0031617268.26563464
Withdraw Liquidi...132735062021-09-22 4:44:451210 days ago1632285885IN
0x74369645...5a4945d16
0 ETH0.009657765.21246928
Approve132734962021-09-22 4:41:521210 days ago1632285712IN
0x74369645...5a4945d16
0 ETH0.0026270556.75097231
Open Swap131889972021-09-09 2:56:281223 days ago1631156188IN
0x74369645...5a4945d16
0 ETH0.0517119150
Liquidate130715482021-08-21 23:16:021241 days ago1629587762IN
0x74369645...5a4945d16
0 ETH0.0047019126.30311989
Deposit Liquidit...130689732021-08-21 13:45:201242 days ago1629553520IN
0x74369645...5a4945d16
0 ETH0.0048457730.27604899
Deposit Liquidit...130562782021-08-19 14:36:251243 days ago1629383785IN
0x74369645...5a4945d16
0 ETH0.0067186641.97775805
Deposit Liquidit...130560142021-08-19 13:36:251244 days ago1629380185IN
0x74369645...5a4945d16
0 ETH0.0047885529.92848803
Deposit Liquidit...130545052021-08-19 8:03:091244 days ago1629360189IN
0x74369645...5a4945d16
0 ETH0.0052833
Deposit Liquidit...130545002021-08-19 8:02:131244 days ago1629360133IN
0x74369645...5a4945d16
0 ETH0.0046694229.18390653
Open Swap130516982021-08-18 21:41:081244 days ago1629322868IN
0x74369645...5a4945d16
0 ETH0.0127913136.81864075
Open Swap130376952021-08-16 17:56:401246 days ago1629136600IN
0x74369645...5a4945d16
0 ETH0.0210201848.55375887
Deposit Liquidit...130376592021-08-16 17:49:061246 days ago1629136146IN
0x74369645...5a4945d16
0 ETH0.0060831951.78640502

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block
From
To
130316822021-08-15 19:33:281247 days ago1629056008  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Pool

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
File 1 of 10 : Pool.sol
// SPDX-License-Identifier: Unlicensed
pragma solidity 0.7.6;

// ============ Contract information ============

/**
 * @title  InterestRateSwapPool
 * @notice A pool for Interest Rate Swaps
 * @author Greenwood Labs
 */

// ============ Imports ============

import '@openzeppelin/contracts/math/SafeMath.sol';
import '@openzeppelin/contracts/math/Math.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/token/ERC20/SafeERC20.sol';
import '../interfaces/IPool.sol';
import '../interfaces/IAdapter.sol';
import './GreenwoodERC20.sol';


contract Pool is IPool, GreenwoodERC20 {
    // ============ Import usage ============

    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    // ============ Immutable storage ============

    address private constant GOVERNANCE = 0xe3D5260Cd7F8a4207f41C3B2aC87882489f97213;

    uint256 private constant TEN_EXP_18 = 1000000000000000000;
    uint256 private constant STANDARD_DECIMALS = 18;
    uint256 private constant BLOCKS_PER_DAY = 6570; // 13.15 seconds per block
    uint256 private constant FEE_NUMERATOR = 3;
    uint256 private constant FEE_DENOMINATOR = 1000;
    uint256 private constant MAX_TO_PAY_BUFFER_NUMERATOR = 10;
    uint256 private constant MAX_TO_PAY_BUFFER_DENOMINATOR = 100;
    uint256 private constant DAYS_PER_YEAR = 360;

    // ============ Mutable storage ============

    address private factory;
    address private adapter;
    address public underlier;

    uint256 public totalSwapCollateral;
    uint256 public totalSupplementaryCollateral;
    uint256 public totalActiveLiquidity;
    uint256 public totalAvailableLiquidity;
    uint256 public totalFees;
    uint256 public fixedRate;
    uint256 public utilization;
    uint256 public protocol;
    uint256 public direction;
    uint256 public durationInDays;
    uint256 public underlierDecimals;
    uint256 public decimalDifference;
    uint256 public rateLimit;
    uint256 public rateSensitivity;
    uint256 public utilizationInflection;
    uint256 public rateMultiplier;
    uint256 public maxDepositLimit;

    mapping(bytes32 => Swap) public swaps;
    mapping(address => uint256) public swapNumbers;
    mapping(address => uint256) public liquidityProviderLastDeposit;

    // ============ Structs ============
  
    struct Swap {
        address user;
        bool isClosed;
        uint256 notional;
        uint256 swapCollateral;
        uint256 activeLiquidity;
        uint256 openBlock;
        uint256 underlierBorrowIndex;
        uint256 fixedRate;
    }

    // ============ Events ============

    event OpenSwap(address indexed user, uint256 notional, uint256 activeLiquidity, uint256 fixedRate);
    event CloseSwap(address indexed user, uint256 notional, uint256 userToPay, uint256 ammToPay, uint256 fixedRate);
    event DepositLiquidity(address indexed user, uint256 liquidityAmount);
    event WithdrawLiquidity(address indexed user, uint256 liquidityAmount, uint256 feesAccrued);
    event Liquidate(address indexed liquidator, address indexed user, uint256 swapNumber, uint256 liquidatorReward);
    event Mint(address indexed user, uint256 underlyingTokenAmount, uint256 liquidityTokenAmount);
    event Burn(address indexed user, uint256 underlyingTokenAmount, uint256 liquidityTokenAmount);
    
    // ============ Constructor ============

    constructor(
        address _underlier,
        uint256 _underlierDecimals,
        address _adapter,
        uint256 _protocol,
        uint256 _direction,
        uint256 _durationInDays,
        uint256 _initialDeposit,
        uint256 _rateLimit,
        uint256 _rateSensitivity,
        uint256 _utilizationInflection,
        uint256 _rateMultiplier,
        address _poolDeployer
    ) {
        // assert that the pool can be initialized with a non-zero amount
        require(_initialDeposit > 0, '14');

        // initialize the pool
        factory = msg.sender;
        underlier = _underlier;
        underlierDecimals = _underlierDecimals;
        protocol = _protocol;
        direction = _direction;
        durationInDays = _durationInDays;

        // calculate difference in decimals between underlier and STANDARD_DECIMALS
        decimalDifference = _calculatedDecimalDifference(underlierDecimals, STANDARD_DECIMALS);

        // adjust the y token decimals to the standard number
        uint256 adjustedInitialDeposit = _convertToStandardDecimal(_initialDeposit);

        totalAvailableLiquidity = adjustedInitialDeposit;
        adapter = _adapter;
        rateLimit = _rateLimit;
        rateSensitivity = _rateSensitivity;
        utilizationInflection = _utilizationInflection;
        rateMultiplier = _rateMultiplier;
        maxDepositLimit = 1000000000000000000000000;

        // calculates the initial fixed rate to be offered
        fixedRate = _calculateFixedRate();

        // update the pool deployer's deposit block number
        liquidityProviderLastDeposit[_poolDeployer] = block.number;

        // mint LP tokens to the pool deployer
        _mintLPTokens(_poolDeployer, adjustedInitialDeposit);
    }


    // ============ Opens a new interest rate swap ============

    function openSwap(uint256 _notional) external override returns (bool) {
        // assert that a swap is opened with an non-zero notional
        require(_notional > 0, '9');

        // adjust notional to standard decimal places
        uint256 adjustedNotional = _convertToStandardDecimal(_notional);

        // calculate the swap collateral and trade active liquidity based off the notional
        (uint256 swapCollateral, uint256 activeLiquidity) = _calculateSwapCollateralAndActiveLiquidity(adjustedNotional);

        // assert that there is sufficient liquidity to open this swap
        require(activeLiquidity <= totalAvailableLiquidity, '10');

        // assign the supplementary collateral
        uint256 supplementaryCollateral = activeLiquidity;

        // the offered fixed rate for this swap
        uint256 offeredFixedRate = fixedRate;

        // calculate the fee based on swap collateral
        uint256 swapFee = swapCollateral.mul(FEE_NUMERATOR).div(FEE_DENOMINATOR);

        // calculate the current borrow index for the underlier
        uint256 underlierBorrowIndex = IAdapter(adapter).getBorrowIndex(underlier);

        // create the swap struct
        Swap memory swap = Swap(
            msg.sender,
            false,
            adjustedNotional,
            swapCollateral,
            activeLiquidity,
            block.number,
            underlierBorrowIndex,
            offeredFixedRate
        );
        
        // create a swap key by hashing together the user and their current swap number
        bytes32 swapKey = keccak256(abi.encode(msg.sender, swapNumbers[msg.sender]));
        swaps[swapKey] = swap;

        // update the user's swap number
        swapNumbers[msg.sender] = swapNumbers[msg.sender].add(1);

        // update the total active liquidity
        totalActiveLiquidity = totalActiveLiquidity.add(activeLiquidity);

        // update the total swap collateral
        totalSwapCollateral = totalSwapCollateral.add(swapCollateral);

        // update the total supplementary collateral
        totalSupplementaryCollateral = totalSupplementaryCollateral.add(supplementaryCollateral);

        // update the total available liquidity
        totalAvailableLiquidity = totalAvailableLiquidity.sub(activeLiquidity);

        // update the total fees accrued
        totalFees = totalFees.add(swapFee);

        // the total amount to debit the user (swap collateral + fee + the supplementary collateral)
        uint256 amountToDebit = swapCollateral.add(swapFee).add(supplementaryCollateral);

        // calculate the new pool utilization
        utilization = _calculateUtilization();

        // calculate the new fixed interest rate
        fixedRate = _calculateFixedRate();

        // transfer underlier from the user
        IERC20(underlier).safeTransferFrom(
            msg.sender,
            address(this),
            _convertToUnderlierDecimal(amountToDebit)
        );

        // emit an open swap event
        emit OpenSwap(msg.sender, adjustedNotional, activeLiquidity, offeredFixedRate);

        // return true on successful open swap
        return true;
    }


    // ============ Closes an interest rate swap ============

    function closeSwap(uint256 _swapNumber) external override returns (bool) {
        // the key of the swap
        bytes32 swapKey = keccak256(abi.encode(msg.sender, _swapNumber));

        // assert that a swap exists for this user
        require(swaps[swapKey].user == msg.sender, '11');

        // assert that this swap has not already been closed
        require(!swaps[swapKey].isClosed, '12');

        // get the swap to be closed
        Swap memory swap = swaps[swapKey];

        // the amounts that the user and the AMM will pay on this swap, depending on the direction of the swap
        (uint256 userToPay, uint256 ammToPay) = _calculateInterestAccrued(swap);

        // assert that the swap cannot be closed in the same block that it was opened
        require(block.number > swap.openBlock, '13');

        // the total payout for this swap
        uint256 payout = userToPay > ammToPay ? userToPay.sub(ammToPay) : ammToPay.sub(userToPay);

        // the supplementary collateral of this swap
        uint256 supplementaryCollateral = swap.activeLiquidity;

        // the active liquidity recovered upon closure of this swap
        uint256 activeLiquidityRecovered;

        // the amount to reward the user upon closing of the swap
        uint256 redeemableFunds;

        // the user won the swap
        if (ammToPay > userToPay) {
            // ensure the payout does not exceed the active liquidity for this swap
            payout = Math.min(payout, swap.activeLiquidity);

            // active liquidity recovered is the the total active liquidity reduced by the user's payout
            activeLiquidityRecovered = swap.activeLiquidity.sub(payout);

            // User can redeem all of swap collateral, all of supplementary collateral, and the payout
            redeemableFunds = swap.swapCollateral.add(supplementaryCollateral).add(payout);
        }

        // the AMM won the swap
        else if (ammToPay < userToPay) {
            // ensure the payout does not exceed the swap collateral for this swap
            payout = Math.min(payout, swap.swapCollateral);

            // active liquidity recovered is the the total active liquidity increased by the amm's payout
            activeLiquidityRecovered = swap.activeLiquidity.add(payout);

            // user can redeem all of swap collateral, all of supplementary collateral, with the payout subtracted
            redeemableFunds = swap.swapCollateral.add(supplementaryCollateral).sub(payout);
        }

        // neither party won the swap
        else {
            // active liquidity recovered is the the initial active liquidity for the trade
            activeLiquidityRecovered = swap.activeLiquidity;

            // user can redeem all of swap collateral and all of supplementary collateral
            redeemableFunds = swap.swapCollateral.add(supplementaryCollateral);
        }

        // update the total active liquidity
        totalActiveLiquidity = totalActiveLiquidity.sub(swap.activeLiquidity);

        // update the total swap collateral
        totalSwapCollateral = totalSwapCollateral.sub(swap.swapCollateral);

        // update the total supplementary collateral
        totalSupplementaryCollateral = totalSupplementaryCollateral.sub(supplementaryCollateral);

        // update the total available liquidity
        totalAvailableLiquidity = totalAvailableLiquidity.add(activeLiquidityRecovered);

        // close the swap
        swaps[swapKey].isClosed = true;

        // calculate the new pool utilization
        utilization = _calculateUtilization();

        // calculate the new fixed interest rate
        fixedRate = _calculateFixedRate();

        // transfer redeemable funds to the user
        IERC20(underlier).safeTransfer(
            msg.sender, 
            _convertToUnderlierDecimal(redeemableFunds)
        );

        // emit a close swap event
        emit CloseSwap(msg.sender, swap.notional, userToPay, ammToPay, swap.fixedRate);

        return true;
    }

    // ============ Deposit liquidity into the pool ============

    function depositLiquidity(uint256 _liquidityAmount) external override returns (bool) {

        // adjust liquidity amount to standard decimals
        uint256 adjustedLiquidityAmount = _convertToStandardDecimal(_liquidityAmount);

        // asert that liquidity amount must be greater than 0 and amount to less than the max deposit limit
        require(adjustedLiquidityAmount > 0 && adjustedLiquidityAmount.add(totalActiveLiquidity).add(totalAvailableLiquidity) <= maxDepositLimit, '14');

        // transfer the specified amount of underlier into the pool
        IERC20(underlier).safeTransferFrom(msg.sender, address(this), _liquidityAmount);

        // add to the total available liquidity in the pool
        totalAvailableLiquidity = totalAvailableLiquidity.add(adjustedLiquidityAmount);

        // update the most recent deposit block of the liquidity provider
        liquidityProviderLastDeposit[msg.sender] = block.number;

        // calculate the new pool utilization
        utilization = _calculateUtilization();

        // calculate the new fixed interest rate
        fixedRate = _calculateFixedRate();

        // mint LP tokens to the liiquidity provider
        _mintLPTokens(msg.sender, adjustedLiquidityAmount);

        // emit deposit liquidity event
        emit DepositLiquidity(msg.sender, adjustedLiquidityAmount);

        return true;
    }


    // ============ Withdraw liquidity into the pool ============

    function withdrawLiquidity(uint256 _liquidityTokenAmount) external override returns (bool) {
        // assert that withdrawal does not occur in the same block as a deposit
        require(liquidityProviderLastDeposit[msg.sender] < block.number, '19');

        // asert that liquidity amount must be greater than 0
        require(_liquidityTokenAmount > 0, '14');

        // transfer the liquidity tokens from sender to the pool
        IERC20(address(this)).safeTransferFrom(msg.sender, address(this), _liquidityTokenAmount);

        // determine the amount of underlying tokens that the liquidity tokens can be redeemed for
        uint256 redeemableUnderlyingTokens = calculateLiquidityTokenValue(_liquidityTokenAmount);

        // assert that there is enough available liquidity to safely withdraw this amount
        require(totalAvailableLiquidity >= redeemableUnderlyingTokens, '10');

        // the fees that this withdraw will yield (total fees accrued * withdraw amount / total liquidity provided)
        uint256 feeShare = totalFees.mul(redeemableUnderlyingTokens).div(totalActiveLiquidity.add(totalAvailableLiquidity));

        // update the total fees remaining in the pool
        totalFees = totalFees.sub(feeShare);

        // remove the withdrawn amount from  the total available liquidity in the pool
        totalAvailableLiquidity = totalAvailableLiquidity.sub(redeemableUnderlyingTokens);

        // calculate the new pool utilization
        utilization = _calculateUtilization();

        // calculate the new fixed interest rate
        fixedRate = _calculateFixedRate();

        // burn LP tokens and redeem underlying tokens to the liiquidity provider
        _burnLPTokens(msg.sender, _liquidityTokenAmount);

        // emit withdraw liquidity event
        emit WithdrawLiquidity(msg.sender, _liquidityTokenAmount, feeShare);

        return true;
    }

    // ============ Liquidate a swap that has expired ============
 
    function liquidate(address _user, uint256 _swapNumber) external override returns (bool) {
        // the key of the swap
        bytes32 swapKey = keccak256(abi.encode(_user, _swapNumber));

        // assert that a swap exists for this user
        require(swaps[swapKey].user == _user, '11');

        // get the swap to be liquidated
        Swap memory swap = swaps[swapKey];

        // assert that the swap has not already been closed
        require(!swap.isClosed, '12');

        // the expiration block of the swap
        uint256 expirationBlock = swap.openBlock.add(durationInDays.mul(BLOCKS_PER_DAY));

        // assert that the swap has eclipsed the expiration block
        require(block.number >= expirationBlock, '17');
        
        // transfer trade active liquidity from the liquidator
        IERC20(underlier).safeTransferFrom(
            msg.sender,
            address(this),
            _convertToUnderlierDecimal(swap.activeLiquidity)
        );

        // the amounts that the user and the AMM will pay on this swap, depending on the direction of the swap
        (uint256 userToPay, uint256 ammToPay) =_calculateInterestAccrued(swap);

        // the total payout for this swap
        uint256 payout = userToPay > ammToPay ? userToPay.sub(ammToPay) : ammToPay.sub(userToPay);

        // the supplementary collateral of this swap
        uint256 supplementaryCollateral = swap.activeLiquidity;

        // the active liquidity recovered upon liquidation of this swap
        uint256 activeLiquidityRecovered;

        // the amount to reward the liquidator upon liquidation of the swap
        uint256 liquidatorReward;

        // the user won the swap
        if (ammToPay > userToPay) {
            // ensure the payout does not exceed the active liquidity for this swap
            payout = Math.min(payout, swap.activeLiquidity);

            // active liquidity recovered is the the total active liquidity increased by the user's unclaimed payout
            activeLiquidityRecovered = swap.activeLiquidity.add(payout);

            // liquidator is rewarded the supplementary collateral and the difference between the swap collateral and the payout
            liquidatorReward = supplementaryCollateral.add(swap.swapCollateral).sub(payout);
        }

        // the AMM won the swap
        else if (ammToPay < userToPay) {
            // ensure the payout does not exceed the swap collateral for this swap
            payout = Math.min(payout, swap.swapCollateral);
            
            // active liquidity recovered is the the total active liquidity increased by the entire swap collateral
            activeLiquidityRecovered = swap.activeLiquidity.add(swap.swapCollateral);

            // liquidator is rewarded all of the supplementary collateral
            liquidatorReward = supplementaryCollateral;
        }

        // neither party won the swap
        else {
            // active liquidity recovered is the the total active liquidity for this swap
            activeLiquidityRecovered = swap.activeLiquidity;

            // liquidator is rewarded all of the supplementary collateral and the swap collateral
            liquidatorReward = supplementaryCollateral.add(swap.swapCollateral);
        }

        // update the total active liquidity
        totalActiveLiquidity = totalActiveLiquidity.sub(swap.activeLiquidity);

        // update the total swap collateral
        totalSwapCollateral = totalSwapCollateral.sub(swap.swapCollateral);

        // update the total supplementary collateral
        totalSupplementaryCollateral = totalSupplementaryCollateral.sub(supplementaryCollateral);

        // update the total available liquidity
        totalAvailableLiquidity = totalAvailableLiquidity.add(activeLiquidityRecovered);

        // close the swap
        swaps[swapKey].isClosed = true;

        // calculate the new pool utilization
        utilization = _calculateUtilization();

        // calculate the new fixed interest rate
        fixedRate = _calculateFixedRate();

        // transfer liquidation reward to the liquidator
        IERC20(underlier).safeTransfer(
            msg.sender, 
            _convertToUnderlierDecimal(liquidatorReward)
        );

        // emit liquidate event
        emit Liquidate(msg.sender, _user, _swapNumber, liquidatorReward);

        return true;
    }

    // ============ External view for the interest accrued on a variable rate ============

    function calculateVariableInterestAccrued(uint256 _notional, uint256 _borrowIndex) external view override returns (uint256) {
        return _calculateVariableInterestAccrued(_notional, _borrowIndex);
    }

    // ============ External view for the interest accrued on a fixed rate ============

    function calculateFixedInterestAccrued(uint256 _notional, uint256 _fixedRate, uint256 _openBlock) external view override returns (uint256) {
        return _calculateFixedInterestAccrued(_notional, _fixedRate, _openBlock);
    }

    // ============ Calculates the fixed rate offered ============

    function calculateFixedRate() external view returns (uint256) {
        return _calculateFixedRate();
    }

    // ============ Calculates the max variable rate to pay ============

    function calculateMaxVariableRate() external view returns (uint256) {
        return _calculateMaxVariableRate();
    }

    // ============ Calculates the current variable rate for the underlier ============

    function calculateVariableRate() external view returns (uint256) {
        
        // get the borrow rate from the adapter
        return IAdapter(adapter).getBorrowRate(underlier);
    }

    // ============ Allows governance to change the max deposit limit ============

    function changeMaxDepositLimit(uint256 _limit) external {

        // assert that only governance can adjust the deposit limit
        require(msg.sender == GOVERNANCE, '18');

        // change the deposit limit
        maxDepositLimit = _limit;
    }

    // ============ Calculates the current approximate value of liquidity tokens denoted in the underlying token ============

    function calculateLiquidityTokenValue(uint256 liquidityTokenAmount) public view returns (uint256 redeemableUnderlyingTokens) {

        // get the total underlying token balance in this pool with supplementary and swap collateral amounts excluded
        uint256 adjustedUnderlyingTokenBalance = _convertToStandardDecimal(IERC20(underlier).balanceOf(address(this)))
                                                    .sub(totalSwapCollateral)
                                                    .sub(totalSupplementaryCollateral);

        // the total supply of LP tokens in circulation
        uint256 _totalSupply = totalSupply();

        // determine the amount of underlying tokens that the liquidity tokens can be redeemed for
        redeemableUnderlyingTokens = liquidityTokenAmount.mul(adjustedUnderlyingTokenBalance).div(_totalSupply);
    }

    // ============ Internal methods ============

    // ============ Mints LP tokens to users that deposit liquidity to the protocol ============

    function _mintLPTokens(address to, uint256 underlyingTokenAmount) internal {

        // the total supply of LP tokens in circulation
        uint256 _totalSupply = totalSupply();

        // determine the amount of LP tokens to mint
        uint256 mintableLiquidity;

        if (_totalSupply == 0) {
            // initialize the supply of LP tokens
            mintableLiquidity = underlyingTokenAmount;
        } 
        
        else {
            // get the total underlying token balance in this pool
            uint256 underlyingTokenBalance = _convertToStandardDecimal(IERC20(underlier).balanceOf(address(this)));
                                                
            // adjust the underlying token balance to standardize the decimals
            // the supplementary collateral, swap collateral, and newly added liquidity amounts are excluded
            uint256 adjustedUnderlyingTokenBalance = underlyingTokenBalance
                                                        .sub(totalSwapCollateral)
                                                        .sub(totalSupplementaryCollateral)
                                                        .sub(underlyingTokenAmount);

            // mint a proportional amount of LP tokens
            mintableLiquidity = underlyingTokenAmount.mul(_totalSupply).div(adjustedUnderlyingTokenBalance);
        }

        // assert that enough liquidity tokens are available to be minted
        require(mintableLiquidity > 0, 'INSUFFICIENT_LIQUIDITY_MINTED');

        // mint the tokens directly to the LP
        _mint(to, mintableLiquidity);

        // emit minting of LP token event
        emit Mint(to, underlyingTokenAmount, mintableLiquidity);
    }

    // ============ Burns LP tokens and sends users the equivalent underlying tokens in return ============

    function _burnLPTokens(address to, uint256 liquidityTokenAmount) internal {

        // determine the amount of underlying tokens that the liquidity tokens can be redeemed for
        uint256 redeemableUnderlyingTokens = calculateLiquidityTokenValue(liquidityTokenAmount);

        // assert that enough underlying tokens are available to send to the redeemer
        require(redeemableUnderlyingTokens > 0, 'INSUFFICIENT_LIQUIDITY_BURNED');

        // burn the liquidity tokens
        _burn(address(this), liquidityTokenAmount);

        // transfer the underlying tokens
        IERC20(underlier).safeTransfer(to, _convertToUnderlierDecimal(redeemableUnderlyingTokens));

        // emit burning of LP token event
        emit Mint(to, redeemableUnderlyingTokens, liquidityTokenAmount);
    }

    // ============ Calculates the fixed rate offered ============

    function _calculateFixedRate() internal view returns (uint256) {

        // the new fixed rate based on updated pool utilization
        uint256 newFixedRate;

        // the rate offered before the utilization inflection is hit
        int256 preInflectionLeg;
        
        // the pool is long
        if (direction == 0) {
            // (utilization * rate sensitivity) + rate limit
            preInflectionLeg = int256(utilization.mul(rateSensitivity).div(TEN_EXP_18).add(rateLimit));
        }
        
        // the pool is short
        else {
            // rate limit - (utilization * rate sensitivity)
            preInflectionLeg = int256(rateLimit) - int256(utilization.mul(rateSensitivity).div(TEN_EXP_18));
        }

        // pool utilization is below the inflection
        if (utilization < utilizationInflection) {
            // assert that the leg is positive before converting to uint256
            require(preInflectionLeg > 0);

            newFixedRate = uint256(preInflectionLeg);
        }

        // pool utilization is at or above the inflection
        else {
            // The additional change in the rate after the utilization inflection is hit
            // rate multiplier * (utilization - utilization inflection)
            int256 postInflectionLeg = int256(rateMultiplier.mul(utilization.sub(utilizationInflection)).div(TEN_EXP_18));

            // assert that the addition of the legs is positive before converting to uint256
            require(preInflectionLeg + postInflectionLeg > 0);

            newFixedRate = uint256(preInflectionLeg + postInflectionLeg);
        }

        // adjust the fixed rate as a percentage
        return newFixedRate.div(100);
    }

    // ============ Calculates the pool utilization ============

    function _calculateUtilization() internal view returns (uint256) {

        // get the total liquidity of this pool
        uint256 totalPoolLiquidity = totalActiveLiquidity.add(totalAvailableLiquidity);

        // pool utilization is the total active liquidity / total pool liquidity
        uint256 newUtilization = totalActiveLiquidity.mul(TEN_EXP_18).div(totalPoolLiquidity);

        // adjust utilization to be an integer between 0 and 100
        uint256 adjustedUtilization = newUtilization * 100;

        return adjustedUtilization;
    }

    // ============ Calculates the swap collateral and active liquidity needed for a given notional ============

    function _calculateSwapCollateralAndActiveLiquidity(uint256 _notional) internal view returns (uint256, uint256) {
        // The maximum rate the user will pay on a swap
        uint256 userMaxRateToPay = direction == 0 ? fixedRate : _calculateMaxVariableRate();

        // the maximum rate the AMM will pay on a swap
        uint256 ammMaxRateToPay = direction == 1 ? fixedRate : _calculateMaxVariableRate();

        // notional * maximum rate to pay * (swap duration in days / days per year)
        uint256 swapCollateral = _calculateMaxAmountToPay(_notional, userMaxRateToPay);
        uint256 activeLiquidity = _calculateMaxAmountToPay(_notional, ammMaxRateToPay);

        return (swapCollateral, activeLiquidity);
    }

    // ============ Calculates the maximum amount to pay over a specific time window with a given notional and rate ============

    function _calculateMaxAmountToPay(uint256 _notional, uint256 _rate) internal view returns (uint256) {
        // the period by which to adjust the rate
        uint256 period = DAYS_PER_YEAR.div(durationInDays);

        // notional * maximum rate to pay / (days per year / swap duration in days)
        return _notional.mul(_rate).div(TEN_EXP_18).div(period);
    }

    // ============ Calculates the maximum variable rate ============

    function _calculateMaxVariableRate() internal view returns (uint256) {
        // use the current variable rate for the underlying token
        uint256 variableRate = IAdapter(adapter).getBorrowRate(underlier);

        // calculate a variable rate buffer 
        uint256 maxBuffer = MAX_TO_PAY_BUFFER_NUMERATOR.mul(TEN_EXP_18).div(MAX_TO_PAY_BUFFER_DENOMINATOR);
        
        // add the buffer to the current variable rate
        return variableRate.add(maxBuffer);
    }

    // ============ Calculates the interest accrued for both parties on a swap ============

    function _calculateInterestAccrued(Swap memory _swap) internal view returns (uint256, uint256) {
        // the amounts that the user and the AMM will pay on this swap, depending on the direction of the swap
        uint256 userToPay;
        uint256 ammToPay;

        // the fixed interest accrued on this swap
        uint256 fixedInterestAccrued = _calculateFixedInterestAccrued(_swap.notional, _swap.fixedRate, _swap.openBlock);

        // the variable interest accrued on this swap
        uint256 variableInterestAccrued = _calculateVariableInterestAccrued(_swap.notional, _swap.underlierBorrowIndex);

        // user went long on the variable rate
        if (direction == 0) {
            userToPay = fixedInterestAccrued;
            ammToPay = variableInterestAccrued;
        } 

        // user went short on the variable rate
        else {
            userToPay = variableInterestAccrued;
            ammToPay = fixedInterestAccrued;
        }

        return (userToPay, ammToPay);
    }

    // ============ Calculates the interest accrued on a fixed rate ============

    function _calculateFixedInterestAccrued(uint256 _notional, uint256 _fixedRate, uint256 _openBlock) internal view returns (uint256) {
        // the period of the fixed interest accrued
        uint256 period = durationInDays.mul(TEN_EXP_18).div(DAYS_PER_YEAR);

        // notional * fixed rate * (swap duration / days in year)
        uint256 maxFixedInterest = _notional.mul(_fixedRate).div(TEN_EXP_18).mul(period).div(TEN_EXP_18);

        // the blocks that have elapsed since the swap was opened
        uint256 blocksElapsed = block.number.sub(_openBlock);

        // the total blocks in a swap
        uint256 totalBlocksInSwapDuration = durationInDays.mul(BLOCKS_PER_DAY);

        // the percentage that the swap has matured
        // safeguard against blocks elapsed potentially being bigger than the total blocks in the swap
        uint256 swapMaturity = blocksElapsed < totalBlocksInSwapDuration ? blocksElapsed.mul(TEN_EXP_18).div(totalBlocksInSwapDuration) : TEN_EXP_18;

        // the max fixed amount one can pay in a full swap * the maturity percentage of the swap
        return maxFixedInterest.mul(swapMaturity).div(TEN_EXP_18);
    }

    // ============ Calculates the interest accrued on a variable rate ============

    function _calculateVariableInterestAccrued(uint256 _notional, uint256 _openSwapBorrowIndex) internal view returns (uint256) {
        // get the current borrow index of the underlying asset
        uint256 currentBorrowIndex = IAdapter(adapter).getBorrowIndex(underlier);

        // The ratio between the current borrow index and the borrow index at time of open swap
        uint256 indexRatio = currentBorrowIndex.mul(TEN_EXP_18).div(_openSwapBorrowIndex);

        // notional * (current borrow index / borrow index when swap was opened) - notional
        return _notional.mul(indexRatio).div(TEN_EXP_18).sub(_notional);
    }

    // ============ Converts an amount to have the contract standard number of decimals ============

    function _convertToStandardDecimal(uint256 _amount) internal view returns (uint256) {

        // set adjustment direction to false to convert to standard pool decimals
        return _convertToDecimal(_amount, true);
    }


    // ============ Converts an amount to have the underlying token's number of decimals ============

    function _convertToUnderlierDecimal(uint256 _amount) internal view returns (uint256) {

        // set adjustment direction to true to convert to underlier decimals
        return _convertToDecimal(_amount, false);
    }

    // ============ Converts an amount to have a particular number of decimals ============

    function _convertToDecimal(uint256 _amount, bool _adjustmentDirection) internal view returns (uint256) {
        // the amount after it has been converted to have the underlier number of decimals
        uint256 convertedAmount;

        // the underlying token has less decimal places
        if (underlierDecimals < STANDARD_DECIMALS) {
            convertedAmount = _adjustmentDirection ? _amount.mul(10 ** decimalDifference) : _amount.div(10 ** decimalDifference);
        }

        // there is no difference in the decimal places
        else {
            convertedAmount = _amount;
        }

        return convertedAmount;
    }

    // ============ Calculates the difference between the underlying decimals and the standard decimals ============

    function _calculatedDecimalDifference(uint256 _x_decimal, uint256 _y_decimal) internal pure returns (uint256) {
        // the difference in decimals
        uint256 difference;

        // the second decimal is greater
        if (_x_decimal < _y_decimal) {
            difference = _y_decimal.sub(_x_decimal);
        }

        return difference;
    }
}

File 2 of 10 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
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) {
        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) {
        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) {
        // 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) {
        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) {
        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) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @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) {
        require(b <= a, "SafeMath: subtraction overflow");
        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) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @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. 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) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        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) {
        require(b > 0, "SafeMath: modulo by zero");
        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) {
        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.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * 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) {
        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) {
        require(b > 0, errorMessage);
        return a % b;
    }
}

File 3 of 10 : Math.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

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

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

File 4 of 10 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

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

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

File 5 of 10 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

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

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

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

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

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

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

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

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

File 6 of 10 : IPool.sol
// SPDX-License-Identifier: Unlicensed
pragma solidity 0.7.6;

interface IPool {
    function openSwap(uint256 _notional) external returns (bool);
    function closeSwap(uint256 _swapNumber) external returns (bool);
    function depositLiquidity(uint256 _liquidityAmount) external returns (bool);
    function withdrawLiquidity(uint256 _liquidityAmount) external returns (bool);
    function liquidate(address _user, uint256 _swapNumber) external returns (bool);
    function calculateVariableInterestAccrued(uint256 _notional, uint256 _borrowIndex) external view returns (uint256);
    function calculateFixedInterestAccrued(uint256 _notional, uint256 _fixedRate, uint256 _openBlock) external view returns (uint256);
}

File 7 of 10 : IAdapter.sol
// SPDX-License-Identifier: Unlicensed
pragma solidity >=0.6.12;


interface IAdapter {
    function getBorrowIndex(address underlier) external view returns (uint256);
    function getBorrowRate(address underlier) external view returns (uint256);
}

File 8 of 10 : GreenwoodERC20.sol
// SPDX-License-Identifier: Unlicensed
pragma solidity 0.7.6;

// ============ Contract information ============

/**
 * @title  Greenwood LP token
 * @notice An LP token for Greenwood Basis Swaps
 * @author Greenwood Labs
 */

 // ============ Imports ============

import '../interfaces/IGreenwoodERC20.sol';
import '@openzeppelin/contracts/math/SafeMath.sol';


contract GreenwoodERC20 is IGreenwoodERC20 {
    // ============ Import usage ============

    using SafeMath for uint256;

    // ============ Immutable storage ============

    string public constant override name = 'Greenwood';
    string public constant override symbol = 'GRN';
    uint256 public constant override decimals = 18;

    // ============ Mutable storage ============

    uint256 private _totalSupply;

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

    // ============ Events ============

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

    // ============ Constructor ============

    constructor() {}

    // ============ External methods ============

    // ============ Returns the amount of tokens in existence ============

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

    // ============ Returns the amount of tokens owned by `account` ============

    function balanceOf(address account) public view override returns (uint256) {
        return _balances[account];
    }

    // ============ Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` ============

    function allowance(address owner, address spender) public view override returns (uint256) {
        return _allowances[owner][spender];
    }

    // ============ Sets `amount` as the allowance of `spender` over the caller's tokens ============

    function approve(address spender, uint256 amount) external override returns (bool) {
        _approve(msg.sender, spender, amount);
        return true;
    }

    // ============ Moves `amount` tokens from the caller's account to `recipient` ============

    function transfer(address recipient, uint256 amount) external override returns (bool) {
        _transfer(msg.sender, recipient, amount);
        return true;
    }

    // ============ Moves `amount` tokens from `sender` to `recipient` using the allowance mechanism ============

    function transferFrom(address sender, address recipient, uint256 amount) external override returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, msg.sender, _allowances[sender][msg.sender].sub(amount, 'GreenwoodERC20: transfer amount exceeds allowance'));
        return true;
    }

    // ============ Internal methods ============

    // ============ Creates `amount` tokens and assigns them to `account`, increasing the total supply ============

    function _mint(address account, uint256 amount) internal {
        require(account != address(0), 'GreenwoodERC20: mint to the zero address');

        _totalSupply = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);

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

    // ============ Destroys `amount` tokens from `account`, reducing the total supply ============

    function _burn(address account, uint256 amount) internal {
        require(account != address(0), 'GreenwoodERC20: burn from the zero address');

        _balances[account] = _balances[account].sub(amount, 'GreenwoodERC20: burn amount exceeds balance');
        _totalSupply = _totalSupply.sub(amount);

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

    // ============ Sets `amount` as the allowance of `spender` over the tokens of the `owner` ============

    function _approve(address owner, address spender, uint256 amount) internal {
        require(owner != address(0), 'GreenwoodERC20: approve from the zero address');
        require(spender != address(0), 'GreenwoodERC20: approve to the zero address');

        _allowances[owner][spender] = amount;

        emit Approval(owner, spender, amount);
    }

    // ============ Moves tokens `amount` from `sender` to `recipient` ============

    function _transfer(address sender, address recipient, uint256 amount) internal {
        require(sender != address(0), 'GreenwoodERC20: transfer from the zero address');
        require(recipient != address(0), 'GreenwoodERC20: transfer to the zero address');

        _balances[sender] = _balances[sender].sub(amount, 'GreenwoodERC20: transfer amount exceeds balance');
        _balances[recipient] = _balances[recipient].add(amount);

        emit Transfer(sender, recipient, amount);
    }
}

File 9 of 10 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

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

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }

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

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

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

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

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

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

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

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

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

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

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

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

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 10 of 10 : IGreenwoodERC20.sol
// SPDX-License-Identifier: Unlicensed
pragma solidity 0.7.6;

interface IGreenwoodERC20 {
    function name() external pure returns (string memory); 
    function symbol() external pure returns (string memory);
    function decimals() external pure returns (uint256);
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function allowance(address owner, address spender) external view returns (uint256);
    
    function approve(address spender, uint256 amount) external returns (bool);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
}

Settings
{
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_underlier","type":"address"},{"internalType":"uint256","name":"_underlierDecimals","type":"uint256"},{"internalType":"address","name":"_adapter","type":"address"},{"internalType":"uint256","name":"_protocol","type":"uint256"},{"internalType":"uint256","name":"_direction","type":"uint256"},{"internalType":"uint256","name":"_durationInDays","type":"uint256"},{"internalType":"uint256","name":"_initialDeposit","type":"uint256"},{"internalType":"uint256","name":"_rateLimit","type":"uint256"},{"internalType":"uint256","name":"_rateSensitivity","type":"uint256"},{"internalType":"uint256","name":"_utilizationInflection","type":"uint256"},{"internalType":"uint256","name":"_rateMultiplier","type":"uint256"},{"internalType":"address","name":"_poolDeployer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"underlyingTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidityTokenAmount","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"notional","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"userToPay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ammToPay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fixedRate","type":"uint256"}],"name":"CloseSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"liquidityAmount","type":"uint256"}],"name":"DepositLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"swapNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidatorReward","type":"uint256"}],"name":"Liquidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"underlyingTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidityTokenAmount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"notional","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"activeLiquidity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fixedRate","type":"uint256"}],"name":"OpenSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"liquidityAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feesAccrued","type":"uint256"}],"name":"WithdrawLiquidity","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_notional","type":"uint256"},{"internalType":"uint256","name":"_fixedRate","type":"uint256"},{"internalType":"uint256","name":"_openBlock","type":"uint256"}],"name":"calculateFixedInterestAccrued","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"calculateFixedRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"liquidityTokenAmount","type":"uint256"}],"name":"calculateLiquidityTokenValue","outputs":[{"internalType":"uint256","name":"redeemableUnderlyingTokens","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"calculateMaxVariableRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_notional","type":"uint256"},{"internalType":"uint256","name":"_borrowIndex","type":"uint256"}],"name":"calculateVariableInterestAccrued","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"calculateVariableRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"changeMaxDepositLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_swapNumber","type":"uint256"}],"name":"closeSwap","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimalDifference","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_liquidityAmount","type":"uint256"}],"name":"depositLiquidity","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"direction","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"durationInDays","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fixedRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_swapNumber","type":"uint256"}],"name":"liquidate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"liquidityProviderLastDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxDepositLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_notional","type":"uint256"}],"name":"openSwap","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"protocol","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rateLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rateMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rateSensitivity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"swapNumbers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"swaps","outputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"bool","name":"isClosed","type":"bool"},{"internalType":"uint256","name":"notional","type":"uint256"},{"internalType":"uint256","name":"swapCollateral","type":"uint256"},{"internalType":"uint256","name":"activeLiquidity","type":"uint256"},{"internalType":"uint256","name":"openBlock","type":"uint256"},{"internalType":"uint256","name":"underlierBorrowIndex","type":"uint256"},{"internalType":"uint256","name":"fixedRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalActiveLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAvailableLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupplementaryCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSwapCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"underlier","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlierDecimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"utilization","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"utilizationInflection","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_liquidityTokenAmount","type":"uint256"}],"name":"withdrawLiquidity","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]

60806040523480156200001157600080fd5b50604051620051c3380380620051c383398181016040526101808110156200003857600080fd5b81019080805190602001909291908051906020019092919080519060200190929190805190602001909291908051906020019092919080519060200190929190805190602001909291908051906020019092919080519060200190929190805190602001909291908051906020019092919080519060200190929190505050600086116200012e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313400000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b33600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508b600560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508a60108190555088600d8190555087600e8190555086600f81905550620001e16010546012620002f060201b60201c565b6011819055506000620001fa876200032360201b60201c565b9050806009819055508a600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508560128190555084601381905550836014819055508260158190555069d3c21bcecceda1000000601681905550620002816200033f60201b60201c565b600b8190555043601960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550620002dd8282620004b260201b60201c565b5050505050505050505050505062000b72565b6000808284101562000319576200031684846200072660201b6200293f1790919060201c565b90505b8091505092915050565b600062000338826001620007aa60201b60201c565b9050919050565b600080600080600e541415620003b157620003a960125462000395670de0b6b3a764000062000381601354600c546200081a60201b620029c21790919060201c565b620008a560201b62002a481790919060201c565b6200093060201b62002ad11790919060201c565b9050620003f7565b620003f0670de0b6b3a7640000620003dc601354600c546200081a60201b620029c21790919060201c565b620008a560201b62002a481790919060201c565b6012540390505b601454600c5410156200041b57600081136200041257600080fd5b80915062000490565b600062000477670de0b6b3a7640000620004636200044c601454600c546200072660201b6200293f1790919060201c565b6015546200081a60201b620029c21790919060201c565b620008a560201b62002a481790919060201c565b90506000818301136200048957600080fd5b8082019250505b620004ab606483620008a560201b62002a481790919060201c565b9250505090565b6000620004c4620009b960201b60201c565b9050600080821415620004da5782905062000641565b6000620005b3600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156200056a57600080fd5b505afa1580156200057f573d6000803e3d6000fd5b505050506040513d60208110156200059657600080fd5b81019080805190602001909291905050506200032360201b60201c565b905060006200060785620005f3600754620005df600654876200072660201b6200293f1790919060201c565b6200072660201b6200293f1790919060201c565b6200072660201b6200293f1790919060201c565b90506200063c816200062886886200081a60201b620029c21790919060201c565b620008a560201b62002a481790919060201c565b925050505b60008111620006b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f494e53554646494349454e545f4c49515549444954595f4d494e54454400000081525060200191505060405180910390fd5b620006ca8482620009c260201b60201c565b8373ffffffffffffffffffffffffffffffffffffffff167f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f8483604051808381526020018281526020019250505060405180910390a250505050565b6000828211156200079f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525060200191505060405180910390fd5b818303905092915050565b600080601260105410156200080c5782620007e457620007de601154600a0a85620008a560201b62002a481790919060201c565b62000804565b62000803601154600a0a856200081a60201b620029c21790919060201c565b5b905062000810565b8390505b8091505092915050565b6000808314156200082f57600090506200089f565b60008284029050828482816200084157fe5b04146200089a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180620051a26021913960400191505060405180910390fd5b809150505b92915050565b60008082116200091d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525060200191505060405180910390fd5b8183816200092757fe5b04905092915050565b600080828401905083811015620009af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b60008054905090565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141562000a4a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260288152602001806200517a6028913960400191505060405180910390fd5b62000a66816000546200093060201b62002ad11790919060201c565b60008190555062000ac581600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546200093060201b62002ad11790919060201c565b600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b6145f88062000b826000396000f3fe608060405234801561001057600080fd5b506004361061025e5760003560e01c80638064a05911610146578063c11eaae2116100c3578063e43c520d11610087578063e43c520d14610a69578063e588b50514610aad578063ea21cd9214610b03578063eb84e7f214610b21578063f3eb4f8a14610bac578063fa7e8d0114610bf05761025e565b8063c11eaae21461093f578063ce3f28f01461095d578063ce7539011461097b578063d14ab67d146109d3578063dd62ed3e146109f15761025e565b8063a9059cbb1161010a578063a9059cbb146107bf578063b2485f9714610823578063b63c44e714610865578063b6984be914610883578063bcbaf487146108db5761025e565b80638064a059146106705780638ce744261461069e5780638d7aeae5146106bc57806391cfad5a1461070857806395d89b411461073c5761025e565b8063330691ac116101df578063645539ed116101a3578063645539ed1461055c57806370a082311461057a578063735d80e3146105d257806376d58e1a146105f05780637b83002914610634578063802d1422146106525761025e565b8063330691ac146104c6578063356cd90a146104e45780633fc896a21461050257806354b6ba951461052057806361e08e721461053e5761025e565b806318160ddd1161022657806318160ddd146103ca57806323b872dd146103e857806327b380ea1461046c578063294164531461048a578063313ce567146104a85761025e565b806306fdde0314610263578063095ea7b3146102e65780630a2a8e781461034a5780630a861f2a1461036857806313114a9d146103ac575b600080fd5b61026b610c0e565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102ab578082015181840152602081019050610290565b50505050905090810190601f1680156102d85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610332600480360360408110156102fc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610c47565b60405180821515815260200191505060405180910390f35b610352610c5e565b6040518082815260200191505060405180910390f35b6103946004803603602081101561037e57600080fd5b8101908080359060200190929190505050610d4b565b60405180821515815260200191505060405180910390f35b6103b4611027565b6040518082815260200191505060405180910390f35b6103d261102d565b6040518082815260200191505060405180910390f35b610454600480360360608110156103fe57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611036565b60405180821515815260200191505060405180910390f35b610474611101565b6040518082815260200191505060405180910390f35b610492611107565b6040518082815260200191505060405180910390f35b6104b061110d565b6040518082815260200191505060405180910390f35b6104ce611112565b6040518082815260200191505060405180910390f35b6104ec611118565b6040518082815260200191505060405180910390f35b61050a61111e565b6040518082815260200191505060405180910390f35b610528611124565b6040518082815260200191505060405180910390f35b61054661112a565b6040518082815260200191505060405180910390f35b610564611130565b6040518082815260200191505060405180910390f35b6105bc6004803603602081101561059057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611136565b6040518082815260200191505060405180910390f35b6105da61117f565b6040518082815260200191505060405180910390f35b61061c6004803603602081101561060657600080fd5b8101908080359060200190929190505050611185565b60405180821515815260200191505060405180910390f35b61063c61136b565b6040518082815260200191505060405180910390f35b61065a61137a565b6040518082815260200191505060405180910390f35b61069c6004803603602081101561068657600080fd5b8101908080359060200190929190505050611380565b005b6106a661143f565b6040518082815260200191505060405180910390f35b6106f2600480360360408110156106d257600080fd5b810190808035906020019092919080359060200190929190505050611445565b6040518082815260200191505060405180910390f35b610710611459565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61074461147f565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610784578082015181840152602081019050610769565b50505050905090810190601f1680156107b15780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61080b600480360360408110156107d557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506114b8565b60405180821515815260200191505060405180910390f35b61084f6004803603602081101561083957600080fd5b81019080803590602001909291905050506114cf565b6040518082815260200191505060405180910390f35b61086d611602565b6040518082815260200191505060405180910390f35b6108c56004803603602081101561089957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611608565b6040518082815260200191505060405180910390f35b610927600480360360408110156108f157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611620565b60405180821515815260200191505060405180910390f35b610947611c32565b6040518082815260200191505060405180910390f35b610965611c38565b6040518082815260200191505060405180910390f35b6109bd6004803603602081101561099157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611c3e565b6040518082815260200191505060405180910390f35b6109db611c56565b6040518082815260200191505060405180910390f35b610a5360048036036040811015610a0757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611c65565b6040518082815260200191505060405180910390f35b610a9560048036036020811015610a7f57600080fd5b8101908080359060200190929190505050611cec565b60405180821515815260200191505060405180910390f35b610aed60048036036060811015610ac357600080fd5b810190808035906020019092919080359060200190929190803590602001909291905050506122b7565b6040518082815260200191505060405180910390f35b610b0b6122cd565b6040518082815260200191505060405180910390f35b610b4d60048036036020811015610b3757600080fd5b81019080803590602001909291905050506122d3565b604051808973ffffffffffffffffffffffffffffffffffffffff16815260200188151581526020018781526020018681526020018581526020018481526020018381526020018281526020019850505050505050505060405180910390f35b610bd860048036036020811015610bc257600080fd5b8101908080359060200190929190505050612348565b60405180821515815260200191505060405180910390f35b610bf8612939565b6040518082815260200191505060405180910390f35b6040518060400160405280600981526020017f477265656e776f6f64000000000000000000000000000000000000000000000081525081565b6000610c54338484612b59565b6001905092915050565b6000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d71275f6600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015610d0b57600080fd5b505afa158015610d1f573d6000803e3d6000fd5b505050506040513d6020811015610d3557600080fd5b8101908080519060200190929190505050905090565b600043601960003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410610e01576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313900000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60008211610e77576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313400000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b610ea43330843073ffffffffffffffffffffffffffffffffffffffff16612d50909392919063ffffffff16565b6000610eaf836114cf565b9050806009541015610f29576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313000000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6000610f68610f45600954600854612ad190919063ffffffff16565b610f5a84600a546129c290919063ffffffff16565b612a4890919063ffffffff16565b9050610f7f81600a5461293f90919063ffffffff16565b600a81905550610f9a8260095461293f90919063ffffffff16565b600981905550610fa8612e11565b600c81905550610fb6612e71565b600b81905550610fc63385612f9f565b3373ffffffffffffffffffffffffffffffffffffffff167fac927268ea9ae2e55027e6ab727fc2db8e3ea48c56c658223a1074567e4298c08583604051808381526020018281526020019250505060405180910390a2600192505050919050565b600a5481565b60008054905090565b60006110438484846130dc565b6110f684336110f18560405180606001604052806031815260200161441f60319139600260008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546133969092919063ffffffff16565b612b59565b600190509392505050565b60085481565b60065481565b601281565b60155481565b60105481565b60115481565b600f5481565b60125481565b600e5481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60095481565b60008061119183613450565b90506000811180156111cd57506016546111ca6009546111bc60085485612ad190919063ffffffff16565b612ad190919063ffffffff16565b11155b61123f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313400000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b61128e333085600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16612d50909392919063ffffffff16565b6112a381600954612ad190919063ffffffff16565b60098190555043601960003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506112f5612e11565b600c81905550611303612e71565b600b819055506113133382613464565b3373ffffffffffffffffffffffffffffffffffffffff167f3bdb4d376f46aac1bdcda94b03200364052b278ed93865d759bf61452bfabdba826040518082815260200191505060405180910390a26001915050919050565b6000611375613697565b905090565b600b5481565b73e3d5260cd7f8a4207f41c3b2ac87882489f9721373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611435576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313800000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8060168190555050565b600d5481565b600061145183836137cf565b905092915050565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6040518060400160405280600381526020017f47524e000000000000000000000000000000000000000000000000000000000081525081565b60006114c53384846130dc565b6001905092915050565b6000806115c66007546115b86006546115aa600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561156a57600080fd5b505afa15801561157e573d6000803e3d6000fd5b505050506040513d602081101561159457600080fd5b8101908080519060200190929190505050613450565b61293f90919063ffffffff16565b61293f90919063ffffffff16565b905060006115d261102d565b90506115f9816115eb84876129c290919063ffffffff16565b612a4890919063ffffffff16565b92505050919050565b60165481565b60186020528060005260406000206000915090505481565b6000808383604051602001808373ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040516020818303038152906040528051906020012090508373ffffffffffffffffffffffffffffffffffffffff166017600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611741576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313100000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600060176000838152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900460ff1615151515815260200160018201548152602001600282015481526020016003820154815260200160048201548152602001600582015481526020016006820154815250509050806020015115611889576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313200000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60006118b86118a56119aa600f546129c290919063ffffffff16565b8360a00151612ad190919063ffffffff16565b905080431015611930576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313700000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b61198b33306119428560800151613934565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16612d50909392919063ffffffff16565b60008061199784613948565b9150915060008183116119bc576119b7838361293f90919063ffffffff16565b6119d0565b6119cf828461293f90919063ffffffff16565b5b905060008560800151905060008085851115611a3f576119f48489608001516139ab565b9350611a0d848960800151612ad190919063ffffffff16565b9150611a3884611a2a8a6060015186612ad190919063ffffffff16565b61293f90919063ffffffff16565b9050611a9e565b85851015611a7c57611a558489606001516139ab565b9350611a7288606001518960800151612ad190919063ffffffff16565b9150829050611a9d565b87608001519150611a9a886060015184612ad190919063ffffffff16565b90505b5b611ab7886080015160085461293f90919063ffffffff16565b600881905550611ad6886060015160065461293f90919063ffffffff16565b600681905550611af18360075461293f90919063ffffffff16565b600781905550611b0c82600954612ad190919063ffffffff16565b6009819055506001601760008b815260200190815260200160002060000160146101000a81548160ff021916908315150217905550611b49612e11565b600c81905550611b57612e71565b600b81905550611bb233611b6a83613934565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166139c49092919063ffffffff16565b8b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167ff3fa0eaee8f258c23b013654df25d1527f98a5c7ccd5e951dd77caca400ef9728d84604051808381526020018281526020019250505060405180910390a36001995050505050505050505092915050565b60135481565b60145481565b60196020528060005260406000206000915090505481565b6000611c60612e71565b905090565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b6000803383604051602001808373ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040516020818303038152906040528051906020012090503373ffffffffffffffffffffffffffffffffffffffff166017600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611e0d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313100000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6017600082815260200190815260200160002060000160149054906101000a900460ff1615611ea4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313200000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600060176000838152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900460ff1615151515815260200160018201548152602001600282015481526020016003820154815260200160048201548152602001600582015481526020016006820154815250509050600080611f8083613948565b915091508260a001514311611ffd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313300000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600081831161201e57612019838361293f90919063ffffffff16565b612032565b612031828461293f90919063ffffffff16565b5b9050600084608001519050600080858511156120a1576120568488608001516139ab565b935061206f84886080015161293f90919063ffffffff16565b915061209a8461208c858a60600151612ad190919063ffffffff16565b612ad190919063ffffffff16565b9050612124565b85851015612102576120b78488606001516139ab565b93506120d0848860800151612ad190919063ffffffff16565b91506120fb846120ed858a60600151612ad190919063ffffffff16565b61293f90919063ffffffff16565b9050612123565b86608001519150612120838860600151612ad190919063ffffffff16565b90505b5b61213d876080015160085461293f90919063ffffffff16565b60088190555061215c876060015160065461293f90919063ffffffff16565b6006819055506121778360075461293f90919063ffffffff16565b60078190555061219282600954612ad190919063ffffffff16565b6009819055506001601760008a815260200190815260200160002060000160146101000a81548160ff0219169083151502179055506121cf612e11565b600c819055506121dd612e71565b600b81905550612238336121f083613934565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166139c49092919063ffffffff16565b3373ffffffffffffffffffffffffffffffffffffffff167f23723065e08b5ed8daf98778977a2e34c11a7d04208b2f12d629329d0a421a84886040015188888b60e001516040518085815260200184815260200183815260200182815260200194505050505060405180910390a2600198505050505050505050919050565b60006122c4848484613a66565b90509392505050565b600c5481565b60176020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060000160149054906101000a900460ff16908060010154908060020154908060030154908060040154908060050154908060060154905088565b60008082116123bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260018152602001807f390000000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60006123ca83613450565b90506000806123d883613bad565b91509150600954811115612454576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313000000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60008190506000600b549050600061248a6103e861247c6003886129c290919063ffffffff16565b612a4890919063ffffffff16565b90506000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d6feb980600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561253957600080fd5b505afa15801561254d573d6000803e3d6000fd5b505050506040513d602081101561256357600080fd5b8101908080519060200190929190505050905060006040518061010001604052803373ffffffffffffffffffffffffffffffffffffffff168152602001600015158152602001898152602001888152602001878152602001438152602001838152602001858152509050600033601860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054604051602001808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050604051602081830303815290604052805190602001209050816017600083815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548160ff02191690831515021790555060408201518160010155606082015181600201556080820151816003015560a0820151816004015560c0820151816005015560e082015181600601559050506127626001601860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612ad190919063ffffffff16565b601860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506127ba87600854612ad190919063ffffffff16565b6008819055506127d588600654612ad190919063ffffffff16565b6006819055506127f086600754612ad190919063ffffffff16565b60078190555061280b8760095461293f90919063ffffffff16565b60098190555061282684600a54612ad190919063ffffffff16565b600a81905550600061285387612845878c612ad190919063ffffffff16565b612ad190919063ffffffff16565b905061285d612e11565b600c8190555061286b612e71565b600b819055506128c8333061287f84613934565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16612d50909392919063ffffffff16565b3373ffffffffffffffffffffffffffffffffffffffff167f1328235872d7c5c1d43227eadd2c10c1514932b9de248bc5f6c7a225288560768b8a8960405180848152602001838152602001828152602001935050505060405180910390a260019a5050505050505050505050919050565b60075481565b6000828211156129b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525060200191505060405180910390fd5b818303905092915050565b6000808314156129d55760009050612a42565b60008284029050828482816129e657fe5b0414612a3d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806145236021913960400191505060405180910390fd5b809150505b92915050565b6000808211612abf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525060200191505060405180910390fd5b818381612ac857fe5b04905092915050565b600080828401905083811015612b4f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415612bdf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602d8152602001806143f2602d913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415612c65576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180614598602b913960400191505060405180910390fd5b80600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a3505050565b612e0b846323b872dd60e01b858585604051602401808473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613c18565b50505050565b600080612e2b600954600854612ad190919063ffffffff16565b90506000612e5e82612e50670de0b6b3a76400006008546129c290919063ffffffff16565b612a4890919063ffffffff16565b9050600060648202905080935050505090565b600080600080600e541415612ecc57612ec5601254612eb7670de0b6b3a7640000612ea9601354600c546129c290919063ffffffff16565b612a4890919063ffffffff16565b612ad190919063ffffffff16565b9050612f04565b612efd670de0b6b3a7640000612eef601354600c546129c290919063ffffffff16565b612a4890919063ffffffff16565b6012540390505b601454600c541015612f255760008113612f1d57600080fd5b809150612f84565b6000612f6c670de0b6b3a7640000612f5e612f4d601454600c5461293f90919063ffffffff16565b6015546129c290919063ffffffff16565b612a4890919063ffffffff16565b9050600081830113612f7d57600080fd5b8082019250505b612f98606483612a4890919063ffffffff16565b9250505090565b6000612faa826114cf565b905060008111613022576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f494e53554646494349454e545f4c49515549444954595f4255524e454400000081525060200191505060405180910390fd5b61302c3083613d07565b6130818361303983613934565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166139c49092919063ffffffff16565b8273ffffffffffffffffffffffffffffffffffffffff167f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f8284604051808381526020018281526020019250505060405180910390a2505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415613162576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e815260200180614450602e913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156131e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c8152602001806144f7602c913960400191505060405180910390fd5b613254816040518060600160405280602f81526020016143c3602f9139600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546133969092919063ffffffff16565b600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506132e981600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612ad190919063ffffffff16565b600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b6000838311158290613443576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156134085780820151818401526020810190506133ed565b50505050905090810190601f1680156134355780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5082840390509392505050565b600061345d826001613ec1565b9050919050565b600061346e61102d565b9050600080821415613482578290506135bb565b6000613550600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561351057600080fd5b505afa158015613524573d6000803e3d6000fd5b505050506040513d602081101561353a57600080fd5b8101908080519060200190929190505050613450565b9050600061358f856135816007546135736006548761293f90919063ffffffff16565b61293f90919063ffffffff16565b61293f90919063ffffffff16565b90506135b6816135a886886129c290919063ffffffff16565b612a4890919063ffffffff16565b925050505b60008111613631576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f494e53554646494349454e545f4c49515549444954595f4d494e54454400000081525060200191505060405180910390fd5b61363b8482613f1f565b8373ffffffffffffffffffffffffffffffffffffffff167f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f8483604051808381526020018281526020019250505060405180910390a250505050565b600080600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d71275f6600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561374557600080fd5b505afa158015613759573d6000803e3d6000fd5b505050506040513d602081101561376f57600080fd5b8101908080519060200190929190505050905060006137b360646137a5670de0b6b3a7640000600a6129c290919063ffffffff16565b612a4890919063ffffffff16565b90506137c88183612ad190919063ffffffff16565b9250505090565b600080600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d6feb980600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561387d57600080fd5b505afa158015613891573d6000803e3d6000fd5b505050506040513d60208110156138a757600080fd5b8101908080519060200190929190505050905060006138e9846138db670de0b6b3a7640000856129c290919063ffffffff16565b612a4890919063ffffffff16565b905061392a8561391c670de0b6b3a764000061390e858a6129c290919063ffffffff16565b612a4890919063ffffffff16565b61293f90919063ffffffff16565b9250505092915050565b6000613941826000613ec1565b9050919050565b600080600080600061396786604001518760e001518860a00151613a66565b9050600061397d87604001518860c001516137cf565b90506000600e5414156139955781935080925061399c565b8093508192505b83839550955050505050915091565b60008183106139ba57816139bc565b825b905092915050565b613a618363a9059cbb60e01b8484604051602401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613c18565b505050565b600080613a9a610168613a8c670de0b6b3a7640000600f546129c290919063ffffffff16565b612a4890919063ffffffff16565b90506000613af7670de0b6b3a7640000613ae984613adb670de0b6b3a7640000613acd8b8d6129c290919063ffffffff16565b612a4890919063ffffffff16565b6129c290919063ffffffff16565b612a4890919063ffffffff16565b90506000613b0e854361293f90919063ffffffff16565b90506000613b296119aa600f546129c290919063ffffffff16565b90506000818310613b4257670de0b6b3a7640000613b70565b613b6f82613b61670de0b6b3a7640000866129c290919063ffffffff16565b612a4890919063ffffffff16565b5b9050613b9f670de0b6b3a7640000613b9183876129c290919063ffffffff16565b612a4890919063ffffffff16565b955050505050509392505050565b600080600080600e5414613bc857613bc3613697565b613bcc565b600b545b905060006001600e5414613be757613be2613697565b613beb565b600b545b90506000613bf986846140bf565b90506000613c0787846140bf565b905081819550955050505050915091565b6000613c7a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166141239092919063ffffffff16565b9050600081511115613d0257808060200190516020811015613c9b57600080fd5b8101908080519060200190929190505050613d01576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a81526020018061456e602a913960400191505060405180910390fd5b5b505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415613d8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a815260200180614544602a913960400191505060405180910390fd5b613df9816040518060600160405280602b81526020016144a6602b9139600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546133969092919063ffffffff16565b600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550613e518160005461293f90919063ffffffff16565b600081905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b60008060126010541015613f115782613ef157613eec601154600a0a85612a4890919063ffffffff16565b613f0a565b613f09601154600a0a856129c290919063ffffffff16565b5b9050613f15565b8390505b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415613fa5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061447e6028913960400191505060405180910390fd5b613fba81600054612ad190919063ffffffff16565b60008190555061401281600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612ad190919063ffffffff16565b600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b6000806140d9600f54610168612a4890919063ffffffff16565b905061411a8161410c670de0b6b3a76400006140fe87896129c290919063ffffffff16565b612a4890919063ffffffff16565b612a4890919063ffffffff16565b91505092915050565b6060614132848460008561413b565b90509392505050565b606082471015614196576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806144d16026913960400191505060405180910390fd5b61419f856142e3565b614211576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000081525060200191505060405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040518082805190602001908083835b60208310614260578051825260208201915060208101905060208303925061423d565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d80600081146142c2576040519150601f19603f3d011682016040523d82523d6000602084013e6142c7565b606091505b50915091506142d78282866142f6565b92505050949350505050565b600080823b905060008111915050919050565b60608315614306578290506143bb565b6000835111156143195782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015614380578082015181840152602081019050614365565b50505050905090810190601f1680156143ad5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b939250505056fe477265656e776f6f6445524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e6365477265656e776f6f6445524332303a20617070726f76652066726f6d20746865207a65726f2061646472657373477265656e776f6f6445524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365477265656e776f6f6445524332303a207472616e736665722066726f6d20746865207a65726f2061646472657373477265656e776f6f6445524332303a206d696e7420746f20746865207a65726f2061646472657373477265656e776f6f6445524332303a206275726e20616d6f756e7420657863656564732062616c616e6365416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c477265656e776f6f6445524332303a207472616e7366657220746f20746865207a65726f2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77477265656e776f6f6445524332303a206275726e2066726f6d20746865207a65726f20616464726573735361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564477265656e776f6f6445524332303a20617070726f766520746f20746865207a65726f2061646472657373a2646970667358221220a296b8d7a92001e6cb1edd19c222cdc3cf016bdb6cd95e1fa6dbbb7bd010b4ea64736f6c63430007060033477265656e776f6f6445524332303a206d696e7420746f20746865207a65726f2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000006000000000000000000000000888d6a7ab9a8a6cbe884f6e7e90adf1e24d247c300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000004563918244f400000000000000000000000000000000000000000000000000000c249fdd3277800000000000000000000000000000000000000000000000000004563918244f40000000000000000000000000000000000000000000000000000c0e6b85ac9ee0000000000000000000000000000bf469ba05900e3c50a7aed5074da5353bca79199

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061025e5760003560e01c80638064a05911610146578063c11eaae2116100c3578063e43c520d11610087578063e43c520d14610a69578063e588b50514610aad578063ea21cd9214610b03578063eb84e7f214610b21578063f3eb4f8a14610bac578063fa7e8d0114610bf05761025e565b8063c11eaae21461093f578063ce3f28f01461095d578063ce7539011461097b578063d14ab67d146109d3578063dd62ed3e146109f15761025e565b8063a9059cbb1161010a578063a9059cbb146107bf578063b2485f9714610823578063b63c44e714610865578063b6984be914610883578063bcbaf487146108db5761025e565b80638064a059146106705780638ce744261461069e5780638d7aeae5146106bc57806391cfad5a1461070857806395d89b411461073c5761025e565b8063330691ac116101df578063645539ed116101a3578063645539ed1461055c57806370a082311461057a578063735d80e3146105d257806376d58e1a146105f05780637b83002914610634578063802d1422146106525761025e565b8063330691ac146104c6578063356cd90a146104e45780633fc896a21461050257806354b6ba951461052057806361e08e721461053e5761025e565b806318160ddd1161022657806318160ddd146103ca57806323b872dd146103e857806327b380ea1461046c578063294164531461048a578063313ce567146104a85761025e565b806306fdde0314610263578063095ea7b3146102e65780630a2a8e781461034a5780630a861f2a1461036857806313114a9d146103ac575b600080fd5b61026b610c0e565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102ab578082015181840152602081019050610290565b50505050905090810190601f1680156102d85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610332600480360360408110156102fc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610c47565b60405180821515815260200191505060405180910390f35b610352610c5e565b6040518082815260200191505060405180910390f35b6103946004803603602081101561037e57600080fd5b8101908080359060200190929190505050610d4b565b60405180821515815260200191505060405180910390f35b6103b4611027565b6040518082815260200191505060405180910390f35b6103d261102d565b6040518082815260200191505060405180910390f35b610454600480360360608110156103fe57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611036565b60405180821515815260200191505060405180910390f35b610474611101565b6040518082815260200191505060405180910390f35b610492611107565b6040518082815260200191505060405180910390f35b6104b061110d565b6040518082815260200191505060405180910390f35b6104ce611112565b6040518082815260200191505060405180910390f35b6104ec611118565b6040518082815260200191505060405180910390f35b61050a61111e565b6040518082815260200191505060405180910390f35b610528611124565b6040518082815260200191505060405180910390f35b61054661112a565b6040518082815260200191505060405180910390f35b610564611130565b6040518082815260200191505060405180910390f35b6105bc6004803603602081101561059057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611136565b6040518082815260200191505060405180910390f35b6105da61117f565b6040518082815260200191505060405180910390f35b61061c6004803603602081101561060657600080fd5b8101908080359060200190929190505050611185565b60405180821515815260200191505060405180910390f35b61063c61136b565b6040518082815260200191505060405180910390f35b61065a61137a565b6040518082815260200191505060405180910390f35b61069c6004803603602081101561068657600080fd5b8101908080359060200190929190505050611380565b005b6106a661143f565b6040518082815260200191505060405180910390f35b6106f2600480360360408110156106d257600080fd5b810190808035906020019092919080359060200190929190505050611445565b6040518082815260200191505060405180910390f35b610710611459565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61074461147f565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610784578082015181840152602081019050610769565b50505050905090810190601f1680156107b15780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61080b600480360360408110156107d557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506114b8565b60405180821515815260200191505060405180910390f35b61084f6004803603602081101561083957600080fd5b81019080803590602001909291905050506114cf565b6040518082815260200191505060405180910390f35b61086d611602565b6040518082815260200191505060405180910390f35b6108c56004803603602081101561089957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611608565b6040518082815260200191505060405180910390f35b610927600480360360408110156108f157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611620565b60405180821515815260200191505060405180910390f35b610947611c32565b6040518082815260200191505060405180910390f35b610965611c38565b6040518082815260200191505060405180910390f35b6109bd6004803603602081101561099157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611c3e565b6040518082815260200191505060405180910390f35b6109db611c56565b6040518082815260200191505060405180910390f35b610a5360048036036040811015610a0757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611c65565b6040518082815260200191505060405180910390f35b610a9560048036036020811015610a7f57600080fd5b8101908080359060200190929190505050611cec565b60405180821515815260200191505060405180910390f35b610aed60048036036060811015610ac357600080fd5b810190808035906020019092919080359060200190929190803590602001909291905050506122b7565b6040518082815260200191505060405180910390f35b610b0b6122cd565b6040518082815260200191505060405180910390f35b610b4d60048036036020811015610b3757600080fd5b81019080803590602001909291905050506122d3565b604051808973ffffffffffffffffffffffffffffffffffffffff16815260200188151581526020018781526020018681526020018581526020018481526020018381526020018281526020019850505050505050505060405180910390f35b610bd860048036036020811015610bc257600080fd5b8101908080359060200190929190505050612348565b60405180821515815260200191505060405180910390f35b610bf8612939565b6040518082815260200191505060405180910390f35b6040518060400160405280600981526020017f477265656e776f6f64000000000000000000000000000000000000000000000081525081565b6000610c54338484612b59565b6001905092915050565b6000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d71275f6600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015610d0b57600080fd5b505afa158015610d1f573d6000803e3d6000fd5b505050506040513d6020811015610d3557600080fd5b8101908080519060200190929190505050905090565b600043601960003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410610e01576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313900000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60008211610e77576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313400000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b610ea43330843073ffffffffffffffffffffffffffffffffffffffff16612d50909392919063ffffffff16565b6000610eaf836114cf565b9050806009541015610f29576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313000000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6000610f68610f45600954600854612ad190919063ffffffff16565b610f5a84600a546129c290919063ffffffff16565b612a4890919063ffffffff16565b9050610f7f81600a5461293f90919063ffffffff16565b600a81905550610f9a8260095461293f90919063ffffffff16565b600981905550610fa8612e11565b600c81905550610fb6612e71565b600b81905550610fc63385612f9f565b3373ffffffffffffffffffffffffffffffffffffffff167fac927268ea9ae2e55027e6ab727fc2db8e3ea48c56c658223a1074567e4298c08583604051808381526020018281526020019250505060405180910390a2600192505050919050565b600a5481565b60008054905090565b60006110438484846130dc565b6110f684336110f18560405180606001604052806031815260200161441f60319139600260008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546133969092919063ffffffff16565b612b59565b600190509392505050565b60085481565b60065481565b601281565b60155481565b60105481565b60115481565b600f5481565b60125481565b600e5481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60095481565b60008061119183613450565b90506000811180156111cd57506016546111ca6009546111bc60085485612ad190919063ffffffff16565b612ad190919063ffffffff16565b11155b61123f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313400000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b61128e333085600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16612d50909392919063ffffffff16565b6112a381600954612ad190919063ffffffff16565b60098190555043601960003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506112f5612e11565b600c81905550611303612e71565b600b819055506113133382613464565b3373ffffffffffffffffffffffffffffffffffffffff167f3bdb4d376f46aac1bdcda94b03200364052b278ed93865d759bf61452bfabdba826040518082815260200191505060405180910390a26001915050919050565b6000611375613697565b905090565b600b5481565b73e3d5260cd7f8a4207f41c3b2ac87882489f9721373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611435576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313800000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8060168190555050565b600d5481565b600061145183836137cf565b905092915050565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6040518060400160405280600381526020017f47524e000000000000000000000000000000000000000000000000000000000081525081565b60006114c53384846130dc565b6001905092915050565b6000806115c66007546115b86006546115aa600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561156a57600080fd5b505afa15801561157e573d6000803e3d6000fd5b505050506040513d602081101561159457600080fd5b8101908080519060200190929190505050613450565b61293f90919063ffffffff16565b61293f90919063ffffffff16565b905060006115d261102d565b90506115f9816115eb84876129c290919063ffffffff16565b612a4890919063ffffffff16565b92505050919050565b60165481565b60186020528060005260406000206000915090505481565b6000808383604051602001808373ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040516020818303038152906040528051906020012090508373ffffffffffffffffffffffffffffffffffffffff166017600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611741576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313100000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600060176000838152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900460ff1615151515815260200160018201548152602001600282015481526020016003820154815260200160048201548152602001600582015481526020016006820154815250509050806020015115611889576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313200000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60006118b86118a56119aa600f546129c290919063ffffffff16565b8360a00151612ad190919063ffffffff16565b905080431015611930576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313700000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b61198b33306119428560800151613934565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16612d50909392919063ffffffff16565b60008061199784613948565b9150915060008183116119bc576119b7838361293f90919063ffffffff16565b6119d0565b6119cf828461293f90919063ffffffff16565b5b905060008560800151905060008085851115611a3f576119f48489608001516139ab565b9350611a0d848960800151612ad190919063ffffffff16565b9150611a3884611a2a8a6060015186612ad190919063ffffffff16565b61293f90919063ffffffff16565b9050611a9e565b85851015611a7c57611a558489606001516139ab565b9350611a7288606001518960800151612ad190919063ffffffff16565b9150829050611a9d565b87608001519150611a9a886060015184612ad190919063ffffffff16565b90505b5b611ab7886080015160085461293f90919063ffffffff16565b600881905550611ad6886060015160065461293f90919063ffffffff16565b600681905550611af18360075461293f90919063ffffffff16565b600781905550611b0c82600954612ad190919063ffffffff16565b6009819055506001601760008b815260200190815260200160002060000160146101000a81548160ff021916908315150217905550611b49612e11565b600c81905550611b57612e71565b600b81905550611bb233611b6a83613934565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166139c49092919063ffffffff16565b8b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167ff3fa0eaee8f258c23b013654df25d1527f98a5c7ccd5e951dd77caca400ef9728d84604051808381526020018281526020019250505060405180910390a36001995050505050505050505092915050565b60135481565b60145481565b60196020528060005260406000206000915090505481565b6000611c60612e71565b905090565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b6000803383604051602001808373ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040516020818303038152906040528051906020012090503373ffffffffffffffffffffffffffffffffffffffff166017600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611e0d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313100000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6017600082815260200190815260200160002060000160149054906101000a900460ff1615611ea4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313200000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600060176000838152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900460ff1615151515815260200160018201548152602001600282015481526020016003820154815260200160048201548152602001600582015481526020016006820154815250509050600080611f8083613948565b915091508260a001514311611ffd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313300000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600081831161201e57612019838361293f90919063ffffffff16565b612032565b612031828461293f90919063ffffffff16565b5b9050600084608001519050600080858511156120a1576120568488608001516139ab565b935061206f84886080015161293f90919063ffffffff16565b915061209a8461208c858a60600151612ad190919063ffffffff16565b612ad190919063ffffffff16565b9050612124565b85851015612102576120b78488606001516139ab565b93506120d0848860800151612ad190919063ffffffff16565b91506120fb846120ed858a60600151612ad190919063ffffffff16565b61293f90919063ffffffff16565b9050612123565b86608001519150612120838860600151612ad190919063ffffffff16565b90505b5b61213d876080015160085461293f90919063ffffffff16565b60088190555061215c876060015160065461293f90919063ffffffff16565b6006819055506121778360075461293f90919063ffffffff16565b60078190555061219282600954612ad190919063ffffffff16565b6009819055506001601760008a815260200190815260200160002060000160146101000a81548160ff0219169083151502179055506121cf612e11565b600c819055506121dd612e71565b600b81905550612238336121f083613934565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166139c49092919063ffffffff16565b3373ffffffffffffffffffffffffffffffffffffffff167f23723065e08b5ed8daf98778977a2e34c11a7d04208b2f12d629329d0a421a84886040015188888b60e001516040518085815260200184815260200183815260200182815260200194505050505060405180910390a2600198505050505050505050919050565b60006122c4848484613a66565b90509392505050565b600c5481565b60176020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060000160149054906101000a900460ff16908060010154908060020154908060030154908060040154908060050154908060060154905088565b60008082116123bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260018152602001807f390000000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60006123ca83613450565b90506000806123d883613bad565b91509150600954811115612454576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260028152602001807f313000000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60008190506000600b549050600061248a6103e861247c6003886129c290919063ffffffff16565b612a4890919063ffffffff16565b90506000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d6feb980600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561253957600080fd5b505afa15801561254d573d6000803e3d6000fd5b505050506040513d602081101561256357600080fd5b8101908080519060200190929190505050905060006040518061010001604052803373ffffffffffffffffffffffffffffffffffffffff168152602001600015158152602001898152602001888152602001878152602001438152602001838152602001858152509050600033601860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054604051602001808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050604051602081830303815290604052805190602001209050816017600083815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548160ff02191690831515021790555060408201518160010155606082015181600201556080820151816003015560a0820151816004015560c0820151816005015560e082015181600601559050506127626001601860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612ad190919063ffffffff16565b601860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506127ba87600854612ad190919063ffffffff16565b6008819055506127d588600654612ad190919063ffffffff16565b6006819055506127f086600754612ad190919063ffffffff16565b60078190555061280b8760095461293f90919063ffffffff16565b60098190555061282684600a54612ad190919063ffffffff16565b600a81905550600061285387612845878c612ad190919063ffffffff16565b612ad190919063ffffffff16565b905061285d612e11565b600c8190555061286b612e71565b600b819055506128c8333061287f84613934565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16612d50909392919063ffffffff16565b3373ffffffffffffffffffffffffffffffffffffffff167f1328235872d7c5c1d43227eadd2c10c1514932b9de248bc5f6c7a225288560768b8a8960405180848152602001838152602001828152602001935050505060405180910390a260019a5050505050505050505050919050565b60075481565b6000828211156129b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525060200191505060405180910390fd5b818303905092915050565b6000808314156129d55760009050612a42565b60008284029050828482816129e657fe5b0414612a3d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806145236021913960400191505060405180910390fd5b809150505b92915050565b6000808211612abf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525060200191505060405180910390fd5b818381612ac857fe5b04905092915050565b600080828401905083811015612b4f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415612bdf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602d8152602001806143f2602d913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415612c65576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180614598602b913960400191505060405180910390fd5b80600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a3505050565b612e0b846323b872dd60e01b858585604051602401808473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613c18565b50505050565b600080612e2b600954600854612ad190919063ffffffff16565b90506000612e5e82612e50670de0b6b3a76400006008546129c290919063ffffffff16565b612a4890919063ffffffff16565b9050600060648202905080935050505090565b600080600080600e541415612ecc57612ec5601254612eb7670de0b6b3a7640000612ea9601354600c546129c290919063ffffffff16565b612a4890919063ffffffff16565b612ad190919063ffffffff16565b9050612f04565b612efd670de0b6b3a7640000612eef601354600c546129c290919063ffffffff16565b612a4890919063ffffffff16565b6012540390505b601454600c541015612f255760008113612f1d57600080fd5b809150612f84565b6000612f6c670de0b6b3a7640000612f5e612f4d601454600c5461293f90919063ffffffff16565b6015546129c290919063ffffffff16565b612a4890919063ffffffff16565b9050600081830113612f7d57600080fd5b8082019250505b612f98606483612a4890919063ffffffff16565b9250505090565b6000612faa826114cf565b905060008111613022576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f494e53554646494349454e545f4c49515549444954595f4255524e454400000081525060200191505060405180910390fd5b61302c3083613d07565b6130818361303983613934565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166139c49092919063ffffffff16565b8273ffffffffffffffffffffffffffffffffffffffff167f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f8284604051808381526020018281526020019250505060405180910390a2505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415613162576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e815260200180614450602e913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156131e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c8152602001806144f7602c913960400191505060405180910390fd5b613254816040518060600160405280602f81526020016143c3602f9139600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546133969092919063ffffffff16565b600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506132e981600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612ad190919063ffffffff16565b600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b6000838311158290613443576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156134085780820151818401526020810190506133ed565b50505050905090810190601f1680156134355780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5082840390509392505050565b600061345d826001613ec1565b9050919050565b600061346e61102d565b9050600080821415613482578290506135bb565b6000613550600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561351057600080fd5b505afa158015613524573d6000803e3d6000fd5b505050506040513d602081101561353a57600080fd5b8101908080519060200190929190505050613450565b9050600061358f856135816007546135736006548761293f90919063ffffffff16565b61293f90919063ffffffff16565b61293f90919063ffffffff16565b90506135b6816135a886886129c290919063ffffffff16565b612a4890919063ffffffff16565b925050505b60008111613631576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f494e53554646494349454e545f4c49515549444954595f4d494e54454400000081525060200191505060405180910390fd5b61363b8482613f1f565b8373ffffffffffffffffffffffffffffffffffffffff167f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f8483604051808381526020018281526020019250505060405180910390a250505050565b600080600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d71275f6600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561374557600080fd5b505afa158015613759573d6000803e3d6000fd5b505050506040513d602081101561376f57600080fd5b8101908080519060200190929190505050905060006137b360646137a5670de0b6b3a7640000600a6129c290919063ffffffff16565b612a4890919063ffffffff16565b90506137c88183612ad190919063ffffffff16565b9250505090565b600080600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d6feb980600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561387d57600080fd5b505afa158015613891573d6000803e3d6000fd5b505050506040513d60208110156138a757600080fd5b8101908080519060200190929190505050905060006138e9846138db670de0b6b3a7640000856129c290919063ffffffff16565b612a4890919063ffffffff16565b905061392a8561391c670de0b6b3a764000061390e858a6129c290919063ffffffff16565b612a4890919063ffffffff16565b61293f90919063ffffffff16565b9250505092915050565b6000613941826000613ec1565b9050919050565b600080600080600061396786604001518760e001518860a00151613a66565b9050600061397d87604001518860c001516137cf565b90506000600e5414156139955781935080925061399c565b8093508192505b83839550955050505050915091565b60008183106139ba57816139bc565b825b905092915050565b613a618363a9059cbb60e01b8484604051602401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613c18565b505050565b600080613a9a610168613a8c670de0b6b3a7640000600f546129c290919063ffffffff16565b612a4890919063ffffffff16565b90506000613af7670de0b6b3a7640000613ae984613adb670de0b6b3a7640000613acd8b8d6129c290919063ffffffff16565b612a4890919063ffffffff16565b6129c290919063ffffffff16565b612a4890919063ffffffff16565b90506000613b0e854361293f90919063ffffffff16565b90506000613b296119aa600f546129c290919063ffffffff16565b90506000818310613b4257670de0b6b3a7640000613b70565b613b6f82613b61670de0b6b3a7640000866129c290919063ffffffff16565b612a4890919063ffffffff16565b5b9050613b9f670de0b6b3a7640000613b9183876129c290919063ffffffff16565b612a4890919063ffffffff16565b955050505050509392505050565b600080600080600e5414613bc857613bc3613697565b613bcc565b600b545b905060006001600e5414613be757613be2613697565b613beb565b600b545b90506000613bf986846140bf565b90506000613c0787846140bf565b905081819550955050505050915091565b6000613c7a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166141239092919063ffffffff16565b9050600081511115613d0257808060200190516020811015613c9b57600080fd5b8101908080519060200190929190505050613d01576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a81526020018061456e602a913960400191505060405180910390fd5b5b505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415613d8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a815260200180614544602a913960400191505060405180910390fd5b613df9816040518060600160405280602b81526020016144a6602b9139600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546133969092919063ffffffff16565b600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550613e518160005461293f90919063ffffffff16565b600081905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b60008060126010541015613f115782613ef157613eec601154600a0a85612a4890919063ffffffff16565b613f0a565b613f09601154600a0a856129c290919063ffffffff16565b5b9050613f15565b8390505b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415613fa5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061447e6028913960400191505060405180910390fd5b613fba81600054612ad190919063ffffffff16565b60008190555061401281600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612ad190919063ffffffff16565b600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b6000806140d9600f54610168612a4890919063ffffffff16565b905061411a8161410c670de0b6b3a76400006140fe87896129c290919063ffffffff16565b612a4890919063ffffffff16565b612a4890919063ffffffff16565b91505092915050565b6060614132848460008561413b565b90509392505050565b606082471015614196576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806144d16026913960400191505060405180910390fd5b61419f856142e3565b614211576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000081525060200191505060405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040518082805190602001908083835b60208310614260578051825260208201915060208101905060208303925061423d565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d80600081146142c2576040519150601f19603f3d011682016040523d82523d6000602084013e6142c7565b606091505b50915091506142d78282866142f6565b92505050949350505050565b600080823b905060008111915050919050565b60608315614306578290506143bb565b6000835111156143195782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015614380578082015181840152602081019050614365565b50505050905090810190601f1680156143ad5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b939250505056fe477265656e776f6f6445524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e6365477265656e776f6f6445524332303a20617070726f76652066726f6d20746865207a65726f2061646472657373477265656e776f6f6445524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365477265656e776f6f6445524332303a207472616e736665722066726f6d20746865207a65726f2061646472657373477265656e776f6f6445524332303a206d696e7420746f20746865207a65726f2061646472657373477265656e776f6f6445524332303a206275726e20616d6f756e7420657863656564732062616c616e6365416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c477265656e776f6f6445524332303a207472616e7366657220746f20746865207a65726f2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77477265656e776f6f6445524332303a206275726e2066726f6d20746865207a65726f20616464726573735361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564477265656e776f6f6445524332303a20617070726f766520746f20746865207a65726f2061646472657373a2646970667358221220a296b8d7a92001e6cb1edd19c222cdc3cf016bdb6cd95e1fa6dbbb7bd010b4ea64736f6c63430007060033

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

000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000006000000000000000000000000888d6a7ab9a8a6cbe884f6e7e90adf1e24d247c300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000004563918244f400000000000000000000000000000000000000000000000000000c249fdd3277800000000000000000000000000000000000000000000000000004563918244f40000000000000000000000000000000000000000000000000000c0e6b85ac9ee0000000000000000000000000000bf469ba05900e3c50a7aed5074da5353bca79199

-----Decoded View---------------
Arg [0] : _underlier (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [1] : _underlierDecimals (uint256): 6
Arg [2] : _adapter (address): 0x888D6A7Ab9a8a6CbE884F6e7E90ADF1E24d247c3
Arg [3] : _protocol (uint256): 0
Arg [4] : _direction (uint256): 1
Arg [5] : _durationInDays (uint256): 5
Arg [6] : _initialDeposit (uint256): 1000000
Arg [7] : _rateLimit (uint256): 80000000000000000000
Arg [8] : _rateSensitivity (uint256): 14000000000000000000
Arg [9] : _utilizationInflection (uint256): 5000000000000000000
Arg [10] : _rateMultiplier (uint256): 13900000000000000000
Arg [11] : _poolDeployer (address): 0xbF469Ba05900e3C50a7AED5074Da5353BCa79199

-----Encoded View---------------
12 Constructor Arguments found :
Arg [0] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [2] : 000000000000000000000000888d6a7ab9a8a6cbe884f6e7e90adf1e24d247c3
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [6] : 00000000000000000000000000000000000000000000000000000000000f4240
Arg [7] : 000000000000000000000000000000000000000000000004563918244f400000
Arg [8] : 000000000000000000000000000000000000000000000000c249fdd327780000
Arg [9] : 0000000000000000000000000000000000000000000000004563918244f40000
Arg [10] : 000000000000000000000000000000000000000000000000c0e6b85ac9ee0000
Arg [11] : 000000000000000000000000bf469ba05900e3c50a7aed5074da5353bca79199


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.