ETH Price: $3,634.48 (+0.15%)

Contract

0x764dfB496a8b2847a9136346a20888Cfd62d55ba

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Amount:Between 1-10k
Reset Filter

Transaction Hash
Method
Block
From
To

There are no matching entries

> 10 Token Transfers found.

Parent Transaction Hash Block From To
View All Internal Transactions

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Liquidator

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: GPL-v3
pragma solidity 0.8.21;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@gammaswap/v1-core/contracts/interfaces/IPoolViewer.sol";
import "@gammaswap/v1-core/contracts/libraries/GSMath.sol";
import "./interfaces/ILiquidator.sol";

/// @title Liquidator Smart Contract
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @dev Helps liquidation of loans in GammaPools
contract Liquidator is ILiquidator {

    constructor(){
    }

    /// @dev See {ILiquidator-canLiquidate}.
    function canLiquidate(address pool, uint256 tokenId) external override view returns(uint256 liquidity, uint256 collateral) {
        return _canLiquidate(pool, tokenId);
    }

    function _canLiquidate(address pool, uint256 tokenId) internal virtual view returns(uint256 liquidity, uint256 collateral) {
        IPoolViewer viewer = IPoolViewer(IGammaPool(pool).viewer());
        if(viewer.canLiquidate(pool, tokenId)) {
            IGammaPool.LoanData memory loan = viewer.loan(pool, tokenId);
            liquidity = loan.liquidity;
            collateral = GSMath.sqrt(uint256(loan.tokensHeld[0])*loan.tokensHeld[1]);
        }
    }

    /// @dev See {ILiquidator-canBatchLiquidate}.
    function canBatchLiquidate(address pool, uint256[] calldata tokenIds) external override virtual view returns(uint256[] memory _tokenIds, uint256 _liquidity, uint256 _collateral) {
        return _canBatchLiquidate(pool, tokenIds);
    }

    function _canBatchLiquidate(address pool, uint256[] calldata tokenIds) internal virtual view returns(uint256[] memory _tokenIds, uint256 _liquidity, uint256 _collateral) {
        IGammaPool.LoanData[] memory _loans = IPoolViewer(IGammaPool(pool).viewer()).getLoansById(pool, tokenIds, true);
        uint256[] memory __tokenIds = new uint256[](_loans.length);
        uint256 k = 0;
        IGammaPool.LoanData memory _loan;
        for(uint256 i = 0; i < _loans.length;) {
            _loan = _loans[i];
            if(_loan.id > 0) {
                if(_loan.canLiquidate) {
                    __tokenIds[k] = _loan.tokenId;
                    _liquidity += _loan.liquidity;
                    _collateral += GSMath.sqrt(uint256(_loan.tokensHeld[0]) * _loan.tokensHeld[1]);
                    unchecked {
                        ++k;
                    }
                }
            } else {
                break;
            }
            unchecked {
                ++i;
            }
        }
        _tokenIds = new uint256[](k);
        for(uint256 j = 0; j < _tokenIds.length;) {
            _tokenIds[j] = __tokenIds[j];
            unchecked {
                ++j;
            }
        }
    }

    /// @dev See {ILiquidator-liquidate}.
    function liquidate(address pool, uint256 tokenId, address to) external override virtual returns(uint256 refund) {
        IPoolViewer viewer = IPoolViewer(IGammaPool(pool).viewer());
        if(viewer.canLiquidate(pool, tokenId)) {
            address cfmm = IGammaPool(pool).cfmm();
            uint256 beforeBalance = IERC20(cfmm).balanceOf(address(this));
            (,refund) = IGammaPool(pool).liquidate(tokenId);
            uint256 afterBalance = IERC20(cfmm).balanceOf(address(this));
            if(afterBalance > beforeBalance) {
                IERC20(cfmm).transfer(to,afterBalance - beforeBalance);
            }
        }
    }

    /// @dev See {ILiquidator-calcLPTokenDebt}.
    function calcLPTokenDebt(address pool, uint256 tokenId) external override virtual view returns(uint256 lpTokens) {
        return _calcLPTokenDebt(pool, tokenId);
    }

    function _calcLPTokenDebt(address pool, uint256 tokenId) internal virtual view returns(uint256 lpTokens) {
        IGammaPool.LoanData memory _loan = IPoolViewer(IGammaPool(pool).viewer()).loan(pool, tokenId);
        lpTokens = _convertLiquidityToLPTokens(pool, _loan.liquidity);
    }

    /// @dev See {ILiquidator-liquidateWithLP}.
    function liquidateWithLP(address pool, uint256 tokenId, uint256 lpTokens, bool calcLpTokens, address to) external override virtual returns(uint256[] memory refunds) {
        //check can liquidate first
        IPoolViewer viewer = IPoolViewer(IGammaPool(pool).viewer());
        if(viewer.canLiquidate(pool, tokenId)){
            if(calcLpTokens) {
                lpTokens = _calcLPTokenDebt(pool, tokenId) * 10002 / 10000; // adding 0.02% to avoid rounding issues
            }
            // transfer CFMM LP Tokens
            address cfmm = IGammaPool(pool).cfmm();
            uint256 beforeBalance = IERC20(cfmm).balanceOf(address(this));
            _transferLPTokensFrom(pool, lpTokens, msg.sender);
            (,refunds) = IGammaPool(pool).liquidateWithLP(tokenId);
            uint256 afterBalance = IERC20(cfmm).balanceOf(address(this));
            _transferRefunds(pool, refunds, to);
            if(afterBalance > beforeBalance) {
                IERC20(cfmm).transfer(msg.sender,afterBalance - beforeBalance);
            }
        }
    }

    /// @dev See {ILiquidator-batchLiquidate}.
    function batchLiquidate(address pool, uint256[] calldata tokenIds, address to) external override virtual returns(uint256[] memory _tokenIds, uint256[] memory refunds) {
        //call canLiquidate first
        uint256 _liquidity;
        (_tokenIds, _liquidity,) = _canBatchLiquidate(pool, tokenIds);
        if(_liquidity > 0) {
            uint256 lpTokens = _convertLiquidityToLPTokens(pool, _liquidity) * 10002 / 10000;
            address cfmm = IGammaPool(pool).cfmm();
            uint256 beforeBalance = IERC20(cfmm).balanceOf(address(this));
            // transfer CFMM LP Tokens
            _transferLPTokensFrom(pool, lpTokens, msg.sender);
            (,refunds) = IGammaPool(pool).batchLiquidations(_tokenIds);
            uint256 afterBalance = IERC20(cfmm).balanceOf(address(this));
            _transferRefunds(pool, refunds, to);
            if(afterBalance > beforeBalance) {
                IERC20(cfmm).transfer(msg.sender,afterBalance - beforeBalance);
            }
        }
    }

    /// @dev See {ILiquidator-getLoan}.
    function getLoan(address pool, uint256 tokenId) external override virtual view returns(IGammaPool.LoanData memory loan) {
        loan = IPoolViewer(IGammaPool(pool).viewer()).loan(pool, tokenId);
    }

    /// @dev See {ILiquidator-getLoans}.
    function getLoans(address pool, uint256[] calldata tokenId, bool active) external override virtual view returns(IGammaPool.LoanData[] memory loans) {
        loans = IGammaPool(pool).getLoansById(tokenId, active);
    }

    /// @dev See {ILiquidator-getOpenLoans}.
    function getLoans(address pool, uint256 start, uint256 end, bool active) external override virtual view returns(IGammaPool.LoanData[] memory loans) {
        loans = IGammaPool(pool).getLoans(start, end, active);
    }

    /// @dev See {ILiquidator-getOpenLoanIds}.
    function getLoanIds(address pool, uint256 start, uint256 end, bool active) external override virtual view returns(uint256[] memory tokenIds) {
        IGammaPool.LoanData[] memory loans = IGammaPool(pool).getLoans(start, end, active);
        tokenIds = new uint256[](loans.length);
        for(uint256 i = 0; i < loans.length;) {
            tokenIds[i] = loans[i].tokenId;
            unchecked {
                ++i;
            }
        }
    }

    /// @dev convert liquidity invariant units to LP tokens
    /// @param pool - address of GammaPool for CFMM's liquidity
    /// @param liquidity - liquidity invariant units to convert into CFMM LP tokens
    /// @return lpTokens - CFMM LP tokens `liquidity` invariant units converts to
    function _convertLiquidityToLPTokens(address pool, uint256 liquidity) internal virtual view returns(uint256 lpTokens) {
        (, uint256 cfmmInvariant, uint256 cfmmTotalSupply) = IGammaPool(pool).getLatestCFMMBalances();
        lpTokens = liquidity * cfmmTotalSupply / cfmmInvariant;
    }

    /// @dev transfer refunded amounts to `to` address
    /// @param pool - refunded quantities of CFMM tokens
    /// @param refunds - refunded quantities of CFMM tokens
    /// @param to - address that will receive refunded quantities
    function _transferRefunds(address pool, uint256[] memory refunds, address to) internal virtual {
        address[] memory tokens = IGammaPool(pool).tokens();
        for(uint256 i = 0; i < refunds.length;) {
            IERC20(tokens[i]).transfer(to, refunds[i]);
            unchecked {
                ++i;
            }
        }
    }

    /// @dev transfer refunded amounts from `from` address
    /// @param pool - address of GammaPool that will receive the LP tokens
    /// @param lpTokens - CFMM LP token amounts refunded
    /// @param from - sender of CFMM LP tokens
    function _transferLPTokensFrom(address pool, uint256 lpTokens, address from) internal virtual {
        IERC20(IGammaPool(pool).cfmm()).transferFrom(from,pool,lpTokens);
    }

    function _calcWritedown(address pool, uint256 tokenId) internal virtual returns (uint256) {
        address liquidationStrategy = IGammaPool(pool).singleLiquidationStrategy();
        (bool success, bytes memory data) = liquidationStrategy.staticcall(abi.encodeWithSignature("LIQUIDATION_FEE()"));
        if (success && data.length > 0) {
            uint16 liquidationFee = abi.decode(data, (uint16));
            (uint256 debt, uint256 collateral) = _canLiquidate(pool, tokenId);
            collateral = collateral * (1e4 - liquidationFee) / 1e4;

            return collateral >= debt ? 0 : debt - collateral;
        }

        return 0;
    }
}

File 2 of 15 : IGammaPool.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;

import "./IGammaPoolEvents.sol";
import "./IProtocol.sol";
import "./strategies/events/IGammaPoolERC20Events.sol";
import "./rates/IRateModel.sol";

/// @title Interface for GammaPool
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @dev Interface used for GammaPool implementations
interface IGammaPool is IProtocol, IGammaPoolEvents, IGammaPoolERC20Events, IRateModel {
    /// @dev Struct containing Loan data plus tokenId
    struct LoanData {
        /// @dev Loan counter, used to generate unique tokenId which indentifies the loan in the GammaPool
        uint256 id;

        /// @dev Loan tokenId
        uint256 tokenId;

        // 1x256 bits
        /// @dev GammaPool address loan belongs to
        address poolId; // 160 bits
        /// @dev Index of GammaPool interest rate at time loan is created/updated, max 7.9% trillion
        uint96 rateIndex; // 96 bits

        // 1x256 bits
        /// @dev Initial loan debt in liquidity invariant units. Only increase when more liquidity is borrowed, decreases when liquidity is paid
        uint128 initLiquidity; // 128 bits
        /// @dev Loan debt in liquidity invariant units in last update
        uint128 lastLiquidity; // 128 bits
        /// @dev Loan debt in liquidity invariant units, increases with every update according to how many blocks have passed
        uint128 liquidity; // 128 bits
        /// @dev Collateral in terms of liquidity invariant units, increases with every update according to how many blocks have passed
        uint256 collateral;

        /// @dev Initial loan debt in terms of LP tokens at time liquidity was borrowed, updates along with initLiquidity
        uint256 lpTokens;
        /// @dev Reserve tokens held as collateral for the liquidity debt, indices match GammaPool's tokens[] array indices
        uint128[] tokensHeld; // array of 128 bit numbers

        /// @dev reference address of contract holding additional collateral for loan (e.g. CollateralManager)
        address refAddr;
        /// @dev reference fee of contract holding additional collateral for loan (e.g. CollateralManager)
        uint16 refFee;
        /// @dev reference type of contract holding additional collateral for loan (e.g. CollateralManager)
        uint8 refType;

        /// @dev price at which loan was opened
        uint256 px;
        /// @dev if true loan can be liquidated
        bool canLiquidate;

        /// @dev names of ERC20 tokens of CFMM
        uint256 accFeeIndex;
        /// @dev Percent accrual in CFMM invariant since last update
        uint256 lastCFMMFeeIndex;
        /// @dev names of ERC20 tokens of CFMM
        uint256 LAST_BLOCK_NUMBER;

        /// @dev ERC20 tokens of CFMM
        address[] tokens;
        /// @dev decimals of ERC20 tokens of CFMM
        uint8[] decimals;
        /// @dev symbols of ERC20 tokens of CFMM
        string[] symbols;
        /// @dev names of ERC20 tokens of CFMM
        string[] names;

        /// @dev interest rate model parameter store
        address paramsStore;
        /// @dev address of short strategy
        address shortStrategy;

        /// @dev borrowed liquidity invariant of the pool
        uint256 BORROWED_INVARIANT;
        /// @dev Quantity of CFMM's liquidity invariant held in GammaPool as LP tokens
        uint256 LP_INVARIANT;
        /// @dev balance of CFMM LP tokens in the pool
        uint256 LP_TOKEN_BALANCE;
        /// @dev last CFMM liquidity invariant
        uint256 lastCFMMInvariant;
        /// @dev last CFMM total supply of LP tokens
        uint256 lastCFMMTotalSupply;
        /// @dev LTV liquidation threshold
        uint256 ltvThreshold;
        /// @dev Liquidation fee
        uint256 liquidationFee;
    }

    /// @dev Struct returned in getLatestRates function. Contains all relevant global state variables
    struct RateData {
        /// @dev GammaPool's ever increasing interest rate index, tracks interest accrued through CFMM and liquidity loans, max 7.9% trillion
        uint256 accFeeIndex;
        /// @dev Percent accrual in CFMM invariant since last update
        uint256 lastCFMMFeeIndex;
        /// @dev Percent accrual in CFMM invariant and GammaPool interest since last update
        uint256 lastFeeIndex;
        /// @dev Borrow APR of LP tokens in GammaPool
        uint256 borrowRate;
        /// @dev Utilization rate of GammaPool
        uint256 utilizationRate;
        /// @dev last block an update to the GammaPool's global storage variables happened
        uint256 lastBlockNumber;
        /// @dev Current block number when requesting pool data
        uint256 currBlockNumber;
        /// @dev Last Price in CFMM
        uint256 lastPrice;
        /// @dev Supply APR of LP tokens in GammaPool
        uint256 supplyRate;
        /// @dev names of ERC20 tokens of CFMM
        uint256 BORROWED_INVARIANT;
        /// @dev Quantity of CFMM's liquidity invariant held in GammaPool as LP tokens
        uint256 LP_INVARIANT;
        /// @dev EMA of utilization Rate
        uint256 emaUtilRate;
        /// @dev Minimum Utilization Rate 1
        uint256 minUtilRate1;
        /// @dev Minimum Utilization Rate 2
        uint256 minUtilRate2;
        /// @dev Dynamic origination fee divisor
        uint256 feeDivisor;
        /// @dev Loan opening origination fee in basis points
        uint256 origFee; // 16 bits
        /// @dev LTV liquidation threshold
        uint256 ltvThreshold;
        /// @dev Liquidation fee
        uint256 liquidationFee;
        /// @dev Short Strategy implementation address
        address shortStrategy;
        /// @dev Interest Rate Parameters Store contract
        address paramsStore;
    }

    /// @dev Struct returned in getPoolData function. Contains all relevant global state variables
    struct PoolData {
        /// @dev GammaPool address
        address poolId;
        /// @dev Protocol id of the implementation contract for this GammaPool
        uint16 protocolId;
        /// @dev Borrow Strategy implementation contract for this GammaPool
        address borrowStrategy;
        /// @dev Repay Strategy implementation contract for this GammaPool
        address repayStrategy;
        /// @dev Rebalance Strategy implementation contract for this GammaPool
        address rebalanceStrategy;
        /// @dev Short Strategy implementation contract for this GammaPool
        address shortStrategy;
        /// @dev Single Liquidation Strategy implementation contract for this GammaPool
        address singleLiquidationStrategy;
        /// @dev Batch Liquidation Strategy implementation contract for this GammaPool
        address batchLiquidationStrategy;

        /// @dev factory - address of factory contract that instantiated this GammaPool
        address factory;
        /// @dev paramsStore - interest rate model parameters store contract
        address paramsStore;

        // LP Tokens
        /// @dev Quantity of CFMM's LP tokens deposited in GammaPool by liquidity providers
        uint256 LP_TOKEN_BALANCE;// LP Tokens in GS, LP_TOKEN_TOTAL = LP_TOKEN_BALANCE + LP_TOKEN_BORROWED_PLUS_INTEREST
        /// @dev Quantity of CFMM's LP tokens that have been borrowed by liquidity borrowers excluding accrued interest (principal)
        uint256 LP_TOKEN_BORROWED;//LP Tokens that have been borrowed (Principal)
        /// @dev Quantity of CFMM's LP tokens that have been borrowed by liquidity borrowers including accrued interest
        uint256 LP_TOKEN_BORROWED_PLUS_INTEREST;//LP Tokens that have been borrowed (principal) plus interest in LP Tokens

        // Invariants
        /// @dev Quantity of CFMM's liquidity invariant that has been borrowed including accrued interest, maps to LP_TOKEN_BORROWED_PLUS_INTEREST
        uint128 BORROWED_INVARIANT;
        /// @dev Quantity of CFMM's liquidity invariant held in GammaPool as LP tokens, maps to LP_TOKEN_BALANCE
        uint128 LP_INVARIANT;//Invariant from LP Tokens, TOTAL_INVARIANT = BORROWED_INVARIANT + LP_INVARIANT

        // Rates
        /// @dev cfmm - address of CFMM this GammaPool is for
        address cfmm;
        /// @dev GammaPool's ever increasing interest rate index, tracks interest accrued through CFMM and liquidity loans, max 30.9% billion
        uint80 accFeeIndex;
        /// @dev External swap fee in basis points, max 255 basis points = 2.55%
        uint8 extSwapFee; // 8 bits
        /// @dev Loan opening origination fee in basis points
        uint16 origFee; // 16 bits
        /// @dev LAST_BLOCK_NUMBER - last block an update to the GammaPool's global storage variables happened
        uint40 LAST_BLOCK_NUMBER;
        /// @dev Percent accrual in CFMM invariant since last update
        uint64 lastCFMMFeeIndex; // 64 bits
        /// @dev Total liquidity invariant amount in CFMM (from GammaPool and others), read in last update to GammaPool's storage variables
        uint128 lastCFMMInvariant;
        /// @dev Total LP token supply from CFMM (belonging to GammaPool and others), read in last update to GammaPool's storage variables
        uint256 lastCFMMTotalSupply;

        // ERC20 fields
        /// @dev Total supply of GammaPool's own ERC20 token representing the liquidity of depositors to the CFMM through the GammaPool
        uint256 totalSupply;

        // tokens and balances
        /// @dev ERC20 tokens of CFMM
        address[] tokens;
        /// @dev symbols of ERC20 tokens of CFMM
        string[] symbols;
        /// @dev names of ERC20 tokens of CFMM
        string[] names;
        /// @dev Decimals of CFMM tokens, indices match tokens[] array
        uint8[] decimals;
        /// @dev Amounts of ERC20 tokens from the CFMM held as collateral in the GammaPool. Equals to the sum of all tokensHeld[] quantities in all loans
        uint128[] TOKEN_BALANCE;
        /// @dev Amounts of ERC20 tokens from the CFMM held in the CFMM as reserve quantities. Used to log prices in the CFMM during updates to the GammaPool
        uint128[] CFMM_RESERVES; //keeps track of price of CFMM at time of update

        /// @dev Last Price in CFMM
        uint256 lastPrice;
        /// @dev Percent accrual in CFMM invariant and GammaPool interest since last update
        uint256 lastFeeIndex;
        /// @dev Borrow rate of LP tokens in GammaPool
        uint256 borrowRate;
        /// @dev Utilization rate of GammaPool
        uint256 utilizationRate;
        /// @dev Current block number when requesting pool data
        uint40 currBlockNumber;
        /// @dev LTV liquidation threshold
        uint8 ltvThreshold;
        /// @dev Liquidation fee
        uint8 liquidationFee;
        /// @dev Supply APR of LP tokens in GammaPool
        uint256 supplyRate;
        /// @dev EMA of utilization Rate
        uint40 emaUtilRate;
        /// @dev Multiplier of EMA Utilization Rate
        uint8 emaMultiplier;
        /// @dev Minimum Utilization Rate 1
        uint8 minUtilRate1;
        /// @dev Minimum Utilization Rate 2
        uint8 minUtilRate2;
        /// @dev Dynamic origination fee divisor
        uint16 feeDivisor;
        /// @dev Minimum liquidity amount that can be borrowed
        uint72 minBorrow;
    }

    /// @dev cfmm - address of CFMM this GammaPool is for
    function cfmm() external view returns(address);

    /// @dev ERC20 tokens of CFMM
    function tokens() external view returns(address[] memory);

    /// @dev address of factory contract that instantiated this GammaPool
    function factory() external view returns(address);

    /// @dev viewer contract to implement complex view functions for data in this GammaPool
    function viewer() external view returns(address);

    /// @dev Borrow Strategy implementation contract for this GammaPool
    function borrowStrategy() external view returns(address);

    /// @dev Repay Strategy implementation contract for this GammaPool
    function repayStrategy() external view returns(address);

    /// @dev Rebalance Strategy implementation contract for this GammaPool
    function rebalanceStrategy() external view returns(address);

    /// @dev Short Strategy implementation contract for this GammaPool
    function shortStrategy() external view returns(address);

    /// @dev Single Loan Liquidation Strategy implementation contract for this GammaPool
    function singleLiquidationStrategy() external view returns(address);

    /// @dev Batch Liquidations Strategy implementation contract for this GammaPool
    function batchLiquidationStrategy() external view returns(address);

    /// @dev Set parameters to calculate origination fee, liquidation fee, and ltv threshold
    /// @param origFee - loan opening origination fee in basis points
    /// @param extSwapFee - external swap fee in basis points, max 255 basis points = 2.55%
    /// @param emaMultiplier - multiplier used in EMA calculation of utilization rate
    /// @param minUtilRate1 - minimum utilization rate to calculate dynamic origination fee in exponential model
    /// @param minUtilRate2 - minimum utilization rate to calculate dynamic origination fee in linear model
    /// @param feeDivisor - fee divisor for calculating origination fee, based on 2^(maxUtilRate - minUtilRate1)
    /// @param liquidationFee - liquidation fee to charge during liquidations in basis points (1 - 255 => 0.01% to 2.55%)
    /// @param ltvThreshold - ltv threshold (1 - 255 => 0.1% to 25.5%)
    /// @param minBorrow - minimum liquidity amount that can be borrowed or left unpaid in a loan
    function setPoolParams(uint16 origFee, uint8 extSwapFee, uint8 emaMultiplier, uint8 minUtilRate1, uint8 minUtilRate2, uint16 feeDivisor, uint8 liquidationFee, uint8 ltvThreshold, uint72 minBorrow) external;

    /// @dev Balances in the GammaPool of collateral tokens, CFMM LP tokens, and invariant amounts at last update
    /// @return tokenBalances - balances of collateral tokens in GammaPool
    /// @return lpTokenBalance - CFMM LP token balance of GammaPool
    /// @return lpTokenBorrowed - CFMM LP token principal amounts borrowed from GammaPool
    /// @return lpTokenBorrowedPlusInterest - CFMM LP token amounts borrowed from GammaPool including accrued interest
    /// @return borrowedInvariant - invariant amount borrowed from GammaPool including accrued interest, maps to lpTokenBorrowedPlusInterest
    /// @return lpInvariant - invariant of CFMM LP tokens in GammaPool not borrowed, maps to lpTokenBalance
    function getPoolBalances() external view returns(uint128[] memory tokenBalances, uint256 lpTokenBalance, uint256 lpTokenBorrowed,
        uint256 lpTokenBorrowedPlusInterest, uint256 borrowedInvariant, uint256 lpInvariant);

    /// @dev Balances in CFMM at last update of GammaPool
    /// @return cfmmReserves - total reserve tokens in CFMM last time GammaPool was updated
    /// @return cfmmInvariant - total liquidity invariant of CFMM last time GammaPool was updated
    /// @return cfmmTotalSupply - total CFMM LP tokens in existence last time GammaPool was updated
    function getCFMMBalances() external view returns(uint128[] memory cfmmReserves, uint256 cfmmInvariant, uint256 cfmmTotalSupply);

    /// @dev Interest rate information in GammaPool at last update
    /// @return accFeeIndex - total accrued interest in GammaPool at last update
    /// @return lastCFMMFeeIndex - total accrued CFMM fee since last update
    /// @return lastBlockNumber - last block GammaPool was updated
    function getRates() external view returns(uint256 accFeeIndex, uint256 lastCFMMFeeIndex, uint256 lastBlockNumber);

    /// @return data - struct containing all relevant global state variables and descriptive information of GammaPool. Used to avoid making multiple calls
    function getPoolData() external view returns(PoolData memory data);

    // Short Gamma

    /// @dev Deposit CFMM LP token and get GS LP token, without doing a transferFrom transaction. Must have sent CFMM LP token first
    /// @param to - address of receiver of GS LP token
    /// @return shares - quantity of GS LP tokens received for CFMM LP tokens
    function depositNoPull(address to) external returns(uint256 shares);

    /// @dev Withdraw CFMM LP token, by burning GS LP token, without doing a transferFrom transaction. Must have sent GS LP token first
    /// @param to - address of receiver of CFMM LP tokens
    /// @return assets - quantity of CFMM LP tokens received for GS LP tokens
    function withdrawNoPull(address to) external returns(uint256 assets);

    /// @dev Withdraw reserve token quantities of CFMM (instead of CFMM LP tokens), by burning GS LP token
    /// @param to - address of receiver of reserve token quantities
    /// @return reserves - quantity of reserve tokens withdrawn from CFMM and sent to receiver
    /// @return assets - quantity of CFMM LP tokens representing reserve tokens withdrawn
    function withdrawReserves(address to) external returns (uint256[] memory reserves, uint256 assets);

    /// @dev Deposit reserve token quantities to CFMM (instead of CFMM LP tokens) to get CFMM LP tokens, store them in GammaPool and receive GS LP tokens
    /// @param to - address of receiver of GS LP tokens
    /// @param amountsDesired - desired amounts of reserve tokens to deposit
    /// @param amountsMin - minimum amounts of reserve tokens to deposit
    /// @param data - information identifying request to deposit
    /// @return reserves - quantity of actual reserve tokens deposited in CFMM
    /// @return shares - quantity of GS LP tokens received for reserve tokens deposited
    function depositReserves(address to, uint256[] calldata amountsDesired, uint256[] calldata amountsMin, bytes calldata data) external returns(uint256[] memory reserves, uint256 shares);

    /// @return cfmmReserves - latest token reserves in the CFMM
    function getLatestCFMMReserves() external view returns(uint128[] memory cfmmReserves);

    /// @return cfmmReserves - latest token reserves in the CFMM
    /// @return cfmmInvariant - latest total invariant in the CFMM
    /// @return cfmmTotalSupply - latest total supply of LP tokens in CFMM
    function getLatestCFMMBalances() external view returns(uint128[] memory cfmmReserves, uint256 cfmmInvariant, uint256 cfmmTotalSupply);

    /// @return lastPrice - calculates and gets current price at CFMM
    function getLastCFMMPrice() external view returns(uint256);

    // Long Gamma

    /// @dev Create a new Loan struct
    /// @param refId - Reference id of post transaction activities attached to this loan
    /// @return tokenId - unique id of loan struct created
    function createLoan(uint16 refId) external returns(uint256 tokenId);

    /// @dev Get loan from storage and convert to LoanData struct
    /// @param _tokenId - tokenId of loan to convert
    /// @return _loanData - loan data struct (same as Loan + tokenId)
    function getLoanData(uint256 _tokenId) external view returns(LoanData memory _loanData);

    /// @dev Get loan with its most updated information
    /// @param _tokenId - unique id of loan, used to look up loan in GammaPool
    /// @return _loanData - loan data struct (same as Loan + tokenId)
    function loan(uint256 _tokenId) external view returns(LoanData memory _loanData);

    /// @dev Get list of loans and their corresponding tokenIds created in GammaPool. Capped at s.tokenIds.length.
    /// @param start - index from where to start getting tokenIds from array
    /// @param end - end index of array wishing to get tokenIds. If end > s.tokenIds.length, end is s.tokenIds.length
    /// @param active - if true, return loans that have an outstanding liquidity debt
    /// @return _loans - list of loans created in GammaPool
    function getLoans(uint256 start, uint256 end, bool active) external view returns(LoanData[] memory _loans);

    /// @dev calculate liquidity invariant from collateral tokens
    /// @param tokensHeld - loan's collateral tokens
    /// @return collateralInvariant - invariant calculated from loan's collateral tokens
    function calcInvariant(uint128[] memory tokensHeld) external view returns(uint256);

    /// @dev Get list of loans mapped to tokenIds in array `tokenIds`
    /// @param tokenIds - list of loan tokenIds
    /// @param active - if true, return loans that have an outstanding liquidity debt
    /// @return _loans - list of loans created in GammaPool
    function getLoansById(uint256[] calldata tokenIds, bool active) external view returns(LoanData[] memory _loans);

    /// @return loanCount - total number of loans opened
    function getLoanCount() external view returns(uint256);

    /// @dev Deposit more collateral in loan identified by tokenId
    /// @param tokenId - unique id identifying loan
    /// @param ratio - ratio to rebalance collateral after increasing collateral
    /// @return tokensHeld - updated collateral token amounts backing loan
    function increaseCollateral(uint256 tokenId, uint256[] calldata ratio) external returns(uint128[] memory tokensHeld);

    /// @dev Withdraw collateral from loan identified by tokenId
    /// @param tokenId - unique id identifying loan
    /// @param amounts - amounts of collateral tokens requested to withdraw
    /// @param to - destination address of receiver of collateral withdrawn
    /// @param ratio - ratio to rebalance collateral after withdrawing collateral
    /// @return tokensHeld - updated collateral token amounts backing loan
    function decreaseCollateral(uint256 tokenId, uint128[] memory amounts, address to, uint256[] calldata ratio) external returns(uint128[] memory tokensHeld);

    /// @dev Borrow liquidity from the CFMM and add it to the debt and collateral of loan identified by tokenId
    /// @param tokenId - unique id identifying loan
    /// @param lpTokens - quantity of CFMM LP tokens requested to short
    /// @param ratio - ratio to rebalance collateral after borrowing
    /// @return liquidityBorrowed - liquidity amount that has been borrowed
    /// @return amounts - reserves quantities withdrawn from CFMM that correspond to the LP tokens shorted, now used as collateral
    /// @return tokensHeld - updated collateral token amounts backing loan
    function borrowLiquidity(uint256 tokenId, uint256 lpTokens, uint256[] calldata ratio) external returns(uint256 liquidityBorrowed, uint256[] memory amounts, uint128[] memory tokensHeld);

    /// @dev Repay liquidity debt of loan identified by tokenId, debt is repaid using available collateral in loan
    /// @param tokenId - unique id identifying loan
    /// @param liquidity - liquidity debt being repaid, capped at actual liquidity owed. Can't repay more than you owe
    /// @param collateralId - index of collateral token + 1
    /// @param to - if repayment type requires withdrawal, the address that will receive the funds. Otherwise can be zero address
    /// @return liquidityPaid - liquidity amount that has been repaid
    /// @return amounts - collateral amounts consumed in repaying liquidity debt
    function repayLiquidity(uint256 tokenId, uint256 liquidity, uint256 collateralId, address to) external returns(uint256 liquidityPaid, uint256[] memory amounts);

    /// @dev Repay liquidity debt of loan identified by tokenId, debt is repaid using available collateral in loan
    /// @param tokenId - unique id identifying loan
    /// @param liquidity - liquidity debt being repaid, capped at actual liquidity owed. Can't repay more than you owe
    /// @param ratio - weights of collateral after repaying liquidity
    /// @return liquidityPaid - liquidity amount that has been repaid
    /// @return amounts - collateral amounts consumed in repaying liquidity debt
    function repayLiquiditySetRatio(uint256 tokenId, uint256 liquidity, uint256[] calldata ratio) external returns(uint256 liquidityPaid, uint256[] memory amounts);

    /// @dev Repay liquidity debt of loan identified by tokenId, using CFMM LP token
    /// @param tokenId - unique id identifying loan
    /// @param collateralId - index of collateral token to rebalance to + 1
    /// @param to - if repayment type requires withdrawal, the address that will receive the funds. Otherwise can be zero address
    /// @return liquidityPaid - liquidity amount that has been repaid
    /// @return tokensHeld - remaining token amounts collateralizing loan
    function repayLiquidityWithLP(uint256 tokenId, uint256 collateralId, address to) external returns(uint256 liquidityPaid, uint128[] memory tokensHeld);

    /// @dev Rebalance collateral amounts of loan identified by tokenId by purchasing or selling some of the collateral
    /// @param tokenId - unique id identifying loan
    /// @param deltas - collateral amounts being bought or sold (>0 buy, <0 sell), index matches tokensHeld[] index. Only n-1 tokens can be traded
    /// @param ratio - ratio to rebalance collateral
    /// @return tokensHeld - updated collateral token amounts backing loan
    function rebalanceCollateral(uint256 tokenId, int256[] memory deltas, uint256[] calldata ratio) external returns(uint128[] memory tokensHeld);

    /// @dev Update pool liquidity debt and optinally also loan liquidity debt
    /// @param tokenId - (optional) unique ids identifying loan, pass zero to ignore this parameter
    /// @return loanLiquidityDebt - updated liquidity debt amount of loan
    /// @return poolLiquidityDebt - updated liquidity debt amount of pool
    function updatePool(uint256 tokenId) external returns(uint256 loanLiquidityDebt, uint256 poolLiquidityDebt);

    /// @notice When calling this function and adding additional collateral it is assumed that you have sent the collateral first
    /// @dev Function to liquidate a loan using its own collateral or depositing additional tokens. Seeks full liquidation
    /// @param tokenId - tokenId of loan being liquidated
    /// @return loanLiquidity - loan liquidity liquidated (after write down)
    /// @return refund - amount of CFMM LP tokens being refunded to liquidator
    function liquidate(uint256 tokenId) external returns(uint256 loanLiquidity, uint256 refund);

    /// @dev Function to liquidate a loan using external LP tokens. Allows partial liquidation
    /// @param tokenId - tokenId of loan being liquidated
    /// @return loanLiquidity - loan liquidity liquidated (after write down)
    /// @return refund - amounts from collateral tokens being refunded to liquidator
    function liquidateWithLP(uint256 tokenId) external returns(uint256 loanLiquidity, uint256[] memory refund);

    /// @dev Function to liquidate multiple loans in batch.
    /// @param tokenIds - list of tokenIds of loans to liquidate
    /// @return totalLoanLiquidity - total loan liquidity liquidated (after write down)
    /// @return refund - amounts from collateral tokens being refunded to liquidator
    function batchLiquidations(uint256[] calldata tokenIds) external returns(uint256 totalLoanLiquidity, uint256[] memory refund);

    // Sync functions

    /// @dev Skim excess collateral tokens or CFMM LP tokens from GammaPool and send them to receiver (`to`) address
    /// @param to - address receiving excess tokens
    function skim(address to) external;

    /// @dev Synchronize LP_TOKEN_BALANCE with actual CFMM LP tokens deposited in GammaPool
    function sync() external;
}

File 3 of 15 : IGammaPoolEvents.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;

import "./strategies/events/ILiquidationStrategyEvents.sol";
import "./strategies/events/IShortStrategyEvents.sol";
import "./strategies/events/IExternalStrategyEvents.sol";

/// @title GammaPool Events Interface
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @dev Events emitted by all GammaPool implementations (contains all strategy events)
interface IGammaPoolEvents is IShortStrategyEvents, ILiquidationStrategyEvents, IExternalStrategyEvents {
    /// @dev Event emitted when a Loan is created
    /// @param caller - address that created the loan
    /// @param tokenId - unique id that identifies the loan in question
    /// @param refId - Reference id of post transaction activities attached to this loan
    event LoanCreated(address indexed caller, uint256 tokenId, uint16 refId);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;

import "./IGammaPool.sol";

/// @title Interface for Viewer Contract for GammaPool
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @dev Viewer makes complex view function calls from GammaPool's storage data (e.g. updated loan and pool debt)
interface IPoolViewer {

    /// @dev Check if can liquidate loan identified by `tokenId`
    /// @param pool - address of pool loans belong to
    /// @param tokenId - unique id of loan, used to look up loan in GammaPool
    /// @return canLiquidate - true if loan can be liquidated, false otherwise
    function canLiquidate(address pool, uint256 tokenId) external view returns(bool);

    /// @dev Get latest rate information from GammaPool
    /// @param pool - address of pool to request latest rates for
    /// @return data - RateData struct containing latest rate information
    function getLatestRates(address pool) external view returns(IGammaPool.RateData memory data);

    /// @dev Get list of loans and their corresponding tokenIds created in GammaPool. Capped at s.tokenIds.length.
    /// @param pool - address of pool loans belong to
    /// @param start - index from where to start getting tokenIds from array
    /// @param end - end index of array wishing to get tokenIds. If end > s.tokenIds.length, end is s.tokenIds.length
    /// @param active - if true, return loans that have an outstanding liquidity debt
    /// @return _loans - list of loans created in GammaPool
    function getLoans(address pool, uint256 start, uint256 end, bool active) external view returns(IGammaPool.LoanData[] memory _loans);

    /// @dev Get list of loans mapped to tokenIds in array `tokenIds`
    /// @param pool - address of pool loans belong to
    /// @param tokenIds - list of loan tokenIds
    /// @param active - if true, return loans that have an outstanding liquidity debt
    /// @return _loans - list of loans created in GammaPool
    function getLoansById(address pool, uint256[] calldata tokenIds, bool active) external view returns(IGammaPool.LoanData[] memory _loans);

    /// @dev Get loan with its most updated information
    /// @param pool - address of pool loan belongs to
    /// @param tokenId - unique id of loan, used to look up loan in GammaPool
    /// @return loanData - loan data struct (same as Loan + tokenId)
    function loan(address pool, uint256 tokenId) external view returns(IGammaPool.LoanData memory loanData);

    /// @dev Returns pool storage data updated to their latest values
    /// @notice Difference with getPoolData() is this struct is what PoolData would return if an update of the GammaPool were to occur at the current block
    /// @param pool - address of pool to get pool data for
    /// @return data - struct containing all relevant global state variables and descriptive information of GammaPool. Used to avoid making multiple calls
    function getLatestPoolData(address pool) external view returns(IGammaPool.PoolData memory data);

    /// @dev Calculate origination fee that will be charged if borrowing liquidity amount
    /// @param pool - address of GammaPool to calculate origination fee for
    /// @param liquidity - liquidity to borrow
    /// @return origFee - calculated origination fee, without any discounts
    function calcDynamicOriginationFee(address pool, uint256 liquidity) external view returns(uint256 origFee);

    /// @dev Return pool storage data
    /// @param pool - address of pool to get pool data for
    /// @return data - struct containing all relevant global state variables and descriptive information of GammaPool. Used to avoid making multiple calls
    function getPoolData(address pool) external view returns(IGammaPool.PoolData memory data);

    /// @dev Get CFMM tokens meta data
    /// @param _tokens - array of token address of ERC20 tokens of CFMM
    /// @return _symbols - array of symbols of ERC20 tokens of CFMM
    /// @return _names - array of names of ERC20 tokens of CFMM
    /// @return _decimals - array of decimals of ERC20 tokens of CFMM
    function getTokensMetaData(address[] memory _tokens) external view returns(string[] memory _symbols, string[] memory _names, uint8[] memory _decimals);

}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;

/// @title Interface for Protocol
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @dev Interface used to add protocols and initialize them in GammaPoolFactory
interface IProtocol {
    /// @dev Protocol id of the implementation contract for this GammaPool
    function protocolId() external view returns(uint16);

    /// @dev Check GammaPool for CFMM and tokens can be created with this implementation
    /// @param _tokens - assumed tokens of CFMM, validate function should check CFMM is indeed for these tokens
    /// @param _cfmm - address of CFMM GammaPool will be for
    /// @param _data - custom struct containing additional information used to verify the `_cfmm`
    /// @return _tokensOrdered - tokens ordered to match the same order as in CFMM
    function validateCFMM(address[] calldata _tokens, address _cfmm, bytes calldata _data) external view returns(address[] memory _tokensOrdered);

    /// @dev Function to initialize state variables GammaPool, called usually from GammaPoolFactory contract right after GammaPool instantiation
    /// @param _cfmm - address of CFMM GammaPool is for
    /// @param _tokens - ERC20 tokens of CFMM
    /// @param _decimals - decimals of CFMM tokens, indices must match _tokens[] array
    /// @param _data - custom struct containing additional information used to verify the `_cfmm`
    /// @param _minBorrow - minimum amount of liquidity that can be borrowed or left unpaid in a loan
    function initialize(address _cfmm, address[] calldata _tokens, uint8[] calldata _decimals, uint72 _minBorrow, bytes calldata _data) external;
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;

/// @title Interface of Interest Rate Model Store
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @notice Interface of contract that saves and retrieves interest rate model parameters
interface IRateModel {
    /// @dev Function to validate interest rate model parameters
    /// @param _data - bytes parameters containing interest rate model parameters
    /// @return validation - true if parameters passed validation
    function validateParameters(bytes calldata _data) external view returns(bool);

    /// @dev Gets address of contract containing parameters for interest rate model
    /// @return address - address of smart contract that stores interest rate parameters
    function rateParamsStore() external view returns(address);
}

File 7 of 15 : IExternalStrategyEvents.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;

import "./IStrategyEvents.sol";

/// @title External Strategy Events Interface
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @dev Events emitted by external strategy (flash loans) implementations
interface IExternalStrategyEvents is IStrategyEvents {
    /// @dev Event emitted when a flash loan is made. Purpose of flash loan is for external swaps/rebalance of loan collateral
    /// @param tokenId - unique id that identifies the loan in question
    /// @param amounts - amounts of tokens held as collateral in pool that were swapped
    /// @param lpTokens - LP tokens swapped externally
    /// @param liquidity - total liquidity externally swapped in flash loan (amounts + lpTokens)
    /// @param txType - transaction type. Possible values come from enum TX_TYPE
    event ExternalSwap(uint256 indexed tokenId, uint128[] amounts, uint256 lpTokens, uint128 liquidity, TX_TYPE indexed txType);
}

File 8 of 15 : IGammaPoolERC20Events.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;

/// @title GammaPool ERC20 Events
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @dev Events that should be emitted by all strategy implementations (root of all strategy events interfaces)
interface IGammaPoolERC20Events {
    /// @dev Emitted when `amount` GS LP tokens are moved from account `from` to account `to`.
    /// @param from - address sending GS LP tokens
    /// @param to - address receiving GS LP tokens
    /// @param amount - amount of GS LP tokens being sent
    event Transfer(address indexed from, address indexed to, uint256 amount);

    /// @dev Emitted when the allowance of a `spender` for an `owner` is set by a call to approve function. `amount` is the new allowance.
    /// @param owner - address which owns the GS LP tokens spender is being given permission to spend
    /// @param spender - address given permission to spend owner's GS LP tokens
    /// @param amount - amount of GS LP tokens spender is given permission to spend
    event Approval(address indexed owner, address indexed spender, uint256 amount);
}

File 9 of 15 : ILiquidationStrategyEvents.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;

import "./ILongStrategyEvents.sol";

/// @title Liquidation Strategy Events Interface
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @dev Events emitted by all liquidation strategy implementations
interface ILiquidationStrategyEvents is ILongStrategyEvents {
    /// @dev Event emitted when liquidating through _liquidate or _liquidateWithLP functions
    /// @param tokenId - id identifier of loan being liquidated
    /// @param collateral - collateral of loan being liquidated
    /// @param liquidity - liquidity debt being repaid
    /// @param writeDownAmt - amount of liquidity invariant being written down
    /// @param fee - liquidation fee paid to liquidator in liquidity invariant units
    /// @param txType - type of liquidation. Possible values come from enum TX_TYPE
    event Liquidation(uint256 indexed tokenId, uint128 collateral, uint128 liquidity, uint128 writeDownAmt, uint128 fee, TX_TYPE txType);
}

File 10 of 15 : ILongStrategyEvents.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;

import "./IStrategyEvents.sol";

/// @title Long Strategy Events Interface
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @dev Events emitted by all long strategy implementations
interface ILongStrategyEvents is IStrategyEvents {
    /// @dev Event emitted when a Loan is updated
    /// @param tokenId - unique id that identifies the loan in question
    /// @param tokensHeld - amounts of tokens held as collateral against the loan
    /// @param liquidity - liquidity invariant that was borrowed including accrued interest
    /// @param initLiquidity - initial liquidity borrowed excluding interest (principal)
    /// @param lpTokens - LP tokens borrowed excluding interest (principal)
    /// @param rateIndex - interest rate index of GammaPool at time loan is updated
    /// @param txType - transaction type. Possible values come from enum TX_TYPE
    event LoanUpdated(uint256 indexed tokenId, uint128[] tokensHeld, uint128 liquidity, uint128 initLiquidity, uint256 lpTokens, uint96 rateIndex, TX_TYPE indexed txType);
}

File 11 of 15 : IShortStrategyEvents.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;

import "./IStrategyEvents.sol";

/// @title Short Strategy Events Interface
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @dev Events emitted by all short strategy implementations
interface IShortStrategyEvents is IStrategyEvents {
    /// @dev Event emitted when a deposit of CFMM LP tokens in exchange of GS LP tokens happens (e.g. _deposit, _mint, _depositReserves, _depositNoPull)
    /// @param caller - address calling the function to deposit CFMM LP tokens
    /// @param to - address receiving GS LP tokens
    /// @param assets - amount CFMM LP tokens deposited
    /// @param shares - amount GS LP tokens minted
    event Deposit(address indexed caller, address indexed to, uint256 assets, uint256 shares);

    /// @dev Event emitted when a withdrawal of CFMM LP tokens happens (e.g. _withdraw, _redeem, _withdrawReserves, _withdrawNoPull)
    /// @param caller - address calling the function to withdraw CFMM LP tokens
    /// @param to - address receiving CFMM LP tokens
    /// @param from - address redeeming/burning GS LP tokens
    /// @param assets - amount of CFMM LP tokens withdrawn
    /// @param shares - amount of GS LP tokens redeemed
    event Withdraw(address indexed caller, address indexed to, address indexed from, uint256 assets, uint256 shares);
}

File 12 of 15 : IStrategyEvents.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;

/// @title Strategy Events interface
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @dev Events that should be emitted by all strategy implementations (root of all strategy events interfaces)
interface IStrategyEvents {
    enum TX_TYPE {
        DEPOSIT_LIQUIDITY,      // 0
        WITHDRAW_LIQUIDITY,     // 1
        DEPOSIT_RESERVES,       // 2
        WITHDRAW_RESERVES,      // 3
        INCREASE_COLLATERAL,    // 4
        DECREASE_COLLATERAL,    // 5
        REBALANCE_COLLATERAL,   // 6
        BORROW_LIQUIDITY,       // 7
        REPAY_LIQUIDITY,        // 8
        REPAY_LIQUIDITY_SET_RATIO,// 9
        REPAY_LIQUIDITY_WITH_LP,// 10
        LIQUIDATE,              // 11
        LIQUIDATE_WITH_LP,      // 12
        BATCH_LIQUIDATION,      // 13
        SYNC,                   // 14
        EXTERNAL_REBALANCE,     // 15
        EXTERNAL_LIQUIDATION,   // 16
        UPDATE_POOL }           // 17

    /// @dev Event emitted when the Pool's global state variables is updated
    /// @param lpTokenBalance - quantity of CFMM LP tokens deposited in the pool
    /// @param lpTokenBorrowed - quantity of CFMM LP tokens that have been borrowed from the pool (principal)
    /// @param lastBlockNumber - last block the Pool's where updated
    /// @param accFeeIndex - interest of total accrued interest in the GammaPool until current update
    /// @param lpTokenBorrowedPlusInterest - quantity of CFMM LP tokens that have been borrowed from the pool including interest
    /// @param lpInvariant - lpTokenBalance as invariant units
    /// @param borrowedInvariant - lpTokenBorrowedPlusInterest as invariant units
    /// @param cfmmReserves - reserves in CFMM. Used to track price
    /// @param txType - transaction type. Possible values come from enum TX_TYPE
    event PoolUpdated(uint256 lpTokenBalance, uint256 lpTokenBorrowed, uint40 lastBlockNumber, uint80 accFeeIndex,
        uint256 lpTokenBorrowedPlusInterest, uint128 lpInvariant, uint128 borrowedInvariant, uint128[] cfmmReserves, TX_TYPE indexed txType);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;

/// @title Math Library
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @dev Library for performing various math operations
library GSMath {
    function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = x > y ? x : y;
    }

    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = x < y ? x : y;
    }

    // Babylonian Method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
    function sqrt(uint256 y) internal pure returns (uint256 z) {
        unchecked {
            if (y > 3) {
                z = y;
                uint256 x = y / 2 + 1;
                while (x < z) {
                    z = x;
                    x = (y / x + x) / 2;
                }
            } else if (y != 0) {
                z = 1;
            }
        }
    }
}

// SPDX-License-Identifier: GPL-v3
pragma solidity >=0.8.0;

import "@gammaswap/v1-core/contracts/interfaces/IGammaPool.sol";

/// @title Interface for Liquidator contract
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @dev Helps liquidation of loans in GammaPools
interface ILiquidator {

    /// @dev Calculate liquidity debt as CFMM LP Tokens
    /// @param pool - address of GammaPool loan belongs to
    /// @param tokenId - tokenId of loan in GammaPool (`pool`) to check
    /// @return lpTokens - liquidity debt of loan as CFMM LP Tokens
    function calcLPTokenDebt(address pool, uint256 tokenId) external view returns(uint256 lpTokens);

    /// @dev Check if loan in `pool` identified by `tokenId` can be liquidated
    /// @param pool - address of GammaPool loan belongs to
    /// @param tokenId - tokenId of loan in GammaPool (`pool`) to check
    /// @return liquidity - liquidity debt of loan (not written down), if it can be liquidated. Otherwise it returns 0
    /// @return collateral - liquidity collateral backing loan, if it can be liquidated. Otherwise it returns 0
    function canLiquidate(address pool, uint256 tokenId) external view returns(uint256 liquidity, uint256 collateral);

    /// @dev Check if loans in `pool` identified by `tokenIds` can be liquidated
    /// @param pool - address of GammaPool loan belongs to
    /// @param tokenIds - list of tokenIds of loans in GammaPool (`pool`) to check
    /// @return _tokenIds - list of tokenIds of loans that can be liquidated. The array may be larger
    /// @return _liquidity - summed liquidity debt of loans (not written down) that can be liquidated. If a loan can't be liquidate it is not summed
    /// @return _collateral - liquidity collateral backing loan that can be liquidated. If a loan can't be liquidate it is not summed
    function canBatchLiquidate(address pool, uint256[] calldata tokenIds) external view returns(uint256[] memory _tokenIds, uint256 _liquidity, uint256 _collateral);

    /// @dev Liquidate loan in `pool` identified by `tokenId` using the loan's own collateral tokens
    /// @param pool - address of GammaPool loan belongs to
    /// @param tokenId - tokenId of loan in GammaPool (`pool`) to check
    /// @param to - receiver of liquidation fee
    /// @return refund - CFMM LP tokens that are refunded to liquidator
    function liquidate(address pool, uint256 tokenId, address to) external returns(uint256 refund);

    /// @dev Liquidate loan in `pool` identified by `tokenId` using CFMM LP tokens of the CFMM liquidity was borrowed from
    /// @param pool - address of GammaPool loan belongs to
    /// @param tokenId - tokenId of loan in GammaPool (`pool`) to check
    /// @param lpTokens - CFMM LP tokens to transfer to liquidate
    /// @param calcLpTokens - if true calculate how many CFMM LP Tokens to liquidate
    /// @param to - receiver of liquidation fee
    /// @return refunds - collateral tokens that are refunded to liquidator
    function liquidateWithLP(address pool, uint256 tokenId, uint256 lpTokens, bool calcLpTokens, address to) external returns(uint256[] memory refunds);

    /// @dev Liquidate loan in `pool` identified by `tokenId` using the loan's own collateral tokens
    /// @param pool - address of GammaPool loan belongs to
    /// @param tokenId - tokenId of loan in GammaPool (`pool`) to check
    /// @param to - receiver of liquidation fee
    /// @return _tokenIds - list of tokenIds of loans that were liquidated
    /// @return refunds - collateral tokens that are refunded to liquidator from all loans that were liquidated
    function batchLiquidate(address pool, uint256[] calldata tokenId, address to) external returns(uint256[] memory _tokenIds, uint256[] memory refunds);

    /// @dev Get most updated loan information for a loan identified by `tokenId` in `pool`
    /// @param pool - address of GammaPool loan belongs to
    /// @param tokenId - tokenId of loan in GammaPool (`pool`) to check
    /// @return loan - struct containing most up to date loan information and other data to identify loan
    function getLoan(address pool, uint256 tokenId) external view returns(IGammaPool.LoanData memory loan);

    /// @dev Get most updated loan information for list of loans in GammaPool
    /// @param pool - address of GammaPool loans belong to
    /// @param tokenIds - list of tokenIds of loans in GammaPool (`pool`) to get information for
    /// @param active - filter to select only loans with outstanding liquidity debts (if true, ignore loans with 0 liquidity debts)
    /// @return loans - struct containing most up to date loan information and other data to identify loan
    function getLoans(address pool, uint256[] calldata tokenIds, bool active) external view returns(IGammaPool.LoanData[] memory loans);

    /// @dev Get most updated loan information for loans opened in GammaPool from index `start` to `end`
    /// @notice All loans in GammaPool are opened in ascending order. The first loan has index 1, the next is 2, ...
    /// @param pool - address of GammaPool loans belong to
    /// @param start - beginning index to query for loans in GammaPool
    /// @param end - last index to query for loans in GammaPool
    /// @param active - filter to select only loans with outstanding liquidity debts (if true, ignore loans with 0 liquidity debts)
    /// @return loans - struct containing most up to date loan information and other data to identify loan
    function getLoans(address pool, uint256 start, uint256 end, bool active) external view returns(IGammaPool.LoanData[] memory loans);

    /// @dev Get tokenIds of loans opened in GammaPool from index `start` to `end`
    /// @notice All loans in GammaPool are opened in ascending order. The first loan has index 1, the next is 2, ...
    /// @param pool - address of GammaPool loans belong to
    /// @param start - beginning index to query for loans in GammaPool
    /// @param end - last index to query for loans in GammaPool
    /// @param active - filter to select only loans with outstanding liquidity debts (if true, ignore loans with 0 liquidity debts)
    /// @return tokenIds - list of tokenIds of loans found in query
    function getLoanIds(address pool, uint256 start, uint256 end, bool active) external view returns(uint256[] memory tokenIds);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/"
  ],
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"address","name":"to","type":"address"}],"name":"batchLiquidate","outputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"uint256[]","name":"refunds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"calcLPTokenDebt","outputs":[{"internalType":"uint256","name":"lpTokens","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"canBatchLiquidate","outputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"uint256","name":"_liquidity","type":"uint256"},{"internalType":"uint256","name":"_collateral","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"canLiquidate","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"collateral","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getLoan","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"poolId","type":"address"},{"internalType":"uint96","name":"rateIndex","type":"uint96"},{"internalType":"uint128","name":"initLiquidity","type":"uint128"},{"internalType":"uint128","name":"lastLiquidity","type":"uint128"},{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint256","name":"lpTokens","type":"uint256"},{"internalType":"uint128[]","name":"tokensHeld","type":"uint128[]"},{"internalType":"address","name":"refAddr","type":"address"},{"internalType":"uint16","name":"refFee","type":"uint16"},{"internalType":"uint8","name":"refType","type":"uint8"},{"internalType":"uint256","name":"px","type":"uint256"},{"internalType":"bool","name":"canLiquidate","type":"bool"},{"internalType":"uint256","name":"accFeeIndex","type":"uint256"},{"internalType":"uint256","name":"lastCFMMFeeIndex","type":"uint256"},{"internalType":"uint256","name":"LAST_BLOCK_NUMBER","type":"uint256"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint8[]","name":"decimals","type":"uint8[]"},{"internalType":"string[]","name":"symbols","type":"string[]"},{"internalType":"string[]","name":"names","type":"string[]"},{"internalType":"address","name":"paramsStore","type":"address"},{"internalType":"address","name":"shortStrategy","type":"address"},{"internalType":"uint256","name":"BORROWED_INVARIANT","type":"uint256"},{"internalType":"uint256","name":"LP_INVARIANT","type":"uint256"},{"internalType":"uint256","name":"LP_TOKEN_BALANCE","type":"uint256"},{"internalType":"uint256","name":"lastCFMMInvariant","type":"uint256"},{"internalType":"uint256","name":"lastCFMMTotalSupply","type":"uint256"},{"internalType":"uint256","name":"ltvThreshold","type":"uint256"},{"internalType":"uint256","name":"liquidationFee","type":"uint256"}],"internalType":"struct IGammaPool.LoanData","name":"loan","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"},{"internalType":"bool","name":"active","type":"bool"}],"name":"getLoanIds","outputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"},{"internalType":"bool","name":"active","type":"bool"}],"name":"getLoans","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"poolId","type":"address"},{"internalType":"uint96","name":"rateIndex","type":"uint96"},{"internalType":"uint128","name":"initLiquidity","type":"uint128"},{"internalType":"uint128","name":"lastLiquidity","type":"uint128"},{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint256","name":"lpTokens","type":"uint256"},{"internalType":"uint128[]","name":"tokensHeld","type":"uint128[]"},{"internalType":"address","name":"refAddr","type":"address"},{"internalType":"uint16","name":"refFee","type":"uint16"},{"internalType":"uint8","name":"refType","type":"uint8"},{"internalType":"uint256","name":"px","type":"uint256"},{"internalType":"bool","name":"canLiquidate","type":"bool"},{"internalType":"uint256","name":"accFeeIndex","type":"uint256"},{"internalType":"uint256","name":"lastCFMMFeeIndex","type":"uint256"},{"internalType":"uint256","name":"LAST_BLOCK_NUMBER","type":"uint256"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint8[]","name":"decimals","type":"uint8[]"},{"internalType":"string[]","name":"symbols","type":"string[]"},{"internalType":"string[]","name":"names","type":"string[]"},{"internalType":"address","name":"paramsStore","type":"address"},{"internalType":"address","name":"shortStrategy","type":"address"},{"internalType":"uint256","name":"BORROWED_INVARIANT","type":"uint256"},{"internalType":"uint256","name":"LP_INVARIANT","type":"uint256"},{"internalType":"uint256","name":"LP_TOKEN_BALANCE","type":"uint256"},{"internalType":"uint256","name":"lastCFMMInvariant","type":"uint256"},{"internalType":"uint256","name":"lastCFMMTotalSupply","type":"uint256"},{"internalType":"uint256","name":"ltvThreshold","type":"uint256"},{"internalType":"uint256","name":"liquidationFee","type":"uint256"}],"internalType":"struct IGammaPool.LoanData[]","name":"loans","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256[]","name":"tokenId","type":"uint256[]"},{"internalType":"bool","name":"active","type":"bool"}],"name":"getLoans","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"poolId","type":"address"},{"internalType":"uint96","name":"rateIndex","type":"uint96"},{"internalType":"uint128","name":"initLiquidity","type":"uint128"},{"internalType":"uint128","name":"lastLiquidity","type":"uint128"},{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint256","name":"lpTokens","type":"uint256"},{"internalType":"uint128[]","name":"tokensHeld","type":"uint128[]"},{"internalType":"address","name":"refAddr","type":"address"},{"internalType":"uint16","name":"refFee","type":"uint16"},{"internalType":"uint8","name":"refType","type":"uint8"},{"internalType":"uint256","name":"px","type":"uint256"},{"internalType":"bool","name":"canLiquidate","type":"bool"},{"internalType":"uint256","name":"accFeeIndex","type":"uint256"},{"internalType":"uint256","name":"lastCFMMFeeIndex","type":"uint256"},{"internalType":"uint256","name":"LAST_BLOCK_NUMBER","type":"uint256"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint8[]","name":"decimals","type":"uint8[]"},{"internalType":"string[]","name":"symbols","type":"string[]"},{"internalType":"string[]","name":"names","type":"string[]"},{"internalType":"address","name":"paramsStore","type":"address"},{"internalType":"address","name":"shortStrategy","type":"address"},{"internalType":"uint256","name":"BORROWED_INVARIANT","type":"uint256"},{"internalType":"uint256","name":"LP_INVARIANT","type":"uint256"},{"internalType":"uint256","name":"LP_TOKEN_BALANCE","type":"uint256"},{"internalType":"uint256","name":"lastCFMMInvariant","type":"uint256"},{"internalType":"uint256","name":"lastCFMMTotalSupply","type":"uint256"},{"internalType":"uint256","name":"ltvThreshold","type":"uint256"},{"internalType":"uint256","name":"liquidationFee","type":"uint256"}],"internalType":"struct IGammaPool.LoanData[]","name":"loans","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"liquidate","outputs":[{"internalType":"uint256","name":"refund","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"lpTokens","type":"uint256"},{"internalType":"bool","name":"calcLpTokens","type":"bool"},{"internalType":"address","name":"to","type":"address"}],"name":"liquidateWithLP","outputs":[{"internalType":"uint256[]","name":"refunds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b5061281f806100206000396000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c8063b39ff73611610066578063b39ff7361461012f578063cd2a755d14610157578063dcf5843914610177578063f3b5b0b314610198578063f42b405d146101ba57600080fd5b80634914c008146100a3578063753a43d2146100c957806383f0454a146100e9578063912863aa146100fc578063a1c515861461010f575b600080fd5b6100b66100b13660046117bf565b6101cd565b6040519081526020015b60405180910390f35b6100dc6100d736600461180f565b6104e9565b6040516100c09190611bcf565b6100b66100f7366004611c31565b610572565b6100dc61010a366004611ca1565b610587565b61012261011d366004611c31565b6105ba565b6040516100c09190611cfd565b61014261013d366004611c31565b610696565b604080519283526020830191909152016100c0565b61016a610165366004611d10565b6106af565b6040516100c09190611d9f565b61018a610185366004611db2565b610a14565b6040516100c0929190611e0e565b6101ab6101a6366004611e33565b610cb8565b6040516100c093929190611e87565b61016a6101c836600461180f565b610cd7565b600080846001600160a01b031663f30878c16040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102329190611eb7565b6040516359cffb9b60e11b81529091506001600160a01b0382169063b39ff736906102639088908890600401611edb565b602060405180830381865afa158015610280573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102a49190611eff565b156104e1576000856001600160a01b0316633035aa9c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061030d9190611eb7565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610357573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061037b9190611f1c565b6040516301057c4960e61b8152600481018890529091506001600160a01b0388169063415f12409060240160408051808303816000875af11580156103c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103e89190611f35565b6040516370a0823160e01b8152306004820152909550600091506001600160a01b038416906370a0823190602401602060405180830381865afa158015610433573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104579190611f1c565b9050818111156104dd576001600160a01b03831663a9059cbb8761047b8585611f6f565b6040518363ffffffff1660e01b8152600401610498929190611edb565b6020604051808303816000875af11580156104b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104db9190611eff565b505b5050505b509392505050565b60405163af800bf960e01b8152600481018490526024810183905281151560448201526060906001600160a01b0386169063af800bf9906064015b600060405180830381865afa158015610541573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261056991908101906124de565b95945050505050565b600061057e8383610df9565b90505b92915050565b6040516359df61a160e01b81526060906001600160a01b038616906359df61a190610524908790879087906004016125c0565b6105c2611670565b826001600160a01b031663f30878c16040518163ffffffff1660e01b8152600401602060405180830381865afa158015610600573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106249190611eb7565b6001600160a01b031663185cc75184846040518363ffffffff1660e01b8152600401610651929190611edb565b600060405180830381865afa15801561066e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261057e91908101906125e6565b6000806106a38484610ef1565b915091505b9250929050565b60606000866001600160a01b031663f30878c16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107159190611eb7565b6040516359cffb9b60e11b81529091506001600160a01b0382169063b39ff73690610746908a908a90600401611edb565b602060405180830381865afa158015610763573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107879190611eff565b15610a0a5783156107b85761271061079f8888610df9565b6107ab9061271261261a565b6107b59190612647565b94505b6000876001600160a01b0316633035aa9c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061081c9190611eb7565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610866573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061088a9190611f1c565b90506108978988336110c7565b604051633bfe638960e21b8152600481018990526001600160a01b038a169063eff98e24906024016000604051808303816000875af11580156108de573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109069190810190612669565b6040516370a0823160e01b8152306004820152909550600091506001600160a01b038416906370a0823190602401602060405180830381865afa158015610951573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109759190611f1c565b90506109828a86886111ac565b81811115610a06576001600160a01b03831663a9059cbb336109a48585611f6f565b6040518363ffffffff1660e01b81526004016109c1929190611edb565b6020604051808303816000875af11580156109e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a049190611eff565b505b5050505b5095945050505050565b6060806000610a248787876112d5565b5090935090508015610cae576000612710610a3f898461158b565b610a4b9061271261261a565b610a559190612647565b90506000886001600160a01b0316633035aa9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610abb9190611eb7565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610b05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b299190611f1c565b9050610b368a84336110c7565b604051638015d92560e01b81526001600160a01b038b1690638015d92590610b62908990600401611d9f565b6000604051808303816000875af1158015610b81573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ba99190810190612669565b6040516370a0823160e01b8152306004820152909650600091506001600160a01b038416906370a0823190602401602060405180830381865afa158015610bf4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c189190611f1c565b9050610c258b878a6111ac565b81811115610ca9576001600160a01b03831663a9059cbb33610c478585611f6f565b6040518363ffffffff1660e01b8152600401610c64929190611edb565b6020604051808303816000875af1158015610c83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca79190611eff565b505b505050505b5094509492505050565b6060600080610cc88686866112d5565b92509250925093509350939050565b60405163af800bf960e01b8152600481018490526024810183905281151560448201526060906000906001600160a01b0387169063af800bf990606401600060405180830381865afa158015610d31573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d5991908101906124de565b905080516001600160401b03811115610d7457610d74611f82565b604051908082528060200260200182016040528015610d9d578160200160208202803683370190505b50915060005b8151811015610def57818181518110610dbe57610dbe612705565b602002602001015160200151838281518110610ddc57610ddc612705565b6020908102919091010152600101610da3565b5050949350505050565b600080836001600160a01b031663f30878c16040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5e9190611eb7565b6001600160a01b031663185cc75185856040518363ffffffff1660e01b8152600401610e8b929190611edb565b600060405180830381865afa158015610ea8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ed091908101906125e6565b9050610ee9848260c001516001600160801b031661158b565b949350505050565b6000806000846001600160a01b031663f30878c16040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f589190611eb7565b6040516359cffb9b60e11b81529091506001600160a01b0382169063b39ff73690610f899088908890600401611edb565b602060405180830381865afa158015610fa6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fca9190611eff565b156110bf5760405163185cc75160e01b81526000906001600160a01b0383169063185cc751906110009089908990600401611edb565b600060405180830381865afa15801561101d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261104591908101906125e6565b90508060c001516001600160801b031693506110bb81610120015160018151811061107257611072612705565b60200260200101516001600160801b031682610120015160008151811061109b5761109b612705565b60200260200101516001600160801b03166110b6919061261a565b611612565b9250505b509250929050565b826001600160a01b0316633035aa9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611105573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111299190611eb7565b6040516323b872dd60e01b81526001600160a01b03838116600483015285811660248301526044820185905291909116906323b872dd906064016020604051808303816000875af1158015611182573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a69190611eff565b50505050565b6000836001600160a01b0316639d63848a6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156111ec573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611214919081019061271b565b905060005b83518110156112ce5781818151811061123457611234612705565b60200260200101516001600160a01b031663a9059cbb8486848151811061125d5761125d612705565b60200260200101516040518363ffffffff1660e01b8152600401611282929190611edb565b6020604051808303816000875af11580156112a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c59190611eff565b50600101611219565b5050505050565b60606000806000866001600160a01b031663f30878c16040518163ffffffff1660e01b8152600401602060405180830381865afa15801561131a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133e9190611eb7565b6001600160a01b0316637edd64b688888860016040518563ffffffff1660e01b8152600401611370949392919061274f565b600060405180830381865afa15801561138d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113b591908101906124de565b9050600081516001600160401b038111156113d2576113d2611f82565b6040519080825280602002602001820160405280156113fb578160200160208202803683370190505b5090506000611408611670565b60005b84518110156114ed5784818151811061142657611426612705565b602002602001015191506000826000015111156114e057816101c00151156114db57816020015184848151811061145f5761145f612705565b602090810291909101015260c0820151611482906001600160801b031688612787565b96506114c882610120015160018151811061149f5761149f612705565b60200260200101516001600160801b031683610120015160008151811061109b5761109b612705565b6114d29087612787565b95508260010192505b6114e5565b6114ed565b60010161140b565b50816001600160401b0381111561150657611506611f82565b60405190808252806020026020018201604052801561152f578160200160208202803683370190505b50965060005b875181101561157d5783818151811061155057611550612705565b602002602001015188828151811061156a5761156a612705565b6020908102919091010152600101611535565b505050505093509350939050565b6000806000846001600160a01b031663cd1891876040518163ffffffff1660e01b8152600401600060405180830381865afa1580156115ce573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115f6919081019061279a565b9250925050818185611608919061261a565b6105699190612647565b60006003821115611661575080600160028204015b8181101561165b5780915060028182858161164457611644612631565b04018161165357611653612631565b049050611627565b50919050565b811561166b575060015b919050565b604051806103e00160405280600081526020016000815260200160006001600160a01b0316815260200160006001600160601b0316815260200160006001600160801b0316815260200160006001600160801b0316815260200160006001600160801b0316815260200160008152602001600081526020016060815260200160006001600160a01b03168152602001600061ffff168152602001600060ff168152602001600081526020016000151581526020016000815260200160008152602001600081526020016060815260200160608152602001606081526020016060815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6001600160a01b03811681146117bc57600080fd5b50565b6000806000606084860312156117d457600080fd5b83356117df816117a7565b92506020840135915060408401356117f6816117a7565b809150509250925092565b80151581146117bc57600080fd5b6000806000806080858703121561182557600080fd5b8435611830816117a7565b93506020850135925060408501359150606085013561184e81611801565b939692955090935050565b600081518084526020808501945080840160005b838110156118925781516001600160801b03168752958201959082019060010161186d565b509495945050505050565b600081518084526020808501945080840160005b838110156118925781516001600160a01b0316875295820195908201906001016118b1565b600081518084526020808501945080840160005b8381101561189257815160ff16875295820195908201906001016118ea565b60005b8381101561192457818101518382015260200161190c565b50506000910152565b600081518084526020808501808196508360051b8101915082860160005b8581101561198d5782840389528151805180865261196e81888801898501611909565b99860199601f01601f191694909401850193509084019060010161194b565b5091979650505050505050565b60006103e0825184526020830151602085015260408301516119c760408601826001600160a01b03169052565b5060608301516119e260608601826001600160601b03169052565b5060808301516119fd60808601826001600160801b03169052565b5060a0830151611a1860a08601826001600160801b03169052565b5060c0830151611a3360c08601826001600160801b03169052565b5060e083015160e0850152610100808401518186015250610120808401518282870152611a6283870182611859565b9250505061014080840151611a81828701826001600160a01b03169052565b50506101608381015161ffff16908501526101808084015160ff16908501526101a080840151908501526101c0808401511515908501526101e08084015190850152610200808401519085015261022080840151908501526102408084015185830382870152611af1838261189d565b925050506102608084015185830382870152611b0d83826118d6565b925050506102808084015185830382870152611b29838261192d565b925050506102a08084015185830382870152611b45838261192d565b925050506102c080840151611b64828701826001600160a01b03169052565b50506102e0838101516001600160a01b031690850152610300808401519085015261032080840151908501526103408084015190850152610360808401519085015261038080840151908501526103a080840151908501526103c09283015192909301919091525090565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015611c2457603f19888603018452611c1285835161199a565b94509285019290850190600101611bf6565b5092979650505050505050565b60008060408385031215611c4457600080fd5b8235611c4f816117a7565b946020939093013593505050565b60008083601f840112611c6f57600080fd5b5081356001600160401b03811115611c8657600080fd5b6020830191508360208260051b85010111156106a857600080fd5b60008060008060608587031215611cb757600080fd5b8435611cc2816117a7565b935060208501356001600160401b03811115611cdd57600080fd5b611ce987828801611c5d565b909450925050604085013561184e81611801565b60208152600061057e602083018461199a565b600080600080600060a08688031215611d2857600080fd5b8535611d33816117a7565b945060208601359350604086013592506060860135611d5181611801565b91506080860135611d61816117a7565b809150509295509295909350565b600081518084526020808501945080840160005b8381101561189257815187529582019590820190600101611d83565b60208152600061057e6020830184611d6f565b60008060008060608587031215611dc857600080fd5b8435611dd3816117a7565b935060208501356001600160401b03811115611dee57600080fd5b611dfa87828801611c5d565b909450925050604085013561184e816117a7565b604081526000611e216040830185611d6f565b82810360208401526105698185611d6f565b600080600060408486031215611e4857600080fd5b8335611e53816117a7565b925060208401356001600160401b03811115611e6e57600080fd5b611e7a86828701611c5d565b9497909650939450505050565b606081526000611e9a6060830186611d6f565b60208301949094525060400152919050565b805161166b816117a7565b600060208284031215611ec957600080fd5b8151611ed4816117a7565b9392505050565b6001600160a01b03929092168252602082015260400190565b805161166b81611801565b600060208284031215611f1157600080fd5b8151611ed481611801565b600060208284031215611f2e57600080fd5b5051919050565b60008060408385031215611f4857600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b8181038181111561058157610581611f59565b634e487b7160e01b600052604160045260246000fd5b6040516103e081016001600160401b0381118282101715611fbb57611fbb611f82565b60405290565b604051601f8201601f191681016001600160401b0381118282101715611fe957611fe9611f82565b604052919050565b60006001600160401b0382111561200a5761200a611f82565b5060051b60200190565b80516001600160601b038116811461166b57600080fd5b80516001600160801b038116811461166b57600080fd5b600082601f83011261205357600080fd5b8151602061206861206383611ff1565b611fc1565b82815260059290921b8401810191818101908684111561208757600080fd5b8286015b848110156120a95761209c8161202b565b835291830191830161208b565b509695505050505050565b805161ffff8116811461166b57600080fd5b805160ff8116811461166b57600080fd5b600082601f8301126120e857600080fd5b815160206120f861206383611ff1565b82815260059290921b8401810191818101908684111561211757600080fd5b8286015b848110156120a957805161212e816117a7565b835291830191830161211b565b600082601f83011261214c57600080fd5b8151602061215c61206383611ff1565b82815260059290921b8401810191818101908684111561217b57600080fd5b8286015b848110156120a957612190816120c6565b835291830191830161217f565b6000601f83818401126121af57600080fd5b825160206121bf61206383611ff1565b82815260059290921b850181019181810190878411156121de57600080fd5b8287015b848110156122745780516001600160401b03808211156122025760008081fd5b818a0191508a603f8301126122175760008081fd5b8582015160408282111561222d5761222d611f82565b61223e828b01601f19168901611fc1565b92508183528c818386010111156122555760008081fd5b61226482898501838701611909565b50508452509183019183016121e2565b50979650505050505050565b60006103e0828403121561229357600080fd5b61229b611f98565b905081518152602082015160208201526122b760408301611eac565b60408201526122c860608301612014565b60608201526122d96080830161202b565b60808201526122ea60a0830161202b565b60a08201526122fb60c0830161202b565b60c082015260e082015160e0820152610100808301518183015250610120808301516001600160401b038082111561233257600080fd5b61233e86838701612042565b838501526101409250612352838601611eac565b8385015261016092506123668386016120b4565b83850152610180925061237a8386016120c6565b838501526101a0925082850151838501526101c0925061239b838601611ef4565b92840192909252506101e0838101519083015261020080840151908301526102208084015190830152610240808401519091808211156123da57600080fd5b6123e6868387016120d7565b8385015261026092508285015191508082111561240257600080fd5b61240e8683870161213b565b8385015261028092508285015191508082111561242a57600080fd5b6124368683870161219d565b838501526102a092508285015191508082111561245257600080fd5b5061245f8582860161219d565b8284015250506102c0612473818401611eac565b908201526102e0612485838201611eac565b90820152610300828101519082015261032080830151908201526103408083015190820152610360808301519082015261038080830151908201526103a080830151908201526103c09182015191810191909152919050565b600060208083850312156124f157600080fd5b82516001600160401b038082111561250857600080fd5b818501915085601f83011261251c57600080fd5b815161252a61206382611ff1565b81815260059190911b8301840190848101908883111561254957600080fd5b8585015b83811015612581578051858111156125655760008081fd5b6125738b89838a0101612280565b84525091860191860161254d565b5098975050505050505050565b81835260006001600160fb1b038311156125a757600080fd5b8260051b80836020870137939093016020019392505050565b6040815260006125d460408301858761258e565b90508215156020830152949350505050565b6000602082840312156125f857600080fd5b81516001600160401b0381111561260e57600080fd5b610ee984828501612280565b808202811582820484141761058157610581611f59565b634e487b7160e01b600052601260045260246000fd5b60008261266457634e487b7160e01b600052601260045260246000fd5b500490565b6000806040838503121561267c57600080fd5b825191506020808401516001600160401b0381111561269a57600080fd5b8401601f810186136126ab57600080fd5b80516126b961206382611ff1565b81815260059190911b820183019083810190888311156126d857600080fd5b928401925b828410156126f6578351825292840192908401906126dd565b80955050505050509250929050565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561272d57600080fd5b81516001600160401b0381111561274357600080fd5b610ee9848285016120d7565b6001600160a01b0385168152606060208201819052600090612774908301858761258e565b9050821515604083015295945050505050565b8082018082111561058157610581611f59565b6000806000606084860312156127af57600080fd5b83516001600160401b038111156127c557600080fd5b6127d186828701612042565b9350506020840151915060408401519050925092509256fea2646970667358221220b576600dcec3bd4a96e9fbf5c1706f2913ae80f30d88e418f4966b112887526864736f6c63430008150033

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061009e5760003560e01c8063b39ff73611610066578063b39ff7361461012f578063cd2a755d14610157578063dcf5843914610177578063f3b5b0b314610198578063f42b405d146101ba57600080fd5b80634914c008146100a3578063753a43d2146100c957806383f0454a146100e9578063912863aa146100fc578063a1c515861461010f575b600080fd5b6100b66100b13660046117bf565b6101cd565b6040519081526020015b60405180910390f35b6100dc6100d736600461180f565b6104e9565b6040516100c09190611bcf565b6100b66100f7366004611c31565b610572565b6100dc61010a366004611ca1565b610587565b61012261011d366004611c31565b6105ba565b6040516100c09190611cfd565b61014261013d366004611c31565b610696565b604080519283526020830191909152016100c0565b61016a610165366004611d10565b6106af565b6040516100c09190611d9f565b61018a610185366004611db2565b610a14565b6040516100c0929190611e0e565b6101ab6101a6366004611e33565b610cb8565b6040516100c093929190611e87565b61016a6101c836600461180f565b610cd7565b600080846001600160a01b031663f30878c16040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102329190611eb7565b6040516359cffb9b60e11b81529091506001600160a01b0382169063b39ff736906102639088908890600401611edb565b602060405180830381865afa158015610280573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102a49190611eff565b156104e1576000856001600160a01b0316633035aa9c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061030d9190611eb7565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610357573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061037b9190611f1c565b6040516301057c4960e61b8152600481018890529091506001600160a01b0388169063415f12409060240160408051808303816000875af11580156103c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103e89190611f35565b6040516370a0823160e01b8152306004820152909550600091506001600160a01b038416906370a0823190602401602060405180830381865afa158015610433573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104579190611f1c565b9050818111156104dd576001600160a01b03831663a9059cbb8761047b8585611f6f565b6040518363ffffffff1660e01b8152600401610498929190611edb565b6020604051808303816000875af11580156104b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104db9190611eff565b505b5050505b509392505050565b60405163af800bf960e01b8152600481018490526024810183905281151560448201526060906001600160a01b0386169063af800bf9906064015b600060405180830381865afa158015610541573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261056991908101906124de565b95945050505050565b600061057e8383610df9565b90505b92915050565b6040516359df61a160e01b81526060906001600160a01b038616906359df61a190610524908790879087906004016125c0565b6105c2611670565b826001600160a01b031663f30878c16040518163ffffffff1660e01b8152600401602060405180830381865afa158015610600573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106249190611eb7565b6001600160a01b031663185cc75184846040518363ffffffff1660e01b8152600401610651929190611edb565b600060405180830381865afa15801561066e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261057e91908101906125e6565b6000806106a38484610ef1565b915091505b9250929050565b60606000866001600160a01b031663f30878c16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107159190611eb7565b6040516359cffb9b60e11b81529091506001600160a01b0382169063b39ff73690610746908a908a90600401611edb565b602060405180830381865afa158015610763573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107879190611eff565b15610a0a5783156107b85761271061079f8888610df9565b6107ab9061271261261a565b6107b59190612647565b94505b6000876001600160a01b0316633035aa9c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061081c9190611eb7565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610866573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061088a9190611f1c565b90506108978988336110c7565b604051633bfe638960e21b8152600481018990526001600160a01b038a169063eff98e24906024016000604051808303816000875af11580156108de573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109069190810190612669565b6040516370a0823160e01b8152306004820152909550600091506001600160a01b038416906370a0823190602401602060405180830381865afa158015610951573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109759190611f1c565b90506109828a86886111ac565b81811115610a06576001600160a01b03831663a9059cbb336109a48585611f6f565b6040518363ffffffff1660e01b81526004016109c1929190611edb565b6020604051808303816000875af11580156109e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a049190611eff565b505b5050505b5095945050505050565b6060806000610a248787876112d5565b5090935090508015610cae576000612710610a3f898461158b565b610a4b9061271261261a565b610a559190612647565b90506000886001600160a01b0316633035aa9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610abb9190611eb7565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610b05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b299190611f1c565b9050610b368a84336110c7565b604051638015d92560e01b81526001600160a01b038b1690638015d92590610b62908990600401611d9f565b6000604051808303816000875af1158015610b81573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ba99190810190612669565b6040516370a0823160e01b8152306004820152909650600091506001600160a01b038416906370a0823190602401602060405180830381865afa158015610bf4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c189190611f1c565b9050610c258b878a6111ac565b81811115610ca9576001600160a01b03831663a9059cbb33610c478585611f6f565b6040518363ffffffff1660e01b8152600401610c64929190611edb565b6020604051808303816000875af1158015610c83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca79190611eff565b505b505050505b5094509492505050565b6060600080610cc88686866112d5565b92509250925093509350939050565b60405163af800bf960e01b8152600481018490526024810183905281151560448201526060906000906001600160a01b0387169063af800bf990606401600060405180830381865afa158015610d31573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d5991908101906124de565b905080516001600160401b03811115610d7457610d74611f82565b604051908082528060200260200182016040528015610d9d578160200160208202803683370190505b50915060005b8151811015610def57818181518110610dbe57610dbe612705565b602002602001015160200151838281518110610ddc57610ddc612705565b6020908102919091010152600101610da3565b5050949350505050565b600080836001600160a01b031663f30878c16040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5e9190611eb7565b6001600160a01b031663185cc75185856040518363ffffffff1660e01b8152600401610e8b929190611edb565b600060405180830381865afa158015610ea8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ed091908101906125e6565b9050610ee9848260c001516001600160801b031661158b565b949350505050565b6000806000846001600160a01b031663f30878c16040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f589190611eb7565b6040516359cffb9b60e11b81529091506001600160a01b0382169063b39ff73690610f899088908890600401611edb565b602060405180830381865afa158015610fa6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fca9190611eff565b156110bf5760405163185cc75160e01b81526000906001600160a01b0383169063185cc751906110009089908990600401611edb565b600060405180830381865afa15801561101d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261104591908101906125e6565b90508060c001516001600160801b031693506110bb81610120015160018151811061107257611072612705565b60200260200101516001600160801b031682610120015160008151811061109b5761109b612705565b60200260200101516001600160801b03166110b6919061261a565b611612565b9250505b509250929050565b826001600160a01b0316633035aa9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611105573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111299190611eb7565b6040516323b872dd60e01b81526001600160a01b03838116600483015285811660248301526044820185905291909116906323b872dd906064016020604051808303816000875af1158015611182573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a69190611eff565b50505050565b6000836001600160a01b0316639d63848a6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156111ec573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611214919081019061271b565b905060005b83518110156112ce5781818151811061123457611234612705565b60200260200101516001600160a01b031663a9059cbb8486848151811061125d5761125d612705565b60200260200101516040518363ffffffff1660e01b8152600401611282929190611edb565b6020604051808303816000875af11580156112a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c59190611eff565b50600101611219565b5050505050565b60606000806000866001600160a01b031663f30878c16040518163ffffffff1660e01b8152600401602060405180830381865afa15801561131a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133e9190611eb7565b6001600160a01b0316637edd64b688888860016040518563ffffffff1660e01b8152600401611370949392919061274f565b600060405180830381865afa15801561138d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113b591908101906124de565b9050600081516001600160401b038111156113d2576113d2611f82565b6040519080825280602002602001820160405280156113fb578160200160208202803683370190505b5090506000611408611670565b60005b84518110156114ed5784818151811061142657611426612705565b602002602001015191506000826000015111156114e057816101c00151156114db57816020015184848151811061145f5761145f612705565b602090810291909101015260c0820151611482906001600160801b031688612787565b96506114c882610120015160018151811061149f5761149f612705565b60200260200101516001600160801b031683610120015160008151811061109b5761109b612705565b6114d29087612787565b95508260010192505b6114e5565b6114ed565b60010161140b565b50816001600160401b0381111561150657611506611f82565b60405190808252806020026020018201604052801561152f578160200160208202803683370190505b50965060005b875181101561157d5783818151811061155057611550612705565b602002602001015188828151811061156a5761156a612705565b6020908102919091010152600101611535565b505050505093509350939050565b6000806000846001600160a01b031663cd1891876040518163ffffffff1660e01b8152600401600060405180830381865afa1580156115ce573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115f6919081019061279a565b9250925050818185611608919061261a565b6105699190612647565b60006003821115611661575080600160028204015b8181101561165b5780915060028182858161164457611644612631565b04018161165357611653612631565b049050611627565b50919050565b811561166b575060015b919050565b604051806103e00160405280600081526020016000815260200160006001600160a01b0316815260200160006001600160601b0316815260200160006001600160801b0316815260200160006001600160801b0316815260200160006001600160801b0316815260200160008152602001600081526020016060815260200160006001600160a01b03168152602001600061ffff168152602001600060ff168152602001600081526020016000151581526020016000815260200160008152602001600081526020016060815260200160608152602001606081526020016060815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6001600160a01b03811681146117bc57600080fd5b50565b6000806000606084860312156117d457600080fd5b83356117df816117a7565b92506020840135915060408401356117f6816117a7565b809150509250925092565b80151581146117bc57600080fd5b6000806000806080858703121561182557600080fd5b8435611830816117a7565b93506020850135925060408501359150606085013561184e81611801565b939692955090935050565b600081518084526020808501945080840160005b838110156118925781516001600160801b03168752958201959082019060010161186d565b509495945050505050565b600081518084526020808501945080840160005b838110156118925781516001600160a01b0316875295820195908201906001016118b1565b600081518084526020808501945080840160005b8381101561189257815160ff16875295820195908201906001016118ea565b60005b8381101561192457818101518382015260200161190c565b50506000910152565b600081518084526020808501808196508360051b8101915082860160005b8581101561198d5782840389528151805180865261196e81888801898501611909565b99860199601f01601f191694909401850193509084019060010161194b565b5091979650505050505050565b60006103e0825184526020830151602085015260408301516119c760408601826001600160a01b03169052565b5060608301516119e260608601826001600160601b03169052565b5060808301516119fd60808601826001600160801b03169052565b5060a0830151611a1860a08601826001600160801b03169052565b5060c0830151611a3360c08601826001600160801b03169052565b5060e083015160e0850152610100808401518186015250610120808401518282870152611a6283870182611859565b9250505061014080840151611a81828701826001600160a01b03169052565b50506101608381015161ffff16908501526101808084015160ff16908501526101a080840151908501526101c0808401511515908501526101e08084015190850152610200808401519085015261022080840151908501526102408084015185830382870152611af1838261189d565b925050506102608084015185830382870152611b0d83826118d6565b925050506102808084015185830382870152611b29838261192d565b925050506102a08084015185830382870152611b45838261192d565b925050506102c080840151611b64828701826001600160a01b03169052565b50506102e0838101516001600160a01b031690850152610300808401519085015261032080840151908501526103408084015190850152610360808401519085015261038080840151908501526103a080840151908501526103c09283015192909301919091525090565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015611c2457603f19888603018452611c1285835161199a565b94509285019290850190600101611bf6565b5092979650505050505050565b60008060408385031215611c4457600080fd5b8235611c4f816117a7565b946020939093013593505050565b60008083601f840112611c6f57600080fd5b5081356001600160401b03811115611c8657600080fd5b6020830191508360208260051b85010111156106a857600080fd5b60008060008060608587031215611cb757600080fd5b8435611cc2816117a7565b935060208501356001600160401b03811115611cdd57600080fd5b611ce987828801611c5d565b909450925050604085013561184e81611801565b60208152600061057e602083018461199a565b600080600080600060a08688031215611d2857600080fd5b8535611d33816117a7565b945060208601359350604086013592506060860135611d5181611801565b91506080860135611d61816117a7565b809150509295509295909350565b600081518084526020808501945080840160005b8381101561189257815187529582019590820190600101611d83565b60208152600061057e6020830184611d6f565b60008060008060608587031215611dc857600080fd5b8435611dd3816117a7565b935060208501356001600160401b03811115611dee57600080fd5b611dfa87828801611c5d565b909450925050604085013561184e816117a7565b604081526000611e216040830185611d6f565b82810360208401526105698185611d6f565b600080600060408486031215611e4857600080fd5b8335611e53816117a7565b925060208401356001600160401b03811115611e6e57600080fd5b611e7a86828701611c5d565b9497909650939450505050565b606081526000611e9a6060830186611d6f565b60208301949094525060400152919050565b805161166b816117a7565b600060208284031215611ec957600080fd5b8151611ed4816117a7565b9392505050565b6001600160a01b03929092168252602082015260400190565b805161166b81611801565b600060208284031215611f1157600080fd5b8151611ed481611801565b600060208284031215611f2e57600080fd5b5051919050565b60008060408385031215611f4857600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b8181038181111561058157610581611f59565b634e487b7160e01b600052604160045260246000fd5b6040516103e081016001600160401b0381118282101715611fbb57611fbb611f82565b60405290565b604051601f8201601f191681016001600160401b0381118282101715611fe957611fe9611f82565b604052919050565b60006001600160401b0382111561200a5761200a611f82565b5060051b60200190565b80516001600160601b038116811461166b57600080fd5b80516001600160801b038116811461166b57600080fd5b600082601f83011261205357600080fd5b8151602061206861206383611ff1565b611fc1565b82815260059290921b8401810191818101908684111561208757600080fd5b8286015b848110156120a95761209c8161202b565b835291830191830161208b565b509695505050505050565b805161ffff8116811461166b57600080fd5b805160ff8116811461166b57600080fd5b600082601f8301126120e857600080fd5b815160206120f861206383611ff1565b82815260059290921b8401810191818101908684111561211757600080fd5b8286015b848110156120a957805161212e816117a7565b835291830191830161211b565b600082601f83011261214c57600080fd5b8151602061215c61206383611ff1565b82815260059290921b8401810191818101908684111561217b57600080fd5b8286015b848110156120a957612190816120c6565b835291830191830161217f565b6000601f83818401126121af57600080fd5b825160206121bf61206383611ff1565b82815260059290921b850181019181810190878411156121de57600080fd5b8287015b848110156122745780516001600160401b03808211156122025760008081fd5b818a0191508a603f8301126122175760008081fd5b8582015160408282111561222d5761222d611f82565b61223e828b01601f19168901611fc1565b92508183528c818386010111156122555760008081fd5b61226482898501838701611909565b50508452509183019183016121e2565b50979650505050505050565b60006103e0828403121561229357600080fd5b61229b611f98565b905081518152602082015160208201526122b760408301611eac565b60408201526122c860608301612014565b60608201526122d96080830161202b565b60808201526122ea60a0830161202b565b60a08201526122fb60c0830161202b565b60c082015260e082015160e0820152610100808301518183015250610120808301516001600160401b038082111561233257600080fd5b61233e86838701612042565b838501526101409250612352838601611eac565b8385015261016092506123668386016120b4565b83850152610180925061237a8386016120c6565b838501526101a0925082850151838501526101c0925061239b838601611ef4565b92840192909252506101e0838101519083015261020080840151908301526102208084015190830152610240808401519091808211156123da57600080fd5b6123e6868387016120d7565b8385015261026092508285015191508082111561240257600080fd5b61240e8683870161213b565b8385015261028092508285015191508082111561242a57600080fd5b6124368683870161219d565b838501526102a092508285015191508082111561245257600080fd5b5061245f8582860161219d565b8284015250506102c0612473818401611eac565b908201526102e0612485838201611eac565b90820152610300828101519082015261032080830151908201526103408083015190820152610360808301519082015261038080830151908201526103a080830151908201526103c09182015191810191909152919050565b600060208083850312156124f157600080fd5b82516001600160401b038082111561250857600080fd5b818501915085601f83011261251c57600080fd5b815161252a61206382611ff1565b81815260059190911b8301840190848101908883111561254957600080fd5b8585015b83811015612581578051858111156125655760008081fd5b6125738b89838a0101612280565b84525091860191860161254d565b5098975050505050505050565b81835260006001600160fb1b038311156125a757600080fd5b8260051b80836020870137939093016020019392505050565b6040815260006125d460408301858761258e565b90508215156020830152949350505050565b6000602082840312156125f857600080fd5b81516001600160401b0381111561260e57600080fd5b610ee984828501612280565b808202811582820484141761058157610581611f59565b634e487b7160e01b600052601260045260246000fd5b60008261266457634e487b7160e01b600052601260045260246000fd5b500490565b6000806040838503121561267c57600080fd5b825191506020808401516001600160401b0381111561269a57600080fd5b8401601f810186136126ab57600080fd5b80516126b961206382611ff1565b81815260059190911b820183019083810190888311156126d857600080fd5b928401925b828410156126f6578351825292840192908401906126dd565b80955050505050509250929050565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561272d57600080fd5b81516001600160401b0381111561274357600080fd5b610ee9848285016120d7565b6001600160a01b0385168152606060208201819052600090612774908301858761258e565b9050821515604083015295945050505050565b8082018082111561058157610581611f59565b6000806000606084860312156127af57600080fd5b83516001600160401b038111156127c557600080fd5b6127d186828701612042565b9350506020840151915060408401519050925092509256fea2646970667358221220b576600dcec3bd4a96e9fbf5c1706f2913ae80f30d88e418f4966b112887526864736f6c63430008150033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

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.