Contract

0x71F177e42cBAbaD75d1393e485B60FeC8e815f3b

Overview

S Balance

Sonic LogoSonic LogoSonic Logo0 S

S Value

-

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Parent Transaction Hash Block From To
4342942024-12-15 7:50:0820 days ago1734249008  Contract Creation0 S
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
FluidVaultT1Admin

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 10000000 runs

Other Settings:
paris EvmVersion
File 1 of 11 : main.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

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

import { Variables } from "../common/variables.sol";
import { Events } from "./events.sol";
import { ErrorTypes } from "../../errorTypes.sol";
import { Error } from "../../error.sol";
import { IFluidVaultT1 } from "../../interfaces/iVaultT1.sol";
import { BigMathMinified } from "../../../../libraries/bigMathMinified.sol";
import { TickMath } from "../../../../libraries/tickMath.sol";
import { SafeTransfer } from "../../../../libraries/safeTransfer.sol";

/// @notice Fluid Vault protocol Admin Module contract.
///         Implements admin related methods to set configs such as liquidation params, rates
///         oracle address etc.
///         Methods are limited to be called via delegateCall only. Vault CoreModule ("VaultT1" contract)
///         is expected to call the methods implemented here after checking the msg.sender is authorized.
///         All methods update the exchange prices in storage before changing configs.
contract FluidVaultT1Admin is Variables, Events, Error {
    uint private constant X8 = 0xff;
    uint private constant X10 = 0x3ff;
    uint private constant X16 = 0xffff;
    uint private constant X19 = 0x7ffff;
    uint private constant X24 = 0xffffff;
    uint internal constant X64 = 0xffffffffffffffff;
    uint private constant X96 = 0xffffffffffffffffffffffff;
    address private constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

    address private immutable addressThis;

    constructor() {
        addressThis = address(this);
    }

    modifier _verifyCaller() {
        if (address(this) == addressThis) {
            revert FluidVaultError(ErrorTypes.VaultAdmin__OnlyDelegateCallAllowed);
        }
        _;
    }

    /// @dev updates exchange price on storage, called on all admin methods in combination with _verifyCaller modifier so
    /// only called by authorized delegatecall
    modifier _updateExchangePrice() {
        IFluidVaultT1(address(this)).updateExchangePricesOnStorage();
        _;
    }

    function _checkLiquidationMaxLimitAndPenalty(uint liquidationMaxLimit_, uint liquidationPenalty_) private pure {
        // liquidation max limit with penalty should not go above 99.7%
        // As liquidation with penalty can happen from liquidation Threshold to max limit
        // If it goes above 100% than that means liquidator is getting more collateral than user's available
        if ((liquidationMaxLimit_ + liquidationPenalty_) > 9970) {
            revert FluidVaultError(ErrorTypes.VaultAdmin__ValueAboveLimit);
        }
    }

    /// @notice updates the supply rate magnifier to `supplyRateMagnifier_`. Input in 1e2 (1% = 100, 100% = 10_000).
    function updateSupplyRateMagnifier(uint supplyRateMagnifier_) public _updateExchangePrice _verifyCaller {
        emit LogUpdateSupplyRateMagnifier(supplyRateMagnifier_);

        if (supplyRateMagnifier_ > X16) revert FluidVaultError(ErrorTypes.VaultAdmin__ValueAboveLimit);

        vaultVariables2 =
            (vaultVariables2 & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000) |
            supplyRateMagnifier_;
    }

    /// @notice updates the borrow rate magnifier to `borrowRateMagnifier_`. Input in 1e2 (1% = 100, 100% = 10_000).
    function updateBorrowRateMagnifier(uint borrowRateMagnifier_) public _updateExchangePrice _verifyCaller {
        emit LogUpdateBorrowRateMagnifier(borrowRateMagnifier_);

        if (borrowRateMagnifier_ > X16) revert FluidVaultError(ErrorTypes.VaultAdmin__ValueAboveLimit);

        vaultVariables2 =
            (vaultVariables2 & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffff) |
            (borrowRateMagnifier_ << 16);
    }

    /// @notice updates the collateral factor to `collateralFactor_`. Input in 1e2 (1% = 100, 100% = 10_000).
    function updateCollateralFactor(uint collateralFactor_) public _updateExchangePrice _verifyCaller {
        emit LogUpdateCollateralFactor(collateralFactor_);

        uint vaultVariables2_ = vaultVariables2;
        uint liquidationThreshold_ = ((vaultVariables2_ >> 42) & X10);

        collateralFactor_ = collateralFactor_ / 10;

        if (collateralFactor_ >= liquidationThreshold_) revert FluidVaultError(ErrorTypes.VaultAdmin__ValueAboveLimit);

        vaultVariables2 =
            (vaultVariables2_ & 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffc00ffffffff) |
            (collateralFactor_ << 32);
    }

    /// @notice updates the liquidation threshold to `liquidationThreshold_`. Input in 1e2 (1% = 100, 100% = 10_000).
    function updateLiquidationThreshold(uint liquidationThreshold_) public _updateExchangePrice _verifyCaller {
        emit LogUpdateLiquidationThreshold(liquidationThreshold_);

        uint vaultVariables2_ = vaultVariables2;
        uint collateralFactor_ = ((vaultVariables2_ >> 32) & X10);
        uint liquidationMaxLimit_ = ((vaultVariables2_ >> 52) & X10);

        liquidationThreshold_ = liquidationThreshold_ / 10;

        if ((collateralFactor_ >= liquidationThreshold_) || (liquidationThreshold_ >= liquidationMaxLimit_))
            revert FluidVaultError(ErrorTypes.VaultAdmin__ValueAboveLimit);

        vaultVariables2 =
            (vaultVariables2_ & 0xfffffffffffffffffffffffffffffffffffffffffffffffffff003ffffffffff) |
            (liquidationThreshold_ << 42);
    }

    /// @notice updates the liquidation max limit to `liquidationMaxLimit_`. Input in 1e2 (1% = 100, 100% = 10_000).
    function updateLiquidationMaxLimit(uint liquidationMaxLimit_) public _updateExchangePrice _verifyCaller {
        emit LogUpdateLiquidationMaxLimit(liquidationMaxLimit_);

        uint vaultVariables2_ = vaultVariables2;
        uint liquidationThreshold_ = ((vaultVariables2_ >> 42) & X10);
        uint liquidationPenalty_ = ((vaultVariables2_ >> 72) & X10);

        // both are in 1e2 decimals (1e2 = 1%)
        _checkLiquidationMaxLimitAndPenalty(liquidationMaxLimit_, liquidationPenalty_);

        liquidationMaxLimit_ = liquidationMaxLimit_ / 10;

        if (liquidationThreshold_ >= liquidationMaxLimit_)
            revert FluidVaultError(ErrorTypes.VaultAdmin__ValueAboveLimit);

        vaultVariables2 =
            (vaultVariables2_ & 0xffffffffffffffffffffffffffffffffffffffffffffffffc00fffffffffffff) |
            (liquidationMaxLimit_ << 52);
    }

    /// @notice updates the withdrawal gap to `withdrawGap_`. Input in 1e2 (1% = 100, 100% = 10_000).
    function updateWithdrawGap(uint withdrawGap_) public _updateExchangePrice _verifyCaller {
        emit LogUpdateWithdrawGap(withdrawGap_);

        withdrawGap_ = withdrawGap_ / 10;

        // withdrawGap must not be > 100%
        if (withdrawGap_ > 1000) revert FluidVaultError(ErrorTypes.VaultAdmin__ValueAboveLimit);

        vaultVariables2 =
            (vaultVariables2 & 0xffffffffffffffffffffffffffffffffffffffffffffff003fffffffffffffff) |
            (withdrawGap_ << 62);
    }

    /// @notice updates the liquidation penalty to `liquidationPenalty_`. Input in 1e2 (1% = 100, 100% = 10_000).
    function updateLiquidationPenalty(uint liquidationPenalty_) public _updateExchangePrice _verifyCaller {
        emit LogUpdateLiquidationPenalty(liquidationPenalty_);

        uint vaultVariables2_ = vaultVariables2;
        uint liquidationMaxLimit_ = ((vaultVariables2_ >> 52) & X10);

        // Converting liquidationMaxLimit_ in 1e2 decimals (1e2 = 1%)
        _checkLiquidationMaxLimitAndPenalty((liquidationMaxLimit_ * 10), liquidationPenalty_);

        if (liquidationPenalty_ > X10) revert FluidVaultError(ErrorTypes.VaultAdmin__ValueAboveLimit);

        vaultVariables2 =
            (vaultVariables2_ & 0xfffffffffffffffffffffffffffffffffffffffffffc00ffffffffffffffffff) |
            (liquidationPenalty_ << 72);
    }

    /// @notice updates the borrow fee to `borrowFee_`. Input in 1e2 (1% = 100, 100% = 10_000).
    function updateBorrowFee(uint borrowFee_) public _updateExchangePrice _verifyCaller {
        emit LogUpdateBorrowFee(borrowFee_);

        if (borrowFee_ > X10) revert FluidVaultError(ErrorTypes.VaultAdmin__ValueAboveLimit);

        vaultVariables2 =
            (vaultVariables2 & 0xfffffffffffffffffffffffffffffffffffffffff003ffffffffffffffffffff) |
            (borrowFee_ << 82);
    }

    /// @notice updates the all Vault core settings according to input params.
    /// All input values are expected in 1e2 (1% = 100, 100% = 10_000).
    function updateCoreSettings(
        uint256 supplyRateMagnifier_,
        uint256 borrowRateMagnifier_,
        uint256 collateralFactor_,
        uint256 liquidationThreshold_,
        uint256 liquidationMaxLimit_,
        uint256 withdrawGap_,
        uint256 liquidationPenalty_,
        uint256 borrowFee_
    ) public _updateExchangePrice _verifyCaller {
        // emitting the event at the start as then we are updating numbers to store in a more optimized way
        emit LogUpdateCoreSettings(
            supplyRateMagnifier_,
            borrowRateMagnifier_,
            collateralFactor_,
            liquidationThreshold_,
            liquidationMaxLimit_,
            withdrawGap_,
            liquidationPenalty_,
            borrowFee_
        );

        _checkLiquidationMaxLimitAndPenalty(liquidationMaxLimit_, liquidationPenalty_);

        collateralFactor_ = collateralFactor_ / 10;
        liquidationThreshold_ = liquidationThreshold_ / 10;
        liquidationMaxLimit_ = liquidationMaxLimit_ / 10;
        withdrawGap_ = withdrawGap_ / 10;

        if (
            (supplyRateMagnifier_ > X16) ||
            (borrowRateMagnifier_ > X16) ||
            (collateralFactor_ >= liquidationThreshold_) ||
            (liquidationThreshold_ >= liquidationMaxLimit_) ||
            (withdrawGap_ > X10) ||
            (liquidationPenalty_ > X10) ||
            (borrowFee_ > X10)
        ) {
            revert FluidVaultError(ErrorTypes.VaultAdmin__ValueAboveLimit);
        }

        vaultVariables2 =
            (vaultVariables2 & 0xfffffffffffffffffffffffffffffffffffffffff00000000000000000000000) |
            supplyRateMagnifier_ |
            (borrowRateMagnifier_ << 16) |
            (collateralFactor_ << 32) |
            (liquidationThreshold_ << 42) |
            (liquidationMaxLimit_ << 52) |
            (withdrawGap_ << 62) |
            (liquidationPenalty_ << 72) |
            (borrowFee_ << 82);
    }

    /// @notice updates the Vault oracle to `newOracle_`. Must implement the FluidOracle interface.
    function updateOracle(address newOracle_) public _updateExchangePrice _verifyCaller {
        if (newOracle_ == address(0)) revert FluidVaultError(ErrorTypes.VaultAdmin__AddressZeroNotAllowed);

        // Removing current oracle by masking only first 96 bits then inserting new oracle as bits
        vaultVariables2 = (vaultVariables2 & X96) | (uint256(uint160(newOracle_)) << 96);

        emit LogUpdateOracle(newOracle_);
    }

    /// @notice updates the allowed rebalancer to `newRebalancer_`.
    function updateRebalancer(address newRebalancer_) public _updateExchangePrice _verifyCaller {
        if (newRebalancer_ == address(0)) revert FluidVaultError(ErrorTypes.VaultAdmin__AddressZeroNotAllowed);

        rebalancer = newRebalancer_;

        emit LogUpdateRebalancer(newRebalancer_);
    }

    /// @notice sends any potentially stuck funds to Liquidity contract.
    /// @dev this contract never holds any funds as all operations send / receive funds from user <-> Liquidity.
    function rescueFunds(address token_) external _verifyCaller {
        if (token_ == NATIVE_TOKEN) {
            SafeTransfer.safeTransferNative(IFluidVaultT1(address(this)).LIQUIDITY(), address(this).balance);
        } else {
            SafeTransfer.safeTransfer(
                token_,
                IFluidVaultT1(address(this)).LIQUIDITY(),
                IERC20(token_).balanceOf(address(this))
            );
        }

        emit LogRescueFunds(token_);
    }

    /// @notice absorbs accumulated dust debt
    /// @dev in decades if a lot of positions are 100% liquidated (aka absorbed) then dust debt can mount up
    /// which is basically sort of an extra revenue for the protocol.
    //
    // this function might never come in use that's why adding it in admin module
    function absorbDustDebt(uint[] memory nftIds_) public _verifyCaller {
        uint256 vaultVariables_ = vaultVariables;
        // re-entrancy check
        if (vaultVariables_ & 1 == 0) {
            // Updating on storage
            vaultVariables = vaultVariables_ | 1;
        } else {
            revert FluidVaultError(ErrorTypes.Vault__AlreadyEntered);
        }

        uint nftId_;
        uint posData_;
        int posTick_;
        uint tickId_;
        uint posCol_;
        uint posDebt_;
        uint posDustDebt_;
        uint tickData_;

        uint absorbedDustDebt_ = absorbedDustDebt;

        for (uint i = 0; i < nftIds_.length; ) {
            nftId_ = nftIds_[i];
            if (nftId_ == 0) {
                revert FluidVaultError(ErrorTypes.VaultAdmin__NftIdShouldBeNonZero);
            }

            // user's position data
            posData_ = positionData[nftId_];

            if (posData_ == 0) {
                revert FluidVaultError(ErrorTypes.VaultAdmin__NftNotOfThisVault);
            }

            posCol_ = (posData_ >> 45) & X64;
            // Converting big number into normal number
            posCol_ = (posCol_ >> 8) << (posCol_ & X8);

            posDustDebt_ = (posData_ >> 109) & X64;
            // Converting big number into normal number
            posDustDebt_ = (posDustDebt_ >> 8) << (posDustDebt_ & X8);

            if (posDustDebt_ == 0) {
                revert FluidVaultError(ErrorTypes.VaultAdmin__DustDebtIsZero);
            }

            // borrow position (has collateral & debt)
            posTick_ = posData_ & 2 == 2 ? int((posData_ >> 2) & X19) : -int((posData_ >> 2) & X19);
            tickId_ = (posData_ >> 21) & X24;

            posDebt_ = (TickMath.getRatioAtTick(int24(posTick_)) * posCol_) >> 96;

            // Tick data from user's tick
            tickData_ = tickData[posTick_];

            // Checking if tick is liquidated OR if the total IDs of tick is greater than user's tick ID
            if (((tickData_ & 1) == 1) || (((tickData_ >> 1) & X24) > tickId_)) {
                // User got liquidated
                (, posDebt_, , , ) = IFluidVaultT1(address(this)).fetchLatestPosition(
                    posTick_,
                    tickId_,
                    posDebt_,
                    tickData_
                );
                if (posDebt_ > 0) {
                    revert FluidVaultError(ErrorTypes.VaultAdmin__FinalDebtShouldBeZero);
                }
                // absorbing user's debt as it's 100% or almost 100% liquidated
                absorbedDustDebt_ = absorbedDustDebt_ + posDustDebt_;
                // making position as supply only
                positionData[nftId_] = 1;
            } else {
                revert FluidVaultError(ErrorTypes.VaultAdmin__NftNotLiquidated);
            }

            unchecked {
                i++;
            }
        }

        if (absorbedDustDebt_ == 0) {
            revert FluidVaultError(ErrorTypes.VaultAdmin__AbsorbedDustDebtIsZero);
        }

        uint totalBorrow_ = (vaultVariables_ >> 146) & X64;
        // Converting big number into normal number
        totalBorrow_ = (totalBorrow_ >> 8) << (totalBorrow_ & X8);
        // note: by default dust debt is not added into total borrow but on 100% liquidation (aka absorb) dust debt equivalent
        // is removed from total borrow so adding it back again here
        totalBorrow_ = totalBorrow_ + absorbedDustDebt_;
        totalBorrow_ = BigMathMinified.toBigNumber(totalBorrow_, 56, 8, BigMathMinified.ROUND_UP);

        // adding absorbed dust debt to total borrow so it will get included in the next rebalancing.
        // there is some fuzziness here as when the position got fully liquidated (aka absorbed) the exchange price was different
        // than what it'll be now. The fuzziness which will be extremely small so we can ignore it
        // updating on storage
        vaultVariables =
            (vaultVariables_ & 0xfffffffffffc0000000000000003ffffffffffffffffffffffffffffffffffff) |
            (totalBorrow_ << 146);

        // updating on storage
        absorbedDustDebt = 0;

        emit LogAbsorbDustDebt(nftIds_, absorbedDustDebt_);
    }
}

File 2 of 11 : IERC20.sol
// 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);
}

File 3 of 11 : bigMathMinified.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

/// @title library that represents a number in BigNumber(coefficient and exponent) format to store in smaller bits.
/// @notice the number is divided into two parts: a coefficient and an exponent. This comes at a cost of losing some precision
/// at the end of the number because the exponent simply fills it with zeroes. This precision is oftentimes negligible and can
/// result in significant gas cost reduction due to storage space reduction.
/// Also note, a valid big number is as follows: if the exponent is > 0, then coefficient last bits should be occupied to have max precision.
/// @dev roundUp is more like a increase 1, which happens everytime for the same number.
/// roundDown simply sets trailing digits after coefficientSize to zero (floor), only once for the same number.
library BigMathMinified {
    /// @dev constants to use for `roundUp` input param to increase readability
    bool internal constant ROUND_DOWN = false;
    bool internal constant ROUND_UP = true;

    /// @dev converts `normal` number to BigNumber with `exponent` and `coefficient` (or precision).
    /// e.g.:
    /// 5035703444687813576399599 (normal) = (coefficient[32bits], exponent[8bits])[40bits]
    /// 5035703444687813576399599 (decimal) => 10000101010010110100000011111011110010100110100000000011100101001101001101011101111 (binary)
    ///                                     => 10000101010010110100000011111011000000000000000000000000000000000000000000000000000
    ///                                                                        ^-------------------- 51(exponent) -------------- ^
    /// coefficient = 1000,0101,0100,1011,0100,0000,1111,1011               (2236301563)
    /// exponent =                                            0011,0011     (51)
    /// bigNumber =   1000,0101,0100,1011,0100,0000,1111,1011,0011,0011     (572493200179)
    ///
    /// @param normal number which needs to be converted into Big Number
    /// @param coefficientSize at max how many bits of precision there should be (64 = uint64 (64 bits precision))
    /// @param exponentSize at max how many bits of exponent there should be (8 = uint8 (8 bits exponent))
    /// @param roundUp signals if result should be rounded down or up
    /// @return bigNumber converted bigNumber (coefficient << exponent)
    function toBigNumber(
        uint256 normal,
        uint256 coefficientSize,
        uint256 exponentSize,
        bool roundUp
    ) internal pure returns (uint256 bigNumber) {
        assembly {
            let lastBit_
            let number_ := normal
            if gt(number_, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {
                number_ := shr(0x80, number_)
                lastBit_ := 0x80
            }
            if gt(number_, 0xFFFFFFFFFFFFFFFF) {
                number_ := shr(0x40, number_)
                lastBit_ := add(lastBit_, 0x40)
            }
            if gt(number_, 0xFFFFFFFF) {
                number_ := shr(0x20, number_)
                lastBit_ := add(lastBit_, 0x20)
            }
            if gt(number_, 0xFFFF) {
                number_ := shr(0x10, number_)
                lastBit_ := add(lastBit_, 0x10)
            }
            if gt(number_, 0xFF) {
                number_ := shr(0x8, number_)
                lastBit_ := add(lastBit_, 0x8)
            }
            if gt(number_, 0xF) {
                number_ := shr(0x4, number_)
                lastBit_ := add(lastBit_, 0x4)
            }
            if gt(number_, 0x3) {
                number_ := shr(0x2, number_)
                lastBit_ := add(lastBit_, 0x2)
            }
            if gt(number_, 0x1) {
                lastBit_ := add(lastBit_, 1)
            }
            if gt(number_, 0) {
                lastBit_ := add(lastBit_, 1)
            }
            if lt(lastBit_, coefficientSize) {
                // for throw exception
                lastBit_ := coefficientSize
            }
            let exponent := sub(lastBit_, coefficientSize)
            let coefficient := shr(exponent, normal)
            if and(roundUp, gt(exponent, 0)) {
                // rounding up is only needed if exponent is > 0, as otherwise the coefficient fully holds the original number
                coefficient := add(coefficient, 1)
                if eq(shl(coefficientSize, 1), coefficient) {
                    // case were coefficient was e.g. 111, with adding 1 it became 1000 (in binary) and coefficientSize 3 bits
                    // final coefficient would exceed it's size. -> reduce coefficent to 100 and increase exponent by 1.
                    coefficient := shl(sub(coefficientSize, 1), 1)
                    exponent := add(exponent, 1)
                }
            }
            if iszero(lt(exponent, shl(exponentSize, 1))) {
                // if exponent is >= exponentSize, the normal number is too big to fit within
                // BigNumber with too small sizes for coefficient and exponent
                revert(0, 0)
            }
            bigNumber := shl(exponentSize, coefficient)
            bigNumber := add(bigNumber, exponent)
        }
    }

    /// @dev get `normal` number from `bigNumber`, `exponentSize` and `exponentMask`
    function fromBigNumber(
        uint256 bigNumber,
        uint256 exponentSize,
        uint256 exponentMask
    ) internal pure returns (uint256 normal) {
        assembly {
            let coefficient := shr(exponentSize, bigNumber)
            let exponent := and(bigNumber, exponentMask)
            normal := shl(exponent, coefficient)
        }
    }

    /// @dev gets the most significant bit `lastBit` of a `normal` number (length of given number of binary format).
    /// e.g.
    /// 5035703444687813576399599 = 10000101010010110100000011111011110010100110100000000011100101001101001101011101111
    /// lastBit =                   ^---------------------------------   83   ----------------------------------------^
    function mostSignificantBit(uint256 normal) internal pure returns (uint lastBit) {
        assembly {
            let number_ := normal
            if gt(normal, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {
                number_ := shr(0x80, number_)
                lastBit := 0x80
            }
            if gt(number_, 0xFFFFFFFFFFFFFFFF) {
                number_ := shr(0x40, number_)
                lastBit := add(lastBit, 0x40)
            }
            if gt(number_, 0xFFFFFFFF) {
                number_ := shr(0x20, number_)
                lastBit := add(lastBit, 0x20)
            }
            if gt(number_, 0xFFFF) {
                number_ := shr(0x10, number_)
                lastBit := add(lastBit, 0x10)
            }
            if gt(number_, 0xFF) {
                number_ := shr(0x8, number_)
                lastBit := add(lastBit, 0x8)
            }
            if gt(number_, 0xF) {
                number_ := shr(0x4, number_)
                lastBit := add(lastBit, 0x4)
            }
            if gt(number_, 0x3) {
                number_ := shr(0x2, number_)
                lastBit := add(lastBit, 0x2)
            }
            if gt(number_, 0x1) {
                lastBit := add(lastBit, 1)
            }
            if gt(number_, 0) {
                lastBit := add(lastBit, 1)
            }
        }
    }
}

File 4 of 11 : errorTypes.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

library LibsErrorTypes {
    /***********************************|
    |         LiquidityCalcs            | 
    |__________________________________*/

    /// @notice thrown when supply or borrow exchange price is zero at calc token data (token not configured yet)
    uint256 internal constant LiquidityCalcs__ExchangePriceZero = 70001;

    /// @notice thrown when rate data is set to a version that is not implemented
    uint256 internal constant LiquidityCalcs__UnsupportedRateVersion = 70002;

    /// @notice thrown when the calculated borrow rate turns negative. This should never happen.
    uint256 internal constant LiquidityCalcs__BorrowRateNegative = 70003;

    /***********************************|
    |           SafeTransfer            | 
    |__________________________________*/

    /// @notice thrown when safe transfer from for an ERC20 fails
    uint256 internal constant SafeTransfer__TransferFromFailed = 71001;

    /// @notice thrown when safe transfer for an ERC20 fails
    uint256 internal constant SafeTransfer__TransferFailed = 71002;

    /***********************************|
    |           SafeApprove             | 
    |__________________________________*/

    /// @notice thrown when safe approve from for an ERC20 fails
    uint256 internal constant SafeApprove__ApproveFailed = 81001;
}

File 5 of 11 : safeTransfer.sol
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.21;

import { LibsErrorTypes as ErrorTypes } from "./errorTypes.sol";

/// @notice provides minimalistic methods for safe transfers, e.g. ERC20 safeTransferFrom
library SafeTransfer {
    uint256 internal constant MAX_NATIVE_TRANSFER_GAS = 20000; // pass max. 20k gas for native transfers

    error FluidSafeTransferError(uint256 errorId_);

    /// @dev Transfer `amount_` of `token_` from `from_` to `to_`, spending the approval given by `from_` to the
    /// calling contract. If `token_` returns no value, non-reverting calls are assumed to be successful.
    /// Minimally modified from Solmate SafeTransferLib (address as input param for token, Custom Error):
    /// https://github.com/transmissions11/solmate/blob/50e15bb566f98b7174da9b0066126a4c3e75e0fd/src/utils/SafeTransferLib.sol#L31-L63
    function safeTransferFrom(address token_, address from_, address to_, uint256 amount_) internal {
        bool success_;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(from_, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from_" argument.
            mstore(add(freeMemoryPointer, 36), and(to_, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to_" argument.
            mstore(add(freeMemoryPointer, 68), amount_) // Append the "amount_" argument. Masking not required as it's a full 32 byte type.

            success_ := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token_, 0, freeMemoryPointer, 100, 0, 32)
            )
        }

        if (!success_) {
            revert FluidSafeTransferError(ErrorTypes.SafeTransfer__TransferFromFailed);
        }
    }

    /// @dev Transfer `amount_` of `token_` to `to_`.
    /// If `token_` returns no value, non-reverting calls are assumed to be successful.
    /// Minimally modified from Solmate SafeTransferLib (address as input param for token, Custom Error):
    /// https://github.com/transmissions11/solmate/blob/50e15bb566f98b7174da9b0066126a4c3e75e0fd/src/utils/SafeTransferLib.sol#L65-L95
    function safeTransfer(address token_, address to_, uint256 amount_) internal {
        bool success_;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to_, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to_" argument.
            mstore(add(freeMemoryPointer, 36), amount_) // Append the "amount_" argument. Masking not required as it's a full 32 byte type.

            success_ := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token_, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        if (!success_) {
            revert FluidSafeTransferError(ErrorTypes.SafeTransfer__TransferFailed);
        }
    }

    /// @dev Transfer `amount_` of ` native token to `to_`.
    /// Minimally modified from Solmate SafeTransferLib (Custom Error):
    /// https://github.com/transmissions11/solmate/blob/50e15bb566f98b7174da9b0066126a4c3e75e0fd/src/utils/SafeTransferLib.sol#L15-L25
    function safeTransferNative(address to_, uint256 amount_) internal {
        bool success_;

        /// @solidity memory-safe-assembly
        assembly {
            // Transfer the ETH and store if it succeeded or not. Pass limited gas
            success_ := call(MAX_NATIVE_TRANSFER_GAS, to_, amount_, 0, 0, 0, 0)
        }

        if (!success_) {
            revert FluidSafeTransferError(ErrorTypes.SafeTransfer__TransferFailed);
        }
    }
}

File 6 of 11 : tickMath.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

/// @title library that calculates number "tick" and "ratioX96" from this: ratioX96 = (1.0015^tick) * 2^96
/// @notice this library is used in Fluid Vault protocol for optimiziation.
/// @dev "tick" supports between -32767 and 32767. "ratioX96" supports between 37075072 and 169307877264527972847801929085841449095838922544595
library TickMath {
    /// The minimum tick that can be passed in getRatioAtTick. 1.0015**-32767
    int24 internal constant MIN_TICK = -32767;
    /// The maximum tick that can be passed in getRatioAtTick. 1.0015**32767
    int24 internal constant MAX_TICK = 32767;

    uint256 internal constant FACTOR00 = 0x100000000000000000000000000000000;
    uint256 internal constant FACTOR01 = 0xff9dd7de423466c20352b1246ce4856f; // 2^128/1.0015**1 = 339772707859149738855091969477551883631
    uint256 internal constant FACTOR02 = 0xff3bd55f4488ad277531fa1c725a66d0; // 2^128/1.0015**2 = 339263812140938331358054887146831636176
    uint256 internal constant FACTOR03 = 0xfe78410fd6498b73cb96a6917f853259; // 2^128/1.0015**4 = 338248306163758188337119769319392490073
    uint256 internal constant FACTOR04 = 0xfcf2d9987c9be178ad5bfeffaa123273; // 2^128/1.0015**8 = 336226404141693512316971918999264834163
    uint256 internal constant FACTOR05 = 0xf9ef02c4529258b057769680fc6601b3; // 2^128/1.0015**16 = 332218786018727629051611634067491389875
    uint256 internal constant FACTOR06 = 0xf402d288133a85a17784a411f7aba082; // 2^128/1.0015**32 = 324346285652234375371948336458280706178
    uint256 internal constant FACTOR07 = 0xe895615b5beb6386553757b0352bda90; // 2^128/1.0015**64 = 309156521885964218294057947947195947664
    uint256 internal constant FACTOR08 = 0xd34f17a00ffa00a8309940a15930391a; // 2^128/1.0015**128 = 280877777739312896540849703637713172762 
    uint256 internal constant FACTOR09 = 0xae6b7961714e20548d88ea5123f9a0ff; // 2^128/1.0015**256 = 231843708922198649176471782639349113087
    uint256 internal constant FACTOR10 = 0x76d6461f27082d74e0feed3b388c0ca1; // 2^128/1.0015**512 = 157961477267171621126394973980180876449
    uint256 internal constant FACTOR11 = 0x372a3bfe0745d8b6b19d985d9a8b85bb; // 2^128/1.0015**1024 = 73326833024599564193373530205717235131
    uint256 internal constant FACTOR12 = 0x0be32cbee48979763cf7247dd7bb539d; // 2^128/1.0015**2048 = 15801066890623697521348224657638773661
    uint256 internal constant FACTOR13 = 0x8d4f70c9ff4924dac37612d1e2921e;   // 2^128/1.0015**4096 = 733725103481409245883800626999235102
    uint256 internal constant FACTOR14 = 0x4e009ae5519380809a02ca7aec77;     // 2^128/1.0015**8192 = 1582075887005588088019997442108535
    uint256 internal constant FACTOR15 = 0x17c45e641b6e95dee056ff10;         // 2^128/1.0015**16384 = 7355550435635883087458926352

    /// The minimum value that can be returned from getRatioAtTick. Equivalent to getRatioAtTick(MIN_TICK). ~ Equivalent to `(1 << 96) * (1.0015**-32767)`
    uint256 internal constant MIN_RATIOX96 = 37075072;
    /// The maximum value that can be returned from getRatioAtTick. Equivalent to getRatioAtTick(MAX_TICK).
    /// ~ Equivalent to `(1 << 96) * (1.0015**32767)`, rounding etc. leading to minor difference
    uint256 internal constant MAX_RATIOX96 = 169307877264527972847801929085841449095838922544595;

    uint256 internal constant ZERO_TICK_SCALED_RATIO = 0x1000000000000000000000000; // 1 << 96 // 79228162514264337593543950336
    uint256 internal constant _1E26 = 1e26;

    /// @notice ratioX96 = (1.0015^tick) * 2^96
    /// @dev Throws if |tick| > max tick
    /// @param tick The input tick for the above formula
    /// @return ratioX96 ratio = (debt amount/collateral amount)
    function getRatioAtTick(int tick) internal pure returns (uint256 ratioX96) {
        assembly {
            let absTick_ := sub(xor(tick, sar(255, tick)), sar(255, tick))

            if gt(absTick_, MAX_TICK) {
                revert(0, 0)
            }
            let factor_ := FACTOR00
            if and(absTick_, 0x1) {
                factor_ := FACTOR01
            }
            if and(absTick_, 0x2) {
                factor_ := shr(128, mul(factor_, FACTOR02))
            }
            if and(absTick_, 0x4) {
                factor_ := shr(128, mul(factor_, FACTOR03))
            }
            if and(absTick_, 0x8) {
                factor_ := shr(128, mul(factor_, FACTOR04))
            }
            if and(absTick_, 0x10) {
                factor_ := shr(128, mul(factor_, FACTOR05))
            }
            if and(absTick_, 0x20) {
                factor_ := shr(128, mul(factor_, FACTOR06))
            }
            if and(absTick_, 0x40) {
                factor_ := shr(128, mul(factor_, FACTOR07))
            }
            if and(absTick_, 0x80) {
                factor_ := shr(128, mul(factor_, FACTOR08))
            }
            if and(absTick_, 0x100) {
                factor_ := shr(128, mul(factor_, FACTOR09))
            }
            if and(absTick_, 0x200) {
                factor_ := shr(128, mul(factor_, FACTOR10))
            }
            if and(absTick_, 0x400) {
                factor_ := shr(128, mul(factor_, FACTOR11))
            }
            if and(absTick_, 0x800) {
                factor_ := shr(128, mul(factor_, FACTOR12))
            }
            if and(absTick_, 0x1000) {
                factor_ := shr(128, mul(factor_, FACTOR13))
            }
            if and(absTick_, 0x2000) {
                factor_ := shr(128, mul(factor_, FACTOR14))
            }
            if and(absTick_, 0x4000) {
                factor_ := shr(128, mul(factor_, FACTOR15))
            }

            let precision_ := 0
            if iszero(and(tick, 0x8000000000000000000000000000000000000000000000000000000000000000)) {
                factor_ := div(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, factor_)
                // we round up in the division so getTickAtRatio of the output price is always consistent
                if mod(factor_, 0x100000000) {
                    precision_ := 1
                }
            }
            ratioX96 := add(shr(32, factor_), precision_)
        }
    }

    /// @notice ratioX96 = (1.0015^tick) * 2^96
    /// @dev Throws if ratioX96 > max ratio || ratioX96 < min ratio
    /// @param ratioX96 The input ratio; ratio = (debt amount/collateral amount)
    /// @return tick The output tick for the above formula. Returns in round down form. if tick is 123.23 then 123, if tick is -123.23 then returns -124
    /// @return perfectRatioX96 perfect ratio for the above tick
    function getTickAtRatio(uint256 ratioX96) internal pure returns (int tick, uint perfectRatioX96) {
        assembly {
            if or(gt(ratioX96, MAX_RATIOX96), lt(ratioX96, MIN_RATIOX96)) {
                revert(0, 0)
            }

            let cond := lt(ratioX96, ZERO_TICK_SCALED_RATIO)
            let factor_

            if iszero(cond) {
                // if ratioX96 >= ZERO_TICK_SCALED_RATIO
                factor_ := div(mul(ratioX96, _1E26), ZERO_TICK_SCALED_RATIO)
            }
            if cond {
                // ratioX96 < ZERO_TICK_SCALED_RATIO
                factor_ := div(mul(ZERO_TICK_SCALED_RATIO, _1E26), ratioX96)
            }

            // put in https://www.wolframalpha.com/ whole equation: (1.0015^tick) * 2^96 * 10^26 / 79228162514264337593543950336

            // for tick = 16384
            // ratioX96 = (1.0015^16384) * 2^96 = 3665252098134783297721995888537077351735
            // 3665252098134783297721995888537077351735 * 10^26 / 79228162514264337593543950336 =
            // 4626198540796508716348404308345255985.06131964639489434655721
            if iszero(lt(factor_, 4626198540796508716348404308345255985)) {
                tick := or(tick, 0x4000)
                factor_ := div(mul(factor_, _1E26), 4626198540796508716348404308345255985)
            }
            // for tick = 8192
            // ratioX96 = (1.0015^8192) * 2^96 = 17040868196391020479062776466509865
            // 17040868196391020479062776466509865 * 10^26 / 79228162514264337593543950336 =
            // 21508599537851153911767490449162.3037648642153898377655505172
            if iszero(lt(factor_, 21508599537851153911767490449162)) {
                tick := or(tick, 0x2000)
                factor_ := div(mul(factor_, _1E26), 21508599537851153911767490449162)
            }
            // for tick = 4096
            // ratioX96 = (1.0015^4096) * 2^96 = 36743933851015821532611831851150
            // 36743933851015821532611831851150 * 10^26 / 79228162514264337593543950336 =
            // 46377364670549310883002866648.9777607649742626173648716941385
            if iszero(lt(factor_, 46377364670549310883002866649)) {
                tick := or(tick, 0x1000)
                factor_ := div(mul(factor_, _1E26), 46377364670549310883002866649)
            }
            // for tick = 2048
            // ratioX96 = (1.0015^2048) * 2^96 = 1706210527034005899209104452335
            // 1706210527034005899209104452335 * 10^26 / 79228162514264337593543950336 =
            // 2153540449365864845468344760.06357108484096046743300420319322
            if iszero(lt(factor_, 2153540449365864845468344760)) {
                tick := or(tick, 0x800)
                factor_ := div(mul(factor_, _1E26), 2153540449365864845468344760)
            }
            // for tick = 1024
            // ratioX96 = (1.0015^1024) * 2^96 = 367668226692760093024536487236
            // 367668226692760093024536487236 * 10^26 / 79228162514264337593543950336 =
            // 464062544207767844008185024.950588990554136265212906454481127
            if iszero(lt(factor_, 464062544207767844008185025)) {
                tick := or(tick, 0x400)
                factor_ := div(mul(factor_, _1E26), 464062544207767844008185025)
            }
            // for tick = 512
            // ratioX96 = (1.0015^512) * 2^96 = 170674186729409605620119663668
            // 170674186729409605620119663668 * 10^26 / 79228162514264337593543950336 =
            // 215421109505955298802281577.031879604792139232258508172947569
            if iszero(lt(factor_, 215421109505955298802281577)) {
                tick := or(tick, 0x200)
                factor_ := div(mul(factor_, _1E26), 215421109505955298802281577)
            }
            // for tick = 256
            // ratioX96 = (1.0015^256) * 2^96 = 116285004205991934861656513301
            // 116285004205991934861656513301 * 10^26 / 79228162514264337593543950336 =
            // 146772309890508740607270614.667650899656438875541505058062410
            if iszero(lt(factor_, 146772309890508740607270615)) {
                tick := or(tick, 0x100)
                factor_ := div(mul(factor_, _1E26), 146772309890508740607270615)
            }
            // for tick = 128
            // ratioX96 = (1.0015^128) * 2^96 = 95984619659632141743747099590
            // 95984619659632141743747099590 * 10^26 / 79228162514264337593543950336 =
            // 121149622323187099817270416.157248837742741760456796835775887
            if iszero(lt(factor_, 121149622323187099817270416)) {
                tick := or(tick, 0x80)
                factor_ := div(mul(factor_, _1E26), 121149622323187099817270416)
            }
            // for tick = 64
            // ratioX96 = (1.0015^64) * 2^96 = 87204845308406958006717891124
            // 87204845308406958006717891124 * 10^26 / 79228162514264337593543950336 =
            // 110067989135437147685980801.568068573422377364214113968609839
            if iszero(lt(factor_, 110067989135437147685980801)) {
                tick := or(tick, 0x40)
                factor_ := div(mul(factor_, _1E26), 110067989135437147685980801)
            }
            // for tick = 32
            // ratioX96 = (1.0015^32) * 2^96 = 83120873769022354029916374475
            // 83120873769022354029916374475 * 10^26 / 79228162514264337593543950336 =
            // 104913292358707887270979599.831816586773651266562785765558183
            if iszero(lt(factor_, 104913292358707887270979600)) {
                tick := or(tick, 0x20)
                factor_ := div(mul(factor_, _1E26), 104913292358707887270979600)
            }
            // for tick = 16
            // ratioX96 = (1.0015^16) * 2^96 = 81151180492336368327184716176
            // 81151180492336368327184716176 * 10^26 / 79228162514264337593543950336 =
            // 102427189924701091191840927.762844039579442328381455567932128
            if iszero(lt(factor_, 102427189924701091191840928)) {
                tick := or(tick, 0x10)
                factor_ := div(mul(factor_, _1E26), 102427189924701091191840928)
            }
            // for tick = 8
            // ratioX96 = (1.0015^8) * 2^96 = 80183906840906820640659903620
            // 80183906840906820640659903620 * 10^26 / 79228162514264337593543950336 =
            // 101206318935480056907421312.890625
            if iszero(lt(factor_, 101206318935480056907421313)) {
                tick := or(tick, 0x8)
                factor_ := div(mul(factor_, _1E26), 101206318935480056907421313)
            }
            // for tick = 4
            // ratioX96 = (1.0015^4) * 2^96 = 79704602139525152702959747603
            // 79704602139525152702959747603 * 10^26 / 79228162514264337593543950336 =
            // 100601351350506250000000000
            if iszero(lt(factor_, 100601351350506250000000000)) {
                tick := or(tick, 0x4)
                factor_ := div(mul(factor_, _1E26), 100601351350506250000000000)
            }
            // for tick = 2
            // ratioX96 = (1.0015^2) * 2^96 = 79466025265172787701084167660
            // 79466025265172787701084167660 * 10^26 / 79228162514264337593543950336 =
            // 100300225000000000000000000
            if iszero(lt(factor_, 100300225000000000000000000)) {
                tick := or(tick, 0x2)
                factor_ := div(mul(factor_, _1E26), 100300225000000000000000000)
            }
            // for tick = 1
            // ratioX96 = (1.0015^1) * 2^96 = 79347004758035734099934266261
            // 79347004758035734099934266261 * 10^26 / 79228162514264337593543950336 =
            // 100150000000000000000000000
            if iszero(lt(factor_, 100150000000000000000000000)) {
                tick := or(tick, 0x1)
                factor_ := div(mul(factor_, _1E26), 100150000000000000000000000)
            }
            if iszero(cond) {
                // if ratioX96 >= ZERO_TICK_SCALED_RATIO
                perfectRatioX96 := div(mul(ratioX96, _1E26), factor_)
            }
            if cond {
                // ratioX96 < ZERO_TICK_SCALED_RATIO
                tick := not(tick)
                perfectRatioX96 := div(mul(ratioX96, factor_), 100150000000000000000000000)
            }
            // perfect ratio should always be <= ratioX96
            // not sure if it can ever be bigger but better to have extra checks
            if gt(perfectRatioX96, ratioX96) {
                revert(0, 0)
            }
        }
    }
}

File 7 of 11 : error.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

abstract contract Error {
    error FluidVaultError(uint256 errorId_);

    /// @notice used to simulate liquidation to find the maximum liquidatable amounts
    error FluidLiquidateResult(uint256 colLiquidated, uint256 debtLiquidated);
}

File 8 of 11 : errorTypes.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

library ErrorTypes {
    /***********************************|
    |           Vault Factory           | 
    |__________________________________*/

    uint256 internal constant VaultFactory__InvalidOperation = 30001;
    uint256 internal constant VaultFactory__Unauthorized = 30002;
    uint256 internal constant VaultFactory__SameTokenNotAllowed = 30003;
    uint256 internal constant VaultFactory__InvalidParams = 30004;
    uint256 internal constant VaultFactory__InvalidVault = 30005;
    uint256 internal constant VaultFactory__InvalidVaultAddress = 30006;
    uint256 internal constant VaultFactory__OnlyDelegateCallAllowed = 30007;

    /***********************************|
    |            Vault                  | 
    |__________________________________*/

    /// @notice thrown at reentrancy
    uint256 internal constant Vault__AlreadyEntered = 31001;

    /// @notice thrown when user sends deposit & borrow amount as 0
    uint256 internal constant Vault__InvalidOperateAmount = 31002;

    /// @notice thrown when msg.value is not in sync with native token deposit or payback
    uint256 internal constant Vault__InvalidMsgValueOperate = 31003;

    /// @notice thrown when msg.sender is not the owner of the vault
    uint256 internal constant Vault__NotAnOwner = 31004;

    /// @notice thrown when user's position does not exist. Sending the wrong index from the frontend
    uint256 internal constant Vault__TickIsEmpty = 31005;

    /// @notice thrown when the user's position is above CF and the user tries to make it more risky by trying to withdraw or borrow
    uint256 internal constant Vault__PositionAboveCF = 31006;

    /// @notice thrown when the top tick is not initialized. Happens if the vault is totally new or all the user's left
    uint256 internal constant Vault__TopTickDoesNotExist = 31007;

    /// @notice thrown when msg.value in liquidate is not in sync payback
    uint256 internal constant Vault__InvalidMsgValueLiquidate = 31008;

    /// @notice thrown when slippage is more on liquidation than what the liquidator sent
    uint256 internal constant Vault__ExcessSlippageLiquidation = 31009;

    /// @notice thrown when msg.sender is not the rebalancer/reserve contract
    uint256 internal constant Vault__NotRebalancer = 31010;

    /// @notice thrown when NFT of one vault interacts with the NFT of other vault
    uint256 internal constant Vault__NftNotOfThisVault = 31011;

    /// @notice thrown when the token is not initialized on the liquidity contract
    uint256 internal constant Vault__TokenNotInitialized = 31012;

    /// @notice thrown when admin updates fallback if a non-auth calls vault
    uint256 internal constant Vault__NotAnAuth = 31013;

    /// @notice thrown in operate when user tries to witdhraw more collateral than deposited
    uint256 internal constant Vault__ExcessCollateralWithdrawal = 31014;

    /// @notice thrown in operate when user tries to payback more debt than borrowed
    uint256 internal constant Vault__ExcessDebtPayback = 31015;

    /// @notice thrown when user try to withdrawal more than operate's withdrawal limit
    uint256 internal constant Vault__WithdrawMoreThanOperateLimit = 31016;

    /// @notice thrown when caller of liquidityCallback is not Liquidity
    uint256 internal constant Vault__InvalidLiquidityCallbackAddress = 31017;

    /// @notice thrown when reentrancy is not already on
    uint256 internal constant Vault__NotEntered = 31018;

    /// @notice thrown when someone directly calls operate or secondary implementation contract
    uint256 internal constant Vault__OnlyDelegateCallAllowed = 31019;

    /// @notice thrown when the safeTransferFrom for a token amount failed
    uint256 internal constant Vault__TransferFromFailed = 31020;

    /// @notice thrown when exchange price overflows while updating on storage
    uint256 internal constant Vault__ExchangePriceOverFlow = 31021;

    /// @notice thrown when debt to liquidate amt is sent wrong
    uint256 internal constant Vault__InvalidLiquidationAmt = 31022;

    /// @notice thrown when user debt or collateral goes above 2**128 or below -2**128
    uint256 internal constant Vault__UserCollateralDebtExceed = 31023;

    /// @notice thrown if on liquidation branch debt becomes lower than 100
    uint256 internal constant Vault__BranchDebtTooLow = 31024;

    /// @notice thrown when tick's debt is less than 10000
    uint256 internal constant Vault__TickDebtTooLow = 31025;

    /// @notice thrown when the received new liquidity exchange price is of unexpected value (< than the old one)
    uint256 internal constant Vault__LiquidityExchangePriceUnexpected = 31026;

    /// @notice thrown when user's debt is less than 10000
    uint256 internal constant Vault__UserDebtTooLow = 31027;

    /// @notice thrown when on only payback and only deposit the ratio of position increases
    uint256 internal constant Vault__InvalidPaybackOrDeposit = 31028;

    /// @notice thrown when liquidation just happens of a single partial or when there's nothing to liquidate
    uint256 internal constant Vault__InvalidLiquidation = 31029;

    /// @notice thrown when msg.value is sent wrong in rebalance
    uint256 internal constant Vault__InvalidMsgValueInRebalance = 31030;

    /// @notice thrown when nothing rebalanced
    uint256 internal constant Vault__NothingToRebalance = 31031;

    /// @notice thrown on unforseen liquidation scenarios. Might never come in use.
    uint256 internal constant Vault__LiquidationReverts = 31032;

    /// @notice thrown when oracle price is > 1e54
    uint256 internal constant Vault__InvalidOraclePrice = 31033;

    /// @notice thrown when constants are not set properly via contructor
    uint256 internal constant Vault__ImproperConstantsSetup = 31034;

    /// @notice thrown when externally calling fetchLatestPosition function
    uint256 internal constant Vault__FetchLatestPositionFailed = 31035;

    /// @notice thrown when dex callback is not from dex
    uint256 internal constant Vault__InvalidDexCallbackAddress = 31036;

    /// @notice thrown when dex callback is already set
    uint256 internal constant Vault__DexFromAddressAlreadySet = 31037;

    /// @notice thrown when an invalid min / max amounts config is passed to rebalance()
    uint256 internal constant Vault__InvalidMinMaxInRebalance = 31038;

    /***********************************|
    |              ERC721               | 
    |__________________________________*/

    uint256 internal constant ERC721__InvalidParams = 32001;
    uint256 internal constant ERC721__Unauthorized = 32002;
    uint256 internal constant ERC721__InvalidOperation = 32003;
    uint256 internal constant ERC721__UnsafeRecipient = 32004;
    uint256 internal constant ERC721__OutOfBoundsIndex = 32005;

    /***********************************|
    |            Vault Admin            | 
    |__________________________________*/

    /// @notice thrown when admin tries to setup invalid value which are crossing limits
    uint256 internal constant VaultAdmin__ValueAboveLimit = 33001;

    /// @notice when someone directly calls admin implementation contract
    uint256 internal constant VaultAdmin__OnlyDelegateCallAllowed = 33002;

    /// @notice thrown when auth sends NFT ID as 0 while collecting dust debt
    uint256 internal constant VaultAdmin__NftIdShouldBeNonZero = 33003;

    /// @notice thrown when trying to collect dust debt of NFT which is not of this vault
    uint256 internal constant VaultAdmin__NftNotOfThisVault = 33004;

    /// @notice thrown when dust debt of NFT is 0, meaning nothing to collect
    uint256 internal constant VaultAdmin__DustDebtIsZero = 33005;

    /// @notice thrown when final debt after liquidation is not 0, meaning position 100% liquidated
    uint256 internal constant VaultAdmin__FinalDebtShouldBeZero = 33006;

    /// @notice thrown when NFT is not liquidated state
    uint256 internal constant VaultAdmin__NftNotLiquidated = 33007;

    /// @notice thrown when total absorbed dust debt is 0
    uint256 internal constant VaultAdmin__AbsorbedDustDebtIsZero = 33008;

    /// @notice thrown when address is set as 0
    uint256 internal constant VaultAdmin__AddressZeroNotAllowed = 33009;

    /***********************************|
    |            Vault Rewards          | 
    |__________________________________*/

    uint256 internal constant VaultRewards__Unauthorized = 34001;
    uint256 internal constant VaultRewards__AddressZero = 34002;
    uint256 internal constant VaultRewards__InvalidParams = 34003;
    uint256 internal constant VaultRewards__NewMagnifierSameAsOldMagnifier = 34004;
    uint256 internal constant VaultRewards__NotTheInitiator = 34005;
    uint256 internal constant VaultRewards__NotTheGovernance = 34006;
    uint256 internal constant VaultRewards__AlreadyStarted = 34007;
    uint256 internal constant VaultRewards__RewardsNotStartedOrEnded = 34008;
    uint256 internal constant VaultRewards__InvalidStartTime = 34009;
    uint256 internal constant VaultRewards__AlreadyEnded = 34010;

    /***********************************|
    |          Vault DEX Types          | 
    |__________________________________*/

    uint256 internal constant VaultDex__InvalidOperateAmount = 35001;
    uint256 internal constant VaultDex__DebtSharesPaidMoreThanAvailableLiquidation = 35002;

    /***********************************|
    |        Vault Borrow Rewards       | 
    |__________________________________*/

    uint256 internal constant VaultBorrowRewards__Unauthorized = 36001;
    uint256 internal constant VaultBorrowRewards__AddressZero = 36002;
    uint256 internal constant VaultBorrowRewards__InvalidParams = 36003;
    uint256 internal constant VaultBorrowRewards__NewMagnifierSameAsOldMagnifier = 36004;
    uint256 internal constant VaultBorrowRewards__NotTheInitiator = 36005;
    uint256 internal constant VaultBorrowRewards__NotTheGovernance = 36006;
    uint256 internal constant VaultBorrowRewards__AlreadyStarted = 36007;
    uint256 internal constant VaultBorrowRewards__RewardsNotStartedOrEnded = 36008;
    uint256 internal constant VaultBorrowRewards__InvalidStartTime = 36009;
    uint256 internal constant VaultBorrowRewards__AlreadyEnded = 36010;
}

File 9 of 11 : iVaultT1.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

interface IFluidVaultT1 {
    /// @notice returns the vault id
    function VAULT_ID() external view returns (uint256);

    /// @notice reads uint256 data `result_` from storage at a bytes32 storage `slot_` key.
    function readFromStorage(bytes32 slot_) external view returns (uint256 result_);

    struct ConstantViews {
        address liquidity;
        address factory;
        address adminImplementation;
        address secondaryImplementation;
        address supplyToken;
        address borrowToken;
        uint8 supplyDecimals;
        uint8 borrowDecimals;
        uint vaultId;
        bytes32 liquiditySupplyExchangePriceSlot;
        bytes32 liquidityBorrowExchangePriceSlot;
        bytes32 liquidityUserSupplySlot;
        bytes32 liquidityUserBorrowSlot;
    }

    /// @notice returns all Vault constants
    function constantsView() external view returns (ConstantViews memory constantsView_);

    /// @notice fetches the latest user position after a liquidation
    function fetchLatestPosition(
        int256 positionTick_,
        uint256 positionTickId_,
        uint256 positionRawDebt_,
        uint256 tickData_
    )
        external
        view
        returns (
            int256, // tick
            uint256, // raw debt
            uint256, // raw collateral
            uint256, // branchID_
            uint256 // branchData_
        );

    /// @notice calculates the updated vault exchange prices
    function updateExchangePrices(
        uint256 vaultVariables2_
    )
        external
        view
        returns (
            uint256 liqSupplyExPrice_,
            uint256 liqBorrowExPrice_,
            uint256 vaultSupplyExPrice_,
            uint256 vaultBorrowExPrice_
        );

    /// @notice calculates the updated vault exchange prices and writes them to storage
    function updateExchangePricesOnStorage()
        external
        returns (
            uint256 liqSupplyExPrice_,
            uint256 liqBorrowExPrice_,
            uint256 vaultSupplyExPrice_,
            uint256 vaultBorrowExPrice_
        );

    /// @notice returns the liquidity contract address
    function LIQUIDITY() external view returns (address);

    function operate(
        uint256 nftId_, // if 0 then new position
        int256 newCol_, // if negative then withdraw
        int256 newDebt_, // if negative then payback
        address to_ // address at which the borrow & withdraw amount should go to. If address(0) then it'll go to msg.sender
    )
        external
        payable
        returns (
            uint256, // nftId_
            int256, // final supply amount. if - then withdraw
            int256 // final borrow amount. if - then payback
        );

    function liquidate(
        uint256 debtAmt_,
        uint256 colPerUnitDebt_, // min collateral needed per unit of debt in 1e18
        address to_,
        bool absorb_
    ) external payable returns (uint actualDebtAmt_, uint actualColAmt_);

    function absorb() external;

    function rebalance() external payable returns (int supplyAmt_, int borrowAmt_);

    error FluidLiquidateResult(uint256 colLiquidated, uint256 debtLiquidated);
}

File 10 of 11 : events.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

contract Events {
    /// @notice emitted when the supply rate magnifier config is updated
    event LogUpdateSupplyRateMagnifier(uint supplyRateMagnifier_);

    /// @notice emitted when the borrow rate magnifier config is updated
    event LogUpdateBorrowRateMagnifier(uint borrowRateMagnifier_);

    /// @notice emitted when the collateral factor config is updated
    event LogUpdateCollateralFactor(uint collateralFactor_);

    /// @notice emitted when the liquidation threshold config is updated
    event LogUpdateLiquidationThreshold(uint liquidationThreshold_);

    /// @notice emitted when the liquidation max limit config is updated
    event LogUpdateLiquidationMaxLimit(uint liquidationMaxLimit_);

    /// @notice emitted when the withdrawal gap config is updated
    event LogUpdateWithdrawGap(uint withdrawGap_);

    /// @notice emitted when the liquidation penalty config is updated
    event LogUpdateLiquidationPenalty(uint liquidationPenalty_);

    /// @notice emitted when the borrow fee config is updated
    event LogUpdateBorrowFee(uint borrowFee_);

    /// @notice emitted when the core setting configs are updated
    event LogUpdateCoreSettings(
        uint supplyRateMagnifier_,
        uint borrowRateMagnifier_,
        uint collateralFactor_,
        uint liquidationThreshold_,
        uint liquidationMaxLimit_,
        uint withdrawGap_,
        uint liquidationPenalty_,
        uint borrowFee_
    );

    /// @notice emitted when the oracle is updated
    event LogUpdateOracle(address indexed newOracle_);

    /// @notice emitted when the allowed rebalancer is updated
    event LogUpdateRebalancer(address indexed newRebalancer_);

    /// @notice emitted when funds are rescued
    event LogRescueFunds(address indexed token_);

    /// @notice emitted when dust debt is absorbed for `nftIds_`
    event LogAbsorbDustDebt(uint256[] nftIds_, uint256 absorbedDustDebt_);
}

File 11 of 11 : variables.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

contract Variables {
    /***********************************|
    |         Storage Variables         |
    |__________________________________*/

    /// note: in all variables. For tick >= 0 are represented with bit as 1, tick < 0 are represented with bit as 0
    /// note: read all the variables through storageRead.sol

    /// note: vaultVariables contains vault variables which need regular updates through transactions
    /// First 1 bit => 0 => re-entrancy. If 0 then allow transaction to go, else throw.
    /// Next 1 bit => 1 => Is the current active branch liquidated? If true then check the branch's minima tick before creating a new position
    /// If the new tick is greater than minima tick then initialize a new branch, make that as current branch & do proper linking
    /// Next 1 bit => 2 => sign of topmost tick (0 -> negative; 1 -> positive)
    /// Next 19 bits => 3-21 => absolute value of topmost tick
    /// Next 30 bits => 22-51 => current branch ID
    /// Next 30 bits => 52-81 => total branch ID
    /// Next 64 bits => 82-145 => Total supply
    /// Next 64 bits => 146-209 => Total borrow
    /// Next 32 bits => 210-241 => Total positions
    uint256 internal vaultVariables;

    /// note: vaultVariables2 contains variables which do not update on every transaction. So mainly admin/auth set amount
    /// First 16 bits => 0-15 => supply rate magnifier; 10000 = 1x (Here 16 bits should be more than enough)
    /// Next 16 bits => 16-31 => borrow rate magnifier; 10000 = 1x (Here 16 bits should be more than enough)
    /// Next 10 bits => 32-41 => collateral factor. 800 = 0.8 = 80% (max precision of 0.1%)
    /// Next 10 bits => 42-51 => liquidation Threshold. 900 = 0.9 = 90% (max precision of 0.1%)
    /// Next 10 bits => 52-61 => liquidation Max Limit. 950 = 0.95 = 95% (max precision of 0.1%) (above this 100% liquidation can happen)
    /// Next 10 bits => 62-71 => withdraw gap. 100 = 0.1 = 10%. (max precision of 0.1%) (max 7 bits can also suffice for the requirement here of 0.1% to 10%). Needed to save some limits on withdrawals so liquidate can work seamlessly.
    /// Next 10 bits => 72-81 => liquidation penalty. 100 = 0.01 = 1%. (max precision of 0.01%) (max liquidation penantly can be 10.23%). Applies when tick is in between liquidation Threshold & liquidation Max Limit.
    /// Next 10 bits => 82-91 => borrow fee. 100 = 0.01 = 1%. (max precision of 0.01%) (max borrow fee can be 10.23%). Fees on borrow.
    /// Next 4  bits => 92-95 => empty
    /// Next 160 bits => 96-255 => Oracle address
    uint256 internal vaultVariables2;

    /// note: stores absorbed liquidity
    /// First 128 bits raw debt amount
    /// last 128 bits raw col amount
    uint256 internal absorbedLiquidity;

    /// position index => position data uint
    /// if the entire variable is 0 (meaning not initialized) at the start that means no position at all
    /// First 1 bit => 0 => position type (0 => borrow position; 1 => supply position)
    /// Next 1 bit => 1 => sign of user's tick (0 => negative; 1 => positive)
    /// Next 19 bits => 2-20 => absolute value of user's tick
    /// Next 24 bits => 21-44 => user's tick's id
    /// Below we are storing user's collateral & not debt, because the position can also be only collateral with no tick but it can never be only debt
    /// Next 64 bits => 45-108 => user's supply amount. Debt will be calculated through supply & ratio.
    /// Next 64 bits => 109-172 => user's dust debt amount. User's net debt = total debt - dust amount. Total debt is calculated through supply & ratio
    /// User won't pay any extra interest on dust debt & hence we will not show it as a debt on UI. For user's there's no dust.
    mapping(uint256 => uint256) internal positionData;

    /// Tick has debt only keeps data of non liquidated positions. liquidated tick's data stays in branch itself
    /// tick parent => uint (represents bool for 256 children)
    /// parent of (i)th tick:-
    /// if (i>=0) (i / 256);
    /// else ((i + 1) / 256) - 1
    /// first bit of the variable is the smallest tick & last bit is the biggest tick of that slot
    mapping(int256 => uint256) internal tickHasDebt;

    /// mapping tickId => tickData
    /// Tick related data. Total debt & other things
    /// First bit => 0 => If 1 then liquidated else not liquidated
    /// Next 24 bits => 1-24 => Total IDs. ID should start from 1.
    /// If not liquidated:
    /// Next 64 bits => 25-88 => raw debt
    /// If liquidated
    /// The below 3 things are of last ID. This is to be updated when user creates a new position
    /// Next 1 bit => 25 => Is 100% liquidated? If this is 1 meaning it was above max tick when it got liquidated (100% liquidated)
    /// Next 30 bits => 26-55 => branch ID where this tick got liquidated
    /// Next 50 bits => 56-105 => debt factor 50 bits (35 bits coefficient | 15 bits expansion)
    mapping(int256 => uint256) internal tickData;

    /// tick id => previous tick id liquidation data. ID starts from 1
    /// One tick ID contains 3 IDs of 80 bits in it, holding liquidation data of previously active but liquidated ticks
    /// 81 bits data below
    /// #### First 85 bits ####
    /// 1st bit => 0 => Is 100% liquidated? If this is 1 meaning it was above max tick when it got liquidated
    /// Next 30 bits => 1-30 => branch ID where this tick got liquidated
    /// Next 50 bits => 31-80 => debt factor 50 bits (35 bits coefficient | 15 bits expansion)
    /// #### Second 85 bits ####
    /// 85th bit => 85 => Is 100% liquidated? If this is 1 meaning it was above max tick when it got liquidated
    /// Next 30 bits => 86-115 => branch ID where this tick got liquidated
    /// Next 50 bits => 116-165 => debt factor 50 bits (35 bits coefficient | 15 bits expansion)
    /// #### Third 85 bits ####
    /// 170th bit => 170 => Is 100% liquidated? If this is 1 meaning it was above max tick when it got liquidated
    /// Next 30 bits => 171-200 => branch ID where this tick got liquidated
    /// Next 50 bits => 201-250 => debt factor 50 bits (35 bits coefficient | 15 bits expansion)
    mapping(int256 => mapping(uint256 => uint256)) internal tickId;

    /// mapping branchId => branchData
    /// First 2 bits => 0-1 => if 0 then not liquidated, if 1 then liquidated, if 2 then merged, if 3 then closed
    /// merged means the branch is merged into it's base branch
    /// closed means all the users are 100% liquidated
    /// Next 1 bit => 2 => minima tick sign of this branch. Will only be there if any liquidation happened.
    /// Next 19 bits => 3-21 => minima tick of this branch. Will only be there if any liquidation happened.
    /// Next 30 bits => 22-51 => Partials of minima tick of branch this is connected to. 0 if master branch.
    /// Next 64 bits => 52-115 Debt liquidity at this branch. Similar to last's top tick data. Remaining debt will move here from tickData after first liquidation
    /// If not merged
    /// Next 50 bits => 116-165 => Debt factor or of this branch. (35 bits coefficient | 15 bits expansion)
    /// If merged
    /// Next 50 bits => 116-165 => Connection/adjustment debt factor of this branch with the next branch.
    /// If closed
    /// Next 50 bits => 116-165 => Debt factor as 0. As all the user's positions are now fully gone
    /// following values are present always again (merged / not merged / closed)
    /// Next 30 bits => 166-195 => Branch's ID with which this branch is connected. If 0 then that means this is the master branch
    /// Next 1 bit => 196 => sign of minima tick of branch this is connected to. 0 if master branch.
    /// Next 19 bits => 197-215 => minima tick of branch this is connected to. 0 if master branch.
    mapping(uint256 => uint256) internal branchData;

    /// Exchange prices are in 1e12
    /// First 64 bits => 0-63 => Liquidity's collateral token supply exchange price
    /// First 64 bits => 64-127 => Liquidity's debt token borrow exchange price
    /// First 64 bits => 128-191 => Vault's collateral token supply exchange price
    /// First 64 bits => 192-255 => Vault's debt token borrow exchange price
    uint256 internal rates;

    /// address of rebalancer
    address internal rebalancer;

    uint256 internal absorbedDustDebt;
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 10000000
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"colLiquidated","type":"uint256"},{"internalType":"uint256","name":"debtLiquidated","type":"uint256"}],"name":"FluidLiquidateResult","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorId_","type":"uint256"}],"name":"FluidSafeTransferError","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorId_","type":"uint256"}],"name":"FluidVaultError","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"nftIds_","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"absorbedDustDebt_","type":"uint256"}],"name":"LogAbsorbDustDebt","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token_","type":"address"}],"name":"LogRescueFunds","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"borrowFee_","type":"uint256"}],"name":"LogUpdateBorrowFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"borrowRateMagnifier_","type":"uint256"}],"name":"LogUpdateBorrowRateMagnifier","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"collateralFactor_","type":"uint256"}],"name":"LogUpdateCollateralFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"supplyRateMagnifier_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowRateMagnifier_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateralFactor_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidationThreshold_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidationMaxLimit_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"withdrawGap_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidationPenalty_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowFee_","type":"uint256"}],"name":"LogUpdateCoreSettings","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"liquidationMaxLimit_","type":"uint256"}],"name":"LogUpdateLiquidationMaxLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"liquidationPenalty_","type":"uint256"}],"name":"LogUpdateLiquidationPenalty","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"liquidationThreshold_","type":"uint256"}],"name":"LogUpdateLiquidationThreshold","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newOracle_","type":"address"}],"name":"LogUpdateOracle","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newRebalancer_","type":"address"}],"name":"LogUpdateRebalancer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"supplyRateMagnifier_","type":"uint256"}],"name":"LogUpdateSupplyRateMagnifier","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"withdrawGap_","type":"uint256"}],"name":"LogUpdateWithdrawGap","type":"event"},{"inputs":[{"internalType":"uint256[]","name":"nftIds_","type":"uint256[]"}],"name":"absorbDustDebt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token_","type":"address"}],"name":"rescueFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"borrowFee_","type":"uint256"}],"name":"updateBorrowFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"borrowRateMagnifier_","type":"uint256"}],"name":"updateBorrowRateMagnifier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"collateralFactor_","type":"uint256"}],"name":"updateCollateralFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"supplyRateMagnifier_","type":"uint256"},{"internalType":"uint256","name":"borrowRateMagnifier_","type":"uint256"},{"internalType":"uint256","name":"collateralFactor_","type":"uint256"},{"internalType":"uint256","name":"liquidationThreshold_","type":"uint256"},{"internalType":"uint256","name":"liquidationMaxLimit_","type":"uint256"},{"internalType":"uint256","name":"withdrawGap_","type":"uint256"},{"internalType":"uint256","name":"liquidationPenalty_","type":"uint256"},{"internalType":"uint256","name":"borrowFee_","type":"uint256"}],"name":"updateCoreSettings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"liquidationMaxLimit_","type":"uint256"}],"name":"updateLiquidationMaxLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"liquidationPenalty_","type":"uint256"}],"name":"updateLiquidationPenalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"liquidationThreshold_","type":"uint256"}],"name":"updateLiquidationThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOracle_","type":"address"}],"name":"updateOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRebalancer_","type":"address"}],"name":"updateRebalancer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"supplyRateMagnifier_","type":"uint256"}],"name":"updateSupplyRateMagnifier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"withdrawGap_","type":"uint256"}],"name":"updateWithdrawGap","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a060405234801561001057600080fd5b5030608052608051612499610084600039600081816102680152818161040a015281816105c40152818161074d015281816108ee01528181610b6101528181610d0c01528181610ec001528181611069015281816111f90152818161133c015281816117e90152611ad401526124996000f3fe608060405234801561001057600080fd5b50600436106100df5760003560e01c8063898e96281161008c578063d3b5be1a11610066578063d3b5be1a14610191578063d61b93fe146101a4578063e53b2017146101b7578063f7a0a7e0146101ca57600080fd5b8063898e962814610158578063b046a4491461016b578063b8244f5f1461017e57600080fd5b8063509c21a4116100bd578063509c21a41461011f57806354b04ef51461013257806357917a111461014557600080fd5b806303f9923c146100e45780631cb44dfc146100f95780634a138a711461010c575b600080fd5b6100f76100f23660046120ac565b6101dd565b005b6100f76101073660046120ea565b61037f565b6100f761011a3660046120ac565b610539565b6100f761012d3660046120ac565b6106c2565b6100f761014036600461210e565b610863565b6100f76101533660046120ac565b610ad6565b6100f76101663660046120ac565b610c81565b6100f76101793660046120ea565b610e35565b6100f761018c3660046120ac565b610fde565b6100f761019f3660046120ac565b61116e565b6100f76101b2366004612192565b611325565b6100f76101c53660046120ea565b6117d2565b6100f76101d83660046120ac565b611a49565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af115801561022a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061024e919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016300390506102cb576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024015b60405180910390fd5b6040518181527fba3aefe95d9bb126dd0e7885e76f453e72b0ee6efd457771f26fe0a7ca56cedc9060200160405180910390a1610309600a826122d3565b90506103e881111561034b576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b603e81901b6001547fffffffffffffffffffffffffffffffffffffffffffffff003fffffffffffffff161760018190555050565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af11580156103cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103f0919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630039050610468576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b73ffffffffffffffffffffffffffffffffffffffff81166104b9576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180f160048201526024016102c2565b600180546bffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084901b1617905560405173ffffffffffffffffffffffffffffffffffffffff8216907f7a46205dbf7cc57a79f474f580e08d7961ad634e14643486b8df2dc30c392b6290600090a250565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af1158015610586573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105aa919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630039050610622576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b6040518181527f06f8b08c94d657867f843433de70bed3628bbdc19b0c89413af75d30420ad3f39060200160405180910390a161ffff811115610695576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169091179055565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af115801561070f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610733919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016300390506107ab576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b6040518181527f0e8160f7246256e8f7eea7dc5ee9de8c9fa1d6057c30561f548e6a84defeef159060200160405180910390a1600154602a81901c6103ff166107f5600a846122d3565b9250808310610834576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b507ffffffffffffffffffffffffffffffffffffffffffffffffffffffc00ffffffff1660209190911b17600155565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af11580156108b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d4919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163003905061094c576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b6040805189815260208101899052908101879052606081018690526080810185905260a0810184905260c0810183905260e081018290527ff992c18e9b1aec434f456c32a556717f76f0f19cba16d430d4ba1be0813ab3e8906101000160405180910390a16109bb8483611bd9565b6109c6600a876122d3565b95506109d3600a866122d3565b94506109e0600a856122d3565b93506109ed600a846122d3565b925061ffff881180610a00575061ffff87115b80610a0b5750848610155b80610a165750838510155b80610a2257506103ff83115b80610a2e57506103ff82115b80610a3a57506103ff81115b15610a75576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b605281901b604883901b603e85901b603487901b602a89901b60208b901b60108d901b8e6001547ffffffffffffffffffffffffffffffffffffffffff000000000000000000000001617171717171717176001819055505050505050505050565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af1158015610b23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b47919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630039050610bbf576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b6040518181527fd3d6bb99321a653b7fc969c9f2a1917bd9623cab8ecaa67a2e1bec34c3eb2e1c9060200160405180910390a1600154603481901c6103ff16610c12610c0c82600a61230e565b84611bd9565b6103ff831115610c52576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b507ffffffffffffffffffffffffffffffffffffffffffffc00ffffffffffffffffff1660489190911b17600155565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af1158015610cce573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf2919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630039050610d6a576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b6040518181527f5ac1492eb2009d4983693cc59b4ec4032b506a0f9cbefc19a7545af5945d26af9060200160405180910390a16001546103ff602a82901c811690604883901c16610dbb8482611bd9565b610dc6600a856122d3565b9350838210610e05576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b50507fffffffffffffffffffffffffffffffffffffffffffffffffc00fffffffffffff1660349190911b17600155565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af1158015610e82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea6919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630039050610f1e576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b73ffffffffffffffffffffffffffffffffffffffff8116610f6f576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180f160048201526024016102c2565b600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fdb94ee7fd8b5bbf8f6d59e76731ff4b4f5a02ab3af1d3e0c774862cf96ff613b90600090a250565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af115801561102b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061104f919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016300390506110c7576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b6040518181527f06a28e5e1500bd478bd28b400a0fb46a9cc8748a5dac616b38bc91c29462c17f9060200160405180910390a16103ff81111561113a576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b605281901b6001547ffffffffffffffffffffffffffffffffffffffffff003ffffffffffffffffffff161760018190555050565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af11580156111bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111df919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630039050611257576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b6040518181527f44a667dd6218a52f7ef808da1e39e9c8497db215eaff093c0c42ecf9bf2168f39060200160405180910390a16001546103ff602082901c811690603483901c166112a9600a856122d3565b935083821015806112ba5750808410155b156112f5576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b50507ffffffffffffffffffffffffffffffffffffffffffffffffffff003ffffffffff16602a9190911b17600155565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163003611398576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b60008054906001821690036113b357600181176000556113e9565b6040517f60121cca00000000000000000000000000000000000000000000000000000000815261791960048201526024016102c2565b6000806000806000806000806000600a54905060005b8b518110156116e5578b818151811061141a5761141a61232b565b6020026020010151995089600003611462576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180eb60048201526024016102c2565b60008a81526003602052604081205499508990036114b0576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ec60048201526024016102c2565b67ffffffffffffffff602d8a901c16955060ff8616600887901c901b955067ffffffffffffffff606d8a901c16935060ff8416600885901c901b93508360000361152a576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ed60048201526024016102c2565b8860021660021461154c5761154760028a901c6207ffff1661235a565b611557565b6207ffff60028a901c165b975062ffffff60158a901c1696506060866115748a60020b611c26565b61157e919061230e565b60008a815260056020526040902054911c95509250600180841614806115ac57508662ffffff600185901c16115b156116a7576040517f22348cc70000000000000000000000000000000000000000000000000000000081526004810189905260248101889052604481018690526064810184905230906322348cc79060840160a060405180830381865afa15801561161b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163f9190612392565b5091975050861591506116849050576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ee60048201526024016102c2565b61168e84836123d2565b60008b81526003602052604090206001905591506116dd565b6040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ef60048201526024016102c2565b6001016113ff565b5080600003611724576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180f060048201526024016102c2565b66ffffffffffffff609a8b901c1660ff60928c901c161b61174582826123d2565b905061175681603860086001611e88565b7ffffffffffffc0000000000000003ffffffffffffffffffffffffffffffffffff8c16609282901b176000908155600a556040519091507fae8abcd7cc16d6da9fa7098d41cc4cdb3bd5ce892e46f15d904b44c9b156cb5e906117bc908e9085906123e5565b60405180910390a1505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163003611845576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8216016118ff576118fa3073ffffffffffffffffffffffffffffffffffffffff16632861c7d16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f4919061242d565b47611fb1565b611a05565b611a05813073ffffffffffffffffffffffffffffffffffffffff16632861c7d16040518163ffffffff1660e01b8152600401602060405180830381865afa15801561194e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611972919061242d565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8516906370a0823190602401602060405180830381865afa1580156119dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a00919061244a565b612002565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fdff2a3947bcf9fc0807b142e7c8497066db9183428b7bdbfb1fcd0f55c27a3df90600090a250565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af1158015611a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aba919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630039050611b32576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b6040518181527f8d6a11b15739c2d7a6d0a69b9d322262db8c1fb2e4b96239e4e4733df8a5164e9060200160405180910390a161ffff811115611ba5576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b601081901b6001547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffff161760018190555050565b6126f2611be682846123d2565b1115611c22576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b5050565b600060ff82901d80831803617fff811115611c4057600080fd5b7001000000000000000000000000000000006001821615611c6e57506fff9dd7de423466c20352b1246ce4856f5b6002821615611c8d576fff3bd55f4488ad277531fa1c725a66d00260801c5b6004821615611cac576ffe78410fd6498b73cb96a6917f8532590260801c5b6008821615611ccb576ffcf2d9987c9be178ad5bfeffaa1232730260801c5b6010821615611cea576ff9ef02c4529258b057769680fc6601b30260801c5b6020821615611d09576ff402d288133a85a17784a411f7aba0820260801c5b6040821615611d28576fe895615b5beb6386553757b0352bda900260801c5b6080821615611d47576fd34f17a00ffa00a8309940a15930391a0260801c5b610100821615611d67576fae6b7961714e20548d88ea5123f9a0ff0260801c5b610200821615611d87576f76d6461f27082d74e0feed3b388c0ca10260801c5b610400821615611da7576f372a3bfe0745d8b6b19d985d9a8b85bb0260801c5b610800821615611dc7576f0be32cbee48979763cf7247dd7bb539d0260801c5b611000821615611de6576e8d4f70c9ff4924dac37612d1e2921e0260801c5b612000821615611e04576d4e009ae5519380809a02ca7aec770260801c5b614000821615611e20576b17c45e641b6e95dee056ff100260801c5b600091507f80000000000000000000000000000000000000000000000000000000000000008416611e7e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0463ffffffff811615611e7e57600191505b60201c0192915050565b600080856fffffffffffffffffffffffffffffffff811115611eab5760809150811c5b67ffffffffffffffff811115611ec3576040918201911c5b63ffffffff811115611ed7576020918201911c5b61ffff811115611ee9576010918201911c5b60ff811115611efa576008918201911c5b600f811115611f0b576004918201911c5b6003811115611f1c576002918201911c5b6001811115611f2c576001820191505b8015611f39576001820191505b5084811015611f455750835b848103905085811c60008211841615611f9457600181019050806001871b03611f9457506001908101907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86011b5b6001851b8210611fa357600080fd5b90931b909201949350505050565b60008060008060008587614e20f1905080611ffd576040517fdee51a8a0000000000000000000000000000000000000000000000000000000081526201155a60048201526024016102c2565b505050565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806120a6576040517fdee51a8a0000000000000000000000000000000000000000000000000000000081526201155a60048201526024016102c2565b50505050565b6000602082840312156120be57600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff811681146120e757600080fd5b50565b6000602082840312156120fc57600080fd5b8135612107816120c5565b9392505050565b600080600080600080600080610100898b03121561212b57600080fd5b505086359860208801359850604088013597606081013597506080810135965060a0810135955060c0810135945060e0013592509050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208083850312156121a557600080fd5b823567ffffffffffffffff808211156121bd57600080fd5b818501915085601f8301126121d157600080fd5b8135818111156121e3576121e3612163565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110858211171561222657612226612163565b60405291825284820192508381018501918883111561224457600080fd5b938501935b8285101561226257843584529385019392850192612249565b98975050505050505050565b6000806000806080858703121561228457600080fd5b505082516020840151604085015160609095015191969095509092509050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082612309577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b8082028115828204841417612325576123256122a4565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007f8000000000000000000000000000000000000000000000000000000000000000820361238b5761238b6122a4565b5060000390565b600080600080600060a086880312156123aa57600080fd5b5050835160208501516040860151606087015160809097015192989197509594509092509050565b80820180821115612325576123256122a4565b604080825283519082018190526000906020906060840190828701845b8281101561241e57815184529284019290840190600101612402565b50505092019290925292915050565b60006020828403121561243f57600080fd5b8151612107816120c5565b60006020828403121561245c57600080fd5b505191905056fea2646970667358221220abda92e80f4f45bce3a5a9e55e518168f660e26cb37f41c35ecab91bc460d1fb64736f6c63430008150033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100df5760003560e01c8063898e96281161008c578063d3b5be1a11610066578063d3b5be1a14610191578063d61b93fe146101a4578063e53b2017146101b7578063f7a0a7e0146101ca57600080fd5b8063898e962814610158578063b046a4491461016b578063b8244f5f1461017e57600080fd5b8063509c21a4116100bd578063509c21a41461011f57806354b04ef51461013257806357917a111461014557600080fd5b806303f9923c146100e45780631cb44dfc146100f95780634a138a711461010c575b600080fd5b6100f76100f23660046120ac565b6101dd565b005b6100f76101073660046120ea565b61037f565b6100f761011a3660046120ac565b610539565b6100f761012d3660046120ac565b6106c2565b6100f761014036600461210e565b610863565b6100f76101533660046120ac565b610ad6565b6100f76101663660046120ac565b610c81565b6100f76101793660046120ea565b610e35565b6100f761018c3660046120ac565b610fde565b6100f761019f3660046120ac565b61116e565b6100f76101b2366004612192565b611325565b6100f76101c53660046120ea565b6117d2565b6100f76101d83660046120ac565b611a49565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af115801561022a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061024e919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000071f177e42cbabad75d1393e485b60fec8e815f3b16300390506102cb576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024015b60405180910390fd5b6040518181527fba3aefe95d9bb126dd0e7885e76f453e72b0ee6efd457771f26fe0a7ca56cedc9060200160405180910390a1610309600a826122d3565b90506103e881111561034b576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b603e81901b6001547fffffffffffffffffffffffffffffffffffffffffffffff003fffffffffffffff161760018190555050565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af11580156103cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103f0919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000071f177e42cbabad75d1393e485b60fec8e815f3b1630039050610468576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b73ffffffffffffffffffffffffffffffffffffffff81166104b9576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180f160048201526024016102c2565b600180546bffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084901b1617905560405173ffffffffffffffffffffffffffffffffffffffff8216907f7a46205dbf7cc57a79f474f580e08d7961ad634e14643486b8df2dc30c392b6290600090a250565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af1158015610586573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105aa919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000071f177e42cbabad75d1393e485b60fec8e815f3b1630039050610622576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b6040518181527f06f8b08c94d657867f843433de70bed3628bbdc19b0c89413af75d30420ad3f39060200160405180910390a161ffff811115610695576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169091179055565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af115801561070f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610733919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000071f177e42cbabad75d1393e485b60fec8e815f3b16300390506107ab576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b6040518181527f0e8160f7246256e8f7eea7dc5ee9de8c9fa1d6057c30561f548e6a84defeef159060200160405180910390a1600154602a81901c6103ff166107f5600a846122d3565b9250808310610834576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b507ffffffffffffffffffffffffffffffffffffffffffffffffffffffc00ffffffff1660209190911b17600155565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af11580156108b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d4919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000071f177e42cbabad75d1393e485b60fec8e815f3b163003905061094c576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b6040805189815260208101899052908101879052606081018690526080810185905260a0810184905260c0810183905260e081018290527ff992c18e9b1aec434f456c32a556717f76f0f19cba16d430d4ba1be0813ab3e8906101000160405180910390a16109bb8483611bd9565b6109c6600a876122d3565b95506109d3600a866122d3565b94506109e0600a856122d3565b93506109ed600a846122d3565b925061ffff881180610a00575061ffff87115b80610a0b5750848610155b80610a165750838510155b80610a2257506103ff83115b80610a2e57506103ff82115b80610a3a57506103ff81115b15610a75576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b605281901b604883901b603e85901b603487901b602a89901b60208b901b60108d901b8e6001547ffffffffffffffffffffffffffffffffffffffffff000000000000000000000001617171717171717176001819055505050505050505050565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af1158015610b23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b47919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000071f177e42cbabad75d1393e485b60fec8e815f3b1630039050610bbf576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b6040518181527fd3d6bb99321a653b7fc969c9f2a1917bd9623cab8ecaa67a2e1bec34c3eb2e1c9060200160405180910390a1600154603481901c6103ff16610c12610c0c82600a61230e565b84611bd9565b6103ff831115610c52576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b507ffffffffffffffffffffffffffffffffffffffffffffc00ffffffffffffffffff1660489190911b17600155565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af1158015610cce573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf2919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000071f177e42cbabad75d1393e485b60fec8e815f3b1630039050610d6a576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b6040518181527f5ac1492eb2009d4983693cc59b4ec4032b506a0f9cbefc19a7545af5945d26af9060200160405180910390a16001546103ff602a82901c811690604883901c16610dbb8482611bd9565b610dc6600a856122d3565b9350838210610e05576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b50507fffffffffffffffffffffffffffffffffffffffffffffffffc00fffffffffffff1660349190911b17600155565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af1158015610e82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea6919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000071f177e42cbabad75d1393e485b60fec8e815f3b1630039050610f1e576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b73ffffffffffffffffffffffffffffffffffffffff8116610f6f576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180f160048201526024016102c2565b600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fdb94ee7fd8b5bbf8f6d59e76731ff4b4f5a02ab3af1d3e0c774862cf96ff613b90600090a250565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af115801561102b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061104f919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000071f177e42cbabad75d1393e485b60fec8e815f3b16300390506110c7576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b6040518181527f06a28e5e1500bd478bd28b400a0fb46a9cc8748a5dac616b38bc91c29462c17f9060200160405180910390a16103ff81111561113a576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b605281901b6001547ffffffffffffffffffffffffffffffffffffffffff003ffffffffffffffffffff161760018190555050565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af11580156111bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111df919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000071f177e42cbabad75d1393e485b60fec8e815f3b1630039050611257576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b6040518181527f44a667dd6218a52f7ef808da1e39e9c8497db215eaff093c0c42ecf9bf2168f39060200160405180910390a16001546103ff602082901c811690603483901c166112a9600a856122d3565b935083821015806112ba5750808410155b156112f5576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b50507ffffffffffffffffffffffffffffffffffffffffffffffffffff003ffffffffff16602a9190911b17600155565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000071f177e42cbabad75d1393e485b60fec8e815f3b163003611398576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b60008054906001821690036113b357600181176000556113e9565b6040517f60121cca00000000000000000000000000000000000000000000000000000000815261791960048201526024016102c2565b6000806000806000806000806000600a54905060005b8b518110156116e5578b818151811061141a5761141a61232b565b6020026020010151995089600003611462576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180eb60048201526024016102c2565b60008a81526003602052604081205499508990036114b0576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ec60048201526024016102c2565b67ffffffffffffffff602d8a901c16955060ff8616600887901c901b955067ffffffffffffffff606d8a901c16935060ff8416600885901c901b93508360000361152a576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ed60048201526024016102c2565b8860021660021461154c5761154760028a901c6207ffff1661235a565b611557565b6207ffff60028a901c165b975062ffffff60158a901c1696506060866115748a60020b611c26565b61157e919061230e565b60008a815260056020526040902054911c95509250600180841614806115ac57508662ffffff600185901c16115b156116a7576040517f22348cc70000000000000000000000000000000000000000000000000000000081526004810189905260248101889052604481018690526064810184905230906322348cc79060840160a060405180830381865afa15801561161b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163f9190612392565b5091975050861591506116849050576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ee60048201526024016102c2565b61168e84836123d2565b60008b81526003602052604090206001905591506116dd565b6040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ef60048201526024016102c2565b6001016113ff565b5080600003611724576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180f060048201526024016102c2565b66ffffffffffffff609a8b901c1660ff60928c901c161b61174582826123d2565b905061175681603860086001611e88565b7ffffffffffffc0000000000000003ffffffffffffffffffffffffffffffffffff8c16609282901b176000908155600a556040519091507fae8abcd7cc16d6da9fa7098d41cc4cdb3bd5ce892e46f15d904b44c9b156cb5e906117bc908e9085906123e5565b60405180910390a1505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000071f177e42cbabad75d1393e485b60fec8e815f3b163003611845576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8216016118ff576118fa3073ffffffffffffffffffffffffffffffffffffffff16632861c7d16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f4919061242d565b47611fb1565b611a05565b611a05813073ffffffffffffffffffffffffffffffffffffffff16632861c7d16040518163ffffffff1660e01b8152600401602060405180830381865afa15801561194e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611972919061242d565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8516906370a0823190602401602060405180830381865afa1580156119dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a00919061244a565b612002565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fdff2a3947bcf9fc0807b142e7c8497066db9183428b7bdbfb1fcd0f55c27a3df90600090a250565b3073ffffffffffffffffffffffffffffffffffffffff1663021618876040518163ffffffff1660e01b81526004016080604051808303816000875af1158015611a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aba919061226e565b50505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000071f177e42cbabad75d1393e485b60fec8e815f3b1630039050611b32576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180ea60048201526024016102c2565b6040518181527f8d6a11b15739c2d7a6d0a69b9d322262db8c1fb2e4b96239e4e4733df8a5164e9060200160405180910390a161ffff811115611ba5576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b601081901b6001547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffff161760018190555050565b6126f2611be682846123d2565b1115611c22576040517f60121cca0000000000000000000000000000000000000000000000000000000081526180e960048201526024016102c2565b5050565b600060ff82901d80831803617fff811115611c4057600080fd5b7001000000000000000000000000000000006001821615611c6e57506fff9dd7de423466c20352b1246ce4856f5b6002821615611c8d576fff3bd55f4488ad277531fa1c725a66d00260801c5b6004821615611cac576ffe78410fd6498b73cb96a6917f8532590260801c5b6008821615611ccb576ffcf2d9987c9be178ad5bfeffaa1232730260801c5b6010821615611cea576ff9ef02c4529258b057769680fc6601b30260801c5b6020821615611d09576ff402d288133a85a17784a411f7aba0820260801c5b6040821615611d28576fe895615b5beb6386553757b0352bda900260801c5b6080821615611d47576fd34f17a00ffa00a8309940a15930391a0260801c5b610100821615611d67576fae6b7961714e20548d88ea5123f9a0ff0260801c5b610200821615611d87576f76d6461f27082d74e0feed3b388c0ca10260801c5b610400821615611da7576f372a3bfe0745d8b6b19d985d9a8b85bb0260801c5b610800821615611dc7576f0be32cbee48979763cf7247dd7bb539d0260801c5b611000821615611de6576e8d4f70c9ff4924dac37612d1e2921e0260801c5b612000821615611e04576d4e009ae5519380809a02ca7aec770260801c5b614000821615611e20576b17c45e641b6e95dee056ff100260801c5b600091507f80000000000000000000000000000000000000000000000000000000000000008416611e7e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0463ffffffff811615611e7e57600191505b60201c0192915050565b600080856fffffffffffffffffffffffffffffffff811115611eab5760809150811c5b67ffffffffffffffff811115611ec3576040918201911c5b63ffffffff811115611ed7576020918201911c5b61ffff811115611ee9576010918201911c5b60ff811115611efa576008918201911c5b600f811115611f0b576004918201911c5b6003811115611f1c576002918201911c5b6001811115611f2c576001820191505b8015611f39576001820191505b5084811015611f455750835b848103905085811c60008211841615611f9457600181019050806001871b03611f9457506001908101907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86011b5b6001851b8210611fa357600080fd5b90931b909201949350505050565b60008060008060008587614e20f1905080611ffd576040517fdee51a8a0000000000000000000000000000000000000000000000000000000081526201155a60048201526024016102c2565b505050565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806120a6576040517fdee51a8a0000000000000000000000000000000000000000000000000000000081526201155a60048201526024016102c2565b50505050565b6000602082840312156120be57600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff811681146120e757600080fd5b50565b6000602082840312156120fc57600080fd5b8135612107816120c5565b9392505050565b600080600080600080600080610100898b03121561212b57600080fd5b505086359860208801359850604088013597606081013597506080810135965060a0810135955060c0810135945060e0013592509050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208083850312156121a557600080fd5b823567ffffffffffffffff808211156121bd57600080fd5b818501915085601f8301126121d157600080fd5b8135818111156121e3576121e3612163565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110858211171561222657612226612163565b60405291825284820192508381018501918883111561224457600080fd5b938501935b8285101561226257843584529385019392850192612249565b98975050505050505050565b6000806000806080858703121561228457600080fd5b505082516020840151604085015160609095015191969095509092509050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082612309577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b8082028115828204841417612325576123256122a4565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007f8000000000000000000000000000000000000000000000000000000000000000820361238b5761238b6122a4565b5060000390565b600080600080600060a086880312156123aa57600080fd5b5050835160208501516040860151606087015160809097015192989197509594509092509050565b80820180821115612325576123256122a4565b604080825283519082018190526000906020906060840190828701845b8281101561241e57815184529284019290840190600101612402565b50505092019290925292915050565b60006020828403121561243f57600080fd5b8151612107816120c5565b60006020828403121561245c57600080fd5b505191905056fea2646970667358221220abda92e80f4f45bce3a5a9e55e518168f660e26cb37f41c35ecab91bc460d1fb64736f6c63430008150033

Block Transaction Gas Used Reward
view all blocks produced

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

Validator Index Block Amount
View All Withdrawals

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

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