ETH Price: $3,337.76 (+2.97%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
VAMM

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 10 runs

Other Settings:
default evmVersion, BSL 1.1 license
File 1 of 41 : VAMM.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity =0.8.9;
import "./core_libraries/Tick.sol";
import "./storage/VAMMStorage.sol";
import "./interfaces/IVAMM.sol";
import "./interfaces/IPeriphery.sol";
import "./core_libraries/TickBitmap.sol";
import "./utils/SafeCastUni.sol";
import "./utils/SqrtPriceMath.sol";
import "./core_libraries/SwapMath.sol";
import "./interfaces/rate_oracles/IRateOracle.sol";
import "./interfaces/IERC20Minimal.sol";
import "./interfaces/IFactory.sol";
import "prb-math/contracts/PRBMathUD60x18.sol";
import "prb-math/contracts/PRBMathSD59x18.sol";
import "./core_libraries/FixedAndVariableMath.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "./utils/FixedPoint128.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";


contract VAMM is VAMMStorage, IVAMM, Initializable, OwnableUpgradeable, UUPSUpgradeable {
  using SafeCastUni for uint256;
  using SafeCastUni for int256;
  using Tick for mapping(int24 => Tick.Info);
  using TickBitmap for mapping(int16 => uint256);

  /// @dev 0.02 = 2% is the max fee as proportion of notional scaled by time to maturity (in wei fixed point notation 0.02 -> 2 * 10^16)
  uint256 public constant MAX_FEE = 20000000000000000;

  bytes32 public constant VOLTZ_PAUSER = keccak256("VOLTZ_PAUSER");

  modifier whenNotPaused() {
        require(!paused, "Paused");
        _;
    }

  function changePauser(address account, bool permission) external onlyOwner {
      pauser[account] = permission;
  }

  function setPausability(bool state) external {
      require(pauser[msg.sender], "no role");
      paused = state;
      _marginEngine.setPausability(state);
  }

  /// @dev Mutually exclusive reentrancy protection into the vamm to/from a method. This method also prevents entrance
  /// to a function before the vamm is initialized. The reentrancy guard is required throughout the contract.
  modifier lock() {
    require(_unlocked, "LOK");
    _unlocked = false;
    _;
    _unlocked = true;
  }

  // https://ethereum.stackexchange.com/questions/68529/solidity-modifiers-in-library
  /// @dev Modifier that ensures new LP positions cannot be minted after one day before the maturity of the vamm
  /// @dev also ensures new swaps cannot be conducted after one day before maturity of the vamm
  modifier checkCurrentTimestampTermEndTimestampDelta() {
    if (Time.isCloseToMaturityOrBeyondMaturity(termEndTimestampWad)) {
      revert("closeToOrBeyondMaturity");
    }
    _;
  }

  modifier checkIsAlpha() {
    
    if (_isAlpha) {
      IPeriphery _periphery = _factory.periphery();
      require(msg.sender==address(_periphery), "pphry only");
    }

    _;
    
  }

  modifier checkIsAlphaBurn() {
    
    if (_isAlpha) {
      IPeriphery _periphery = _factory.periphery();
      require(msg.sender==address(_periphery) || msg.sender==address(_marginEngine), "pphry only");
    }

    _;
    
  }

  // https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable
  /// @custom:oz-upgrades-unsafe-allow constructor
  constructor () initializer {}

  /// @inheritdoc IVAMM
  function initialize(IMarginEngine __marginEngine, int24 __tickSpacing) external override initializer {

    require(address(__marginEngine) != address(0), "ME = 0");
    // tick spacing is capped at 16384 to prevent the situation where tickSpacing is so large that
    // TickBitmap#nextInitializedTickWithinOneWord overflows int24 container from a valid tick
    // 16384 ticks represents a >5x price change with ticks of 1 bips
    require(__tickSpacing > 0 && __tickSpacing < Tick.MAXIMUM_TICK_SPACING, "TSOOB");

    _marginEngine = __marginEngine;
    rateOracle = _marginEngine.rateOracle();
    _factory = IFactory(msg.sender);
    _tickSpacing = __tickSpacing;
    _maxLiquidityPerTick = Tick.tickSpacingToMaxLiquidityPerTick(_tickSpacing);
    termStartTimestampWad = _marginEngine.termStartTimestampWad();
    termEndTimestampWad = _marginEngine.termEndTimestampWad();

    __Ownable_init();
    __UUPSUpgradeable_init();
  }

  // To authorize the owner to upgrade the contract we implement _authorizeUpgrade with the onlyOwner modifier.
  // ref: https://forum.openzeppelin.com/t/uups-proxies-tutorial-solidity-javascript/7786
  function _authorizeUpgrade(address) internal override onlyOwner {}

  /// @inheritdoc IVAMM
    function refreshRateOracle()
        external
        override
        onlyOwner
    {
        rateOracle = _marginEngine.rateOracle();
    }

  /// @inheritdoc IVAMM
    function getRateOracle() external view override returns (IRateOracle) {
        return rateOracle;
    }


  // GETTERS FOR STORAGE SLOTS
  // Not auto-generated by public variables in the storage contract, cos solidity doesn't support that for functions that implement an interface
  /// @inheritdoc IVAMM
  function feeWad() external view override returns (uint256) {
      return _feeWad;
  }
  /// @inheritdoc IVAMM
  function tickSpacing() external view override returns (int24) {
      return _tickSpacing;
  }
  /// @inheritdoc IVAMM
  function maxLiquidityPerTick() external view override returns (uint128) {
      return _maxLiquidityPerTick;
  }
  /// @inheritdoc IVAMM
  function feeGrowthGlobalX128() external view override returns (uint256) {
      return _feeGrowthGlobalX128;
  }
  /// @inheritdoc IVAMM
  function protocolFees() external view override returns (uint256) {
      return _protocolFees;
  }
  /// @inheritdoc IVAMM
  function fixedTokenGrowthGlobalX128() external view override returns (int256) {
      return _fixedTokenGrowthGlobalX128;
  }
  /// @inheritdoc IVAMM
  function variableTokenGrowthGlobalX128() external view override returns (int256) {
      return _variableTokenGrowthGlobalX128;
  }
  /// @inheritdoc IVAMM
  function liquidity() external view override returns (uint128) {
      return _liquidity;
  }
  /// @inheritdoc IVAMM
  function factory() external view override returns (IFactory) {
      return _factory;
  }
  /// @inheritdoc IVAMM
  function marginEngine() external view override returns (IMarginEngine) {
      return _marginEngine;
  }
  /// @inheritdoc IVAMM
  function ticks(int24 tick)
    external
    view
    override
    returns (Tick.Info memory) {
    return _ticks[tick];
  }
  /// @inheritdoc IVAMM
  function tickBitmap(int16 wordPosition) external view override returns (uint256) {
    return _tickBitmap[wordPosition];
  }
  /// @inheritdoc IVAMM
  function vammVars() external view override returns (VAMMVars memory) {
      return _vammVars;
  }

  /// @inheritdoc IVAMM
  function isAlpha() external view override returns (bool) {
    return _isAlpha;
  }

  /// @dev modifier that ensures the
  modifier onlyMarginEngine () {
    if (msg.sender != address(_marginEngine)) {
        revert CustomErrors.OnlyMarginEngine();
    }
    _;
  }

  function updateProtocolFees(uint256 protocolFeesCollected)
    external
    override
    onlyMarginEngine
  {
    if (_protocolFees < protocolFeesCollected) {
      revert CustomErrors.NotEnoughFunds(protocolFeesCollected, _protocolFees);
    }
    _protocolFees -= protocolFeesCollected;
  }

  /// @dev not locked because it initializes unlocked
  function initializeVAMM(uint160 sqrtPriceX96) external override {

    require(sqrtPriceX96 != 0, "zero input price");
    require((sqrtPriceX96 < TickMath.MAX_SQRT_RATIO) && (sqrtPriceX96 >= TickMath.MIN_SQRT_RATIO), "R"); 

    /// @dev initializeVAMM should only be callable given the initialize function was already executed
    /// @dev we can check if the initialize function was executed by making sure the address of the margin engine is non-zero since it is set in the initialize function
    require(address(_marginEngine) != address(0), "vamm not initialized");

    if (_vammVars.sqrtPriceX96 != 0)  {
      revert CustomErrors.ExpectedSqrtPriceZeroBeforeInit(_vammVars.sqrtPriceX96);
    }

    int24 tick = TickMath.getTickAtSqrtRatio(sqrtPriceX96);

    _vammVars = VAMMVars({ sqrtPriceX96: sqrtPriceX96, tick: tick, feeProtocol: 0 });

    _unlocked = true;

    emit VAMMInitialization(sqrtPriceX96, tick);
  }

  function setFeeProtocol(uint8 feeProtocol) external override onlyOwner {
    require(feeProtocol == 0 || (feeProtocol >= 3 && feeProtocol <= 50), "PR range");

    _vammVars.feeProtocol = feeProtocol;
    emit FeeProtocol(feeProtocol);
  }

  function setFee(uint256 newFeeWad) external override onlyOwner {
    require(newFeeWad >= 0 && newFeeWad <= MAX_FEE, "fee range");

    _feeWad = newFeeWad;
    emit Fee(_feeWad);
  }

  
  /// @inheritdoc IVAMM
  function setIsAlpha(bool __isAlpha) external override onlyOwner {
    _isAlpha = __isAlpha;
    emit IsAlpha(_isAlpha);
  }

  function burn(
    address recipient,
    int24 tickLower,
    int24 tickUpper,
    uint128 amount
  ) external override checkIsAlphaBurn whenNotPaused lock returns(int256 positionMarginRequirement) {

    /// @dev if msg.sender is the MarginEngine, it is a burn induced by a position liquidation

    if (amount <= 0) {
      revert CustomErrors.LiquidityDeltaMustBePositiveInBurn(amount);
    }

    require((msg.sender==recipient) || (msg.sender == address(_marginEngine)) || _factory.isApproved(recipient, msg.sender) , "MS or ME");

    positionMarginRequirement = updatePosition(
      ModifyPositionParams({
        owner: recipient,
        tickLower: tickLower,
        tickUpper: tickUpper,
        liquidityDelta: -int256(uint256(amount)).toInt128()
      })
    );

    emit Burn(msg.sender, recipient, tickLower, tickUpper, amount);
  }

  function flipTicks(ModifyPositionParams memory params)
    internal
    returns (bool flippedLower, bool flippedUpper)
  {

    Tick.checkTicks(params.tickLower, params.tickUpper);


    /// @dev isUpper = false
    flippedLower = _ticks.update(
      params.tickLower,
      _vammVars.tick,
      params.liquidityDelta,
      _fixedTokenGrowthGlobalX128,
      _variableTokenGrowthGlobalX128,
      _feeGrowthGlobalX128,
      false,
      _maxLiquidityPerTick
    );

    /// @dev isUpper = true
    flippedUpper = _ticks.update(
      params.tickUpper,
      _vammVars.tick,
      params.liquidityDelta,
      _fixedTokenGrowthGlobalX128,
      _variableTokenGrowthGlobalX128,
      _feeGrowthGlobalX128,
      true,
      _maxLiquidityPerTick
    );

    if (flippedLower) {
      _tickBitmap.flipTick(params.tickLower, _tickSpacing);
    }

    if (flippedUpper) {
      _tickBitmap.flipTick(params.tickUpper, _tickSpacing);
    }
  }


  function updatePosition(ModifyPositionParams memory params) private returns(int256 positionMarginRequirement) {

    /// @dev give a more descriptive name

    Tick.checkTicks(params.tickLower, params.tickUpper);

    VAMMVars memory lvammVars = _vammVars; // SLOAD for gas optimization

    bool flippedLower;
    bool flippedUpper;

    /// @dev update the ticks if necessary
    if (params.liquidityDelta != 0) {
      (flippedLower, flippedUpper) = flipTicks(params);
    }

    positionMarginRequirement = 0;
    if (msg.sender != address(_marginEngine)) {
      // this only happens if the margin engine triggers a liquidation which in turn triggers a burn
      // the state updated in the margin engine in that case are done directly in the liquidatePosition function
      positionMarginRequirement = _marginEngine.updatePositionPostVAMMInducedMintBurn(params);
    }

    // clear any tick data that is no longer needed
    if (params.liquidityDelta < 0) {
      if (flippedLower) {
        _ticks.clear(params.tickLower);
      }
      if (flippedUpper) {
        _ticks.clear(params.tickUpper);
      }
    }

    rateOracle.writeOracleEntry();

    if (params.liquidityDelta != 0) {
      if (
        (lvammVars.tick >= params.tickLower) && (lvammVars.tick < params.tickUpper)
      ) {
        // current tick is inside the passed range
        uint128 liquidityBefore = _liquidity; // SLOAD for gas optimization

        _liquidity = LiquidityMath.addDelta(
          liquidityBefore,
          params.liquidityDelta
        );
      }
    }
  }

  /// @inheritdoc IVAMM
  function mint(
    address recipient,
    int24 tickLower,
    int24 tickUpper,
    uint128 amount
  ) external override checkIsAlpha whenNotPaused checkCurrentTimestampTermEndTimestampDelta lock returns(int256 positionMarginRequirement) {
    
    /// might be helpful to have a higher level peripheral function for minting a given amount given a certain amount of notional an LP wants to support

    if (amount <= 0) {
      revert CustomErrors.LiquidityDeltaMustBePositiveInMint(amount);
    }

    require(msg.sender==recipient || _factory.isApproved(recipient, msg.sender), "only msg.sender or approved can mint");

    positionMarginRequirement = updatePosition(
      ModifyPositionParams({
        owner: recipient,
        tickLower: tickLower,
        tickUpper: tickUpper,
        liquidityDelta: int256(uint256(amount)).toInt128()
      })
    );

    emit Mint(msg.sender, recipient, tickLower, tickUpper, amount);
  }


  /// @inheritdoc IVAMM
  function swap(SwapParams memory params)
    external
    override
    whenNotPaused
    checkCurrentTimestampTermEndTimestampDelta
    returns (int256 fixedTokenDelta, int256 variableTokenDelta, uint256 cumulativeFeeIncurred, int256 fixedTokenDeltaUnbalanced, int256 marginRequirement)
  {

    Tick.checkTicks(params.tickLower, params.tickUpper);

    VAMMVars memory vammVarsStart = _vammVars;

    checksBeforeSwap(params, vammVarsStart, params.amountSpecified > 0);

    if (!(msg.sender == address(_marginEngine) || msg.sender==address(_marginEngine.fcm()))) {
      require(msg.sender==params.recipient || _factory.isApproved(params.recipient, msg.sender), "only sender or approved integration");
    }

    /// @dev lock the vamm while the swap is taking place
    _unlocked = false;

    SwapCache memory cache = SwapCache({
      liquidityStart: _liquidity,
      feeProtocol: _vammVars.feeProtocol
    });

    /// @dev amountSpecified = The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
    /// @dev Both FTs and VTs care about the notional of their IRS contract, the notional is the absolute amount of variableTokens traded
    /// @dev Hence, if an FT wishes to trade x notional, amountSpecified needs to be an exact input (in terms of the variableTokens they provide), hence amountSpecified needs to be positive
    /// @dev Also, if a VT wishes to trade x notional, amountSpecified needs to be an exact output (in terms of the variableTokens they receive), hence amountSpecified needs to be negative
    /// @dev amountCalculated is the amount already swapped out/in of the output (variable taker) / input (fixed taker) asset
    /// @dev amountSpecified should always be in terms of the variable tokens

    SwapState memory state = SwapState({
      amountSpecifiedRemaining: params.amountSpecified,
      amountCalculated: 0,
      sqrtPriceX96: vammVarsStart.sqrtPriceX96,
      tick: vammVarsStart.tick,
      liquidity: cache.liquidityStart,
      fixedTokenGrowthGlobalX128: _fixedTokenGrowthGlobalX128,
      variableTokenGrowthGlobalX128: _variableTokenGrowthGlobalX128,
      feeGrowthGlobalX128: _feeGrowthGlobalX128,
      protocolFee: 0,
      cumulativeFeeIncurred: 0,
      fixedTokenDeltaCumulative: 0, // for Trader (user invoking the swap)
      variableTokenDeltaCumulative: 0, // for Trader (user invoking the swap),
      fixedTokenDeltaUnbalancedCumulative: 0, //  for Trader (user invoking the swap)
      variableFactorWad: rateOracle.variableFactor(termStartTimestampWad, termEndTimestampWad)
    });

    /// @dev write an entry to the rate oracle (given no throttling)

    rateOracle.writeOracleEntry();

    // continue swapping as long as we haven't used the entire input/output and haven't reached the price (implied fixed rate) limit
    if (params.amountSpecified > 0) {
      // Fixed Taker
      while (
      state.amountSpecifiedRemaining != 0 &&
      state.sqrtPriceX96 != params.sqrtPriceLimitX96
    ) {
      StepComputations memory step;

      step.sqrtPriceStartX96 = state.sqrtPriceX96;

      /// the nextInitializedTick should be more than or equal to the current tick
      /// add a test for the statement that checks for the above two conditions
      (step.tickNext, step.initialized) = _tickBitmap
        .nextInitializedTickWithinOneWord(state.tick, _tickSpacing, false);

      // ensure that we do not overshoot the min/max tick, as the tick bitmap is not aware of these bounds
      if (step.tickNext > TickMath.MAX_TICK) {
        step.tickNext = TickMath.MAX_TICK;
      }

      // get the price for the next tick
      step.sqrtPriceNextX96 = TickMath.getSqrtRatioAtTick(step.tickNext);

      // compute values to swap to the target tick, price limit, or point where input/output amount is exhausted
      /// @dev for a Fixed Taker (isFT) if the sqrtPriceNextX96 is larger than the limit, then the target price passed into computeSwapStep is sqrtPriceLimitX96
      /// @dev for a Variable Taker (!isFT) if the sqrtPriceNextX96 is lower than the limit, then the target price passed into computeSwapStep is sqrtPriceLimitX96
      (
        state.sqrtPriceX96,
        step.amountIn,
        step.amountOut,
        step.feeAmount
      ) = SwapMath.computeSwapStep(
        SwapMath.SwapStepParams({
            sqrtRatioCurrentX96: state.sqrtPriceX96,
            sqrtRatioTargetX96: step.sqrtPriceNextX96 > params.sqrtPriceLimitX96
          ? params.sqrtPriceLimitX96
          : step.sqrtPriceNextX96,
            liquidity: state.liquidity,
            amountRemaining: state.amountSpecifiedRemaining,
            feePercentageWad: _feeWad,
            timeToMaturityInSecondsWad: termEndTimestampWad - Time.blockTimestampScaled()
        })
      );

      // exact input
      /// prb math is not used in here (following v3 logic)
      state.amountSpecifiedRemaining -= (step.amountIn).toInt256(); // this value is positive
      state.amountCalculated -= step.amountOut.toInt256(); // this value is negative

      // LP is a Variable Taker
      step.variableTokenDelta = (step.amountIn).toInt256();
      step.fixedTokenDeltaUnbalanced = -step.amountOut.toInt256();

      // update cumulative fee incurred while initiating an interest rate swap
      state.cumulativeFeeIncurred += step.feeAmount;

      // if the protocol fee is on, calculate how much is owed, decrement feeAmount, and increment protocolFee
      if (cache.feeProtocol > 0) {
        /// here we should round towards protocol fees (+ ((step.feeAmount % cache.feeProtocol == 0) ? 0 : 1)) ?
        step.feeProtocolDelta = step.feeAmount / cache.feeProtocol;
        step.feeAmount -= step.feeProtocolDelta;
        state.protocolFee += step.feeProtocolDelta;
      }

      // update global fee tracker
      if (state.liquidity > 0) {
        (
          state.feeGrowthGlobalX128,
          state.variableTokenGrowthGlobalX128,
          state.fixedTokenGrowthGlobalX128,
          step.fixedTokenDelta // for LP
        ) = calculateUpdatedGlobalTrackerValues(
          state,
          step
        );

        state.fixedTokenDeltaCumulative -= step.fixedTokenDelta; // opposite sign from that of the LP's
        state.variableTokenDeltaCumulative -= step.variableTokenDelta; // opposite sign from that of the LP's

        // necessary for testing purposes, also handy to quickly compute the fixed rate at which an interest rate swap is created
        state.fixedTokenDeltaUnbalancedCumulative -= step.fixedTokenDeltaUnbalanced;
      }

      // shift tick if we reached the next price
      if (state.sqrtPriceX96 == step.sqrtPriceNextX96) {
        // if the tick is initialized, run the tick transition
        if (step.initialized) {
          int128 liquidityNet = _ticks.cross(
            step.tickNext,
            state.fixedTokenGrowthGlobalX128,
            state.variableTokenGrowthGlobalX128,
            state.feeGrowthGlobalX128
          );

          state.liquidity = LiquidityMath.addDelta(
            state.liquidity,
            liquidityNet
          );

        }

        state.tick = step.tickNext;
      } else if (state.sqrtPriceX96 != step.sqrtPriceStartX96) {
        // recompute unless we're on a lower tick boundary (i.e. already transitioned ticks), and haven't moved
        state.tick = TickMath.getTickAtSqrtRatio(state.sqrtPriceX96);
      }
    }
    }
    else {
      while (
      state.amountSpecifiedRemaining != 0 &&
      state.sqrtPriceX96 != params.sqrtPriceLimitX96
    ) {
      StepComputations memory step;

      step.sqrtPriceStartX96 = state.sqrtPriceX96;

      /// @dev if isFT (fixed taker) (moving right to left), the nextInitializedTick should be more than or equal to the current tick
      /// @dev if !isFT (variable taker) (moving left to right), the nextInitializedTick should be less than or equal to the current tick
      /// add a test for the statement that checks for the above two conditions
      (step.tickNext, step.initialized) = _tickBitmap
        .nextInitializedTickWithinOneWord(state.tick, _tickSpacing, true);

      // ensure that we do not overshoot the min/max tick, as the tick bitmap is not aware of these bounds
      if (step.tickNext < TickMath.MIN_TICK) {
        step.tickNext = TickMath.MIN_TICK;
      }

      // get the price for the next tick
      step.sqrtPriceNextX96 = TickMath.getSqrtRatioAtTick(step.tickNext);

      // compute values to swap to the target tick, price limit, or point where input/output amount is exhausted
      /// @dev for a Fixed Taker (isFT) if the sqrtPriceNextX96 is larger than the limit, then the target price passed into computeSwapStep is sqrtPriceLimitX96
      /// @dev for a Variable Taker (!isFT) if the sqrtPriceNextX96 is lower than the limit, then the target price passed into computeSwapStep is sqrtPriceLimitX96
      (
        state.sqrtPriceX96,
        step.amountIn,
        step.amountOut,
        step.feeAmount
      ) = SwapMath.computeSwapStep(

        SwapMath.SwapStepParams({
            sqrtRatioCurrentX96: state.sqrtPriceX96,
            sqrtRatioTargetX96: step.sqrtPriceNextX96 < params.sqrtPriceLimitX96
          ? params.sqrtPriceLimitX96
          : step.sqrtPriceNextX96,
            liquidity: state.liquidity,
            amountRemaining: state.amountSpecifiedRemaining,
            feePercentageWad: _feeWad,
            timeToMaturityInSecondsWad: termEndTimestampWad - Time.blockTimestampScaled()
        })

      );

      /// prb math is not used in here (following v3 logic)
      state.amountSpecifiedRemaining += step.amountOut.toInt256(); // this value is negative
      state.amountCalculated += step.amountIn.toInt256(); // this value is positive

      // LP is a Fixed Taker
      step.variableTokenDelta = -step.amountOut.toInt256();
      step.fixedTokenDeltaUnbalanced = step.amountIn.toInt256();

      // update cumulative fee incurred while initiating an interest rate swap
      state.cumulativeFeeIncurred = state.cumulativeFeeIncurred + step.feeAmount;

      // if the protocol fee is on, calculate how much is owed, decrement feeAmount, and increment protocolFee
      if (cache.feeProtocol > 0) {
        /// here we should round towards protocol fees (+ ((step.feeAmount % cache.feeProtocol == 0) ? 0 : 1)) ?
        step.feeProtocolDelta = step.feeAmount / cache.feeProtocol;
        step.feeAmount -= step.feeProtocolDelta;
        state.protocolFee += step.feeProtocolDelta;
      }

      // update global fee tracker
      if (state.liquidity > 0) {
        (
          state.feeGrowthGlobalX128,
          state.variableTokenGrowthGlobalX128,
          state.fixedTokenGrowthGlobalX128,
          step.fixedTokenDelta // for LP
        ) = calculateUpdatedGlobalTrackerValues(
          state,
          step
        );

        state.fixedTokenDeltaCumulative -= step.fixedTokenDelta; // opposite sign from that of the LP's
        state.variableTokenDeltaCumulative -= step.variableTokenDelta; // opposite sign from that of the LP's

        // necessary for testing purposes, also handy to quickly compute the fixed rate at which an interest rate swap is created
        state.fixedTokenDeltaUnbalancedCumulative -= step.fixedTokenDeltaUnbalanced;
      }

      // shift tick if we reached the next price
      if (state.sqrtPriceX96 == step.sqrtPriceNextX96) {
        // if the tick is initialized, run the tick transition
        if (step.initialized) {
          int128 liquidityNet = _ticks.cross(
            step.tickNext,
            state.fixedTokenGrowthGlobalX128,
            state.variableTokenGrowthGlobalX128,
            state.feeGrowthGlobalX128
          );

          state.liquidity = LiquidityMath.addDelta(
            state.liquidity,
            -liquidityNet
          );

        }

        state.tick = step.tickNext - 1;
      } else if (state.sqrtPriceX96 != step.sqrtPriceStartX96) {
        // recompute unless we're on a lower tick boundary (i.e. already transitioned ticks), and haven't moved
        state.tick = TickMath.getTickAtSqrtRatio(state.sqrtPriceX96);
      }
    }
    }
    _vammVars.sqrtPriceX96 = state.sqrtPriceX96;

    if (state.tick != vammVarsStart.tick) {
       // update the tick in case it changed
      _vammVars.tick = state.tick;
    }

    // update liquidity if it changed
    if (cache.liquidityStart != state.liquidity) _liquidity = state.liquidity;

    _feeGrowthGlobalX128 = state.feeGrowthGlobalX128;
    _variableTokenGrowthGlobalX128 = state.variableTokenGrowthGlobalX128;
    _fixedTokenGrowthGlobalX128 = state.fixedTokenGrowthGlobalX128;

    cumulativeFeeIncurred = state.cumulativeFeeIncurred;
    fixedTokenDelta = state.fixedTokenDeltaCumulative;
    variableTokenDelta = state.variableTokenDeltaCumulative;
    fixedTokenDeltaUnbalanced = state.fixedTokenDeltaUnbalancedCumulative;

    if (state.protocolFee > 0) {
      _protocolFees += state.protocolFee;
    }

    /// @dev if it is an unwind then state change happen direcly in the MarginEngine to avoid making an unnecessary external call
    if (!(msg.sender == address(_marginEngine) || msg.sender==address(_marginEngine.fcm()))) {
      marginRequirement = _marginEngine.updatePositionPostVAMMInducedSwap(params.recipient, params.tickLower, params.tickUpper, state.fixedTokenDeltaCumulative, state.variableTokenDeltaCumulative, state.cumulativeFeeIncurred, state.fixedTokenDeltaUnbalancedCumulative);
    }

    emit VAMMPriceChange(_vammVars.tick);

    emit Swap(
      msg.sender,
      params.recipient,
      params.tickLower,
      params.tickUpper,
      params.amountSpecified,
      params.sqrtPriceLimitX96,
      cumulativeFeeIncurred,
      fixedTokenDelta,
      variableTokenDelta,
      fixedTokenDeltaUnbalanced
    );

    _unlocked = true;
  }

  /// @inheritdoc IVAMM
  function computeGrowthInside(
    int24 tickLower,
    int24 tickUpper
  )
    external
    view
    override
    returns (int256 fixedTokenGrowthInsideX128, int256 variableTokenGrowthInsideX128, uint256 feeGrowthInsideX128)
  {

    Tick.checkTicks(tickLower, tickUpper);

    fixedTokenGrowthInsideX128 = _ticks.getFixedTokenGrowthInside(
      Tick.FixedTokenGrowthInsideParams({
        tickLower: tickLower,
        tickUpper: tickUpper,
        tickCurrent: _vammVars.tick,
        fixedTokenGrowthGlobalX128: _fixedTokenGrowthGlobalX128
      })
    );

    variableTokenGrowthInsideX128 = _ticks.getVariableTokenGrowthInside(
      Tick.VariableTokenGrowthInsideParams({
        tickLower: tickLower,
        tickUpper: tickUpper,
        tickCurrent: _vammVars.tick,
        variableTokenGrowthGlobalX128: _variableTokenGrowthGlobalX128
      })
    );

    feeGrowthInsideX128 = _ticks.getFeeGrowthInside(
      Tick.FeeGrowthInsideParams({
        tickLower: tickLower,
        tickUpper: tickUpper,
        tickCurrent: _vammVars.tick,
        feeGrowthGlobalX128: _feeGrowthGlobalX128
      })
    );

  }

  function checksBeforeSwap(
      SwapParams memory params,
      VAMMVars memory vammVarsStart,
      bool isFT
  ) internal view {

      if (params.amountSpecified == 0) {
          revert CustomErrors.IRSNotionalAmountSpecifiedMustBeNonZero();
      }

      if (!_unlocked) {
          revert CustomErrors.CanOnlyTradeIfUnlocked(_unlocked);
      }

      /// @dev if a trader is an FT, they consume fixed in return for variable
      /// @dev Movement from right to left along the VAMM, hence the sqrtPriceLimitX96 needs to be higher than the current sqrtPriceX96, but lower than the MAX_SQRT_RATIO
      /// @dev if a trader is a VT, they consume variable in return for fixed
      /// @dev Movement from left to right along the VAMM, hence the sqrtPriceLimitX96 needs to be lower than the current sqrtPriceX96, but higher than the MIN_SQRT_RATIO

      require(
          isFT
              ? params.sqrtPriceLimitX96 > vammVarsStart.sqrtPriceX96 &&
                  params.sqrtPriceLimitX96 < TickMath.MAX_SQRT_RATIO
              : params.sqrtPriceLimitX96 < vammVarsStart.sqrtPriceX96 &&
                  params.sqrtPriceLimitX96 > TickMath.MIN_SQRT_RATIO,
          "SPL"
      );
  }

    function calculateUpdatedGlobalTrackerValues(
        SwapState memory state,
        StepComputations memory step
    )
        internal
        view
        returns (
            uint256 stateFeeGrowthGlobalX128,
            int256 stateVariableTokenGrowthGlobalX128,
            int256 stateFixedTokenGrowthGlobalX128,
            int256 fixedTokenDelta// for LP
        )
    {

        stateFeeGrowthGlobalX128 = state.feeGrowthGlobalX128 + FullMath.mulDiv(step.feeAmount, FixedPoint128.Q128, state.liquidity);

        fixedTokenDelta = FixedAndVariableMath.getFixedTokenBalance(
          step.fixedTokenDeltaUnbalanced,
          step.variableTokenDelta,
          state.variableFactorWad,
          termStartTimestampWad,
          termEndTimestampWad
        );

        stateVariableTokenGrowthGlobalX128 = state.variableTokenGrowthGlobalX128 + FullMath.mulDivSigned(step.variableTokenDelta, FixedPoint128.Q128, state.liquidity);

        stateFixedTokenGrowthGlobalX128 = state.fixedTokenGrowthGlobalX128 + FullMath.mulDivSigned(fixedTokenDelta, FixedPoint128.Q128, state.liquidity);
    }

}

File 2 of 41 : OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 3 of 41 : draft-IERC1822Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)

pragma solidity ^0.8.0;

/**
 * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
 * proxy whose upgrades are fully controlled by the current implementation.
 */
interface IERC1822ProxiableUpgradeable {
    /**
     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
     * address.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy.
     */
    function proxiableUUID() external view returns (bytes32);
}

File 4 of 41 : ERC1967UpgradeUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)

pragma solidity ^0.8.2;

import "../beacon/IBeaconUpgradeable.sol";
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../../utils/AddressUpgradeable.sol";
import "../../utils/StorageSlotUpgradeable.sol";
import "../utils/Initializable.sol";

/**
 * @dev This abstract contract provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
 *
 * _Available since v4.1._
 *
 * @custom:oz-upgrades-unsafe-allow delegatecall
 */
abstract contract ERC1967UpgradeUpgradeable is Initializable {
    function __ERC1967Upgrade_init() internal onlyInitializing {
    }

    function __ERC1967Upgrade_init_unchained() internal onlyInitializing {
    }
    // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;

    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev Emitted when the implementation is upgraded.
     */
    event Upgraded(address indexed implementation);

    /**
     * @dev Returns the current implementation address.
     */
    function _getImplementation() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 implementation slot.
     */
    function _setImplementation(address newImplementation) private {
        require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract");
        StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
    }

    /**
     * @dev Perform implementation upgrade
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeTo(address newImplementation) internal {
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);
    }

    /**
     * @dev Perform implementation upgrade with additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCall(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        _upgradeTo(newImplementation);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(newImplementation, data);
        }
    }

    /**
     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCallUUPS(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        // Upgrades from old implementations will perform a rollback test. This test requires the new
        // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
        // this special case will break upgrade paths from old UUPS implementation to new ones.
        if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {
            _setImplementation(newImplementation);
        } else {
            try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
            } catch {
                revert("ERC1967Upgrade: new implementation is not UUPS");
            }
            _upgradeToAndCall(newImplementation, data, forceCall);
        }
    }

    /**
     * @dev Storage slot with the admin of the contract.
     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
     * @dev Emitted when the admin account has changed.
     */
    event AdminChanged(address previousAdmin, address newAdmin);

    /**
     * @dev Returns the current admin.
     */
    function _getAdmin() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 admin slot.
     */
    function _setAdmin(address newAdmin) private {
        require(newAdmin != address(0), "ERC1967: new admin is the zero address");
        StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
    }

    /**
     * @dev Changes the admin of the proxy.
     *
     * Emits an {AdminChanged} event.
     */
    function _changeAdmin(address newAdmin) internal {
        emit AdminChanged(_getAdmin(), newAdmin);
        _setAdmin(newAdmin);
    }

    /**
     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
     * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
     */
    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

    /**
     * @dev Emitted when the beacon is upgraded.
     */
    event BeaconUpgraded(address indexed beacon);

    /**
     * @dev Returns the current beacon.
     */
    function _getBeacon() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
    }

    /**
     * @dev Stores a new beacon in the EIP1967 beacon slot.
     */
    function _setBeacon(address newBeacon) private {
        require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract");
        require(
            AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()),
            "ERC1967: beacon implementation is not a contract"
        );
        StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;
    }

    /**
     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
     *
     * Emits a {BeaconUpgraded} event.
     */
    function _upgradeBeaconToAndCall(
        address newBeacon,
        bytes memory data,
        bool forceCall
    ) internal {
        _setBeacon(newBeacon);
        emit BeaconUpgraded(newBeacon);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
        }
    }

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

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed");
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 5 of 41 : IBeaconUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)

pragma solidity ^0.8.0;

/**
 * @dev This is the interface that {BeaconProxy} expects of its beacon.
 */
interface IBeaconUpgradeable {
    /**
     * @dev Must return an address that can be used as a delegate call target.
     *
     * {BeaconProxy} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}

File 6 of 41 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
     * initialization step. This is essential to configure modules that are added through upgrades and that require
     * initialization.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }
}

File 7 of 41 : UUPSUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/UUPSUpgradeable.sol)

pragma solidity ^0.8.0;

import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../ERC1967/ERC1967UpgradeUpgradeable.sol";
import "./Initializable.sol";

/**
 * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
 * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
 *
 * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
 * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
 * `UUPSUpgradeable` with a custom implementation of upgrades.
 *
 * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
 *
 * _Available since v4.1._
 */
abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
    function __UUPSUpgradeable_init() internal onlyInitializing {
    }

    function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
    }
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
    address private immutable __self = address(this);

    /**
     * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
     * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
     * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
     * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
     * fail.
     */
    modifier onlyProxy() {
        require(address(this) != __self, "Function must be called through delegatecall");
        require(_getImplementation() == __self, "Function must be called through active proxy");
        _;
    }

    /**
     * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
     * callable on the implementing contract but not through proxies.
     */
    modifier notDelegated() {
        require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
        _;
    }

    /**
     * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
     * implementation. It is used to validate that the this implementation remains valid after an upgrade.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
     */
    function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
        return _IMPLEMENTATION_SLOT;
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     */
    function upgradeTo(address newImplementation) external virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
     * encoded in `data`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, data, true);
    }

    /**
     * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
     * {upgradeTo} and {upgradeToAndCall}.
     *
     * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
     *
     * ```solidity
     * function _authorizeUpgrade(address) internal override onlyOwner {}
     * ```
     */
    function _authorizeUpgrade(address newImplementation) internal virtual;

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 8 of 41 : AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

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

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

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

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

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

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

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

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

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

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 9 of 41 : ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 10 of 41 : StorageSlotUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)

pragma solidity ^0.8.0;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
 */
library StorageSlotUpgradeable {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }
}

File 11 of 41 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/SafeCast.sol)

pragma solidity ^0.8.0;

/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 *
 * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` and then downcasting.
 */
library SafeCast {
    /**
     * @dev Returns the downcasted uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     *
     * _Available since v4.7._
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     *
     * _Available since v4.7._
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     *
     * _Available since v4.7._
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
        return uint232(value);
    }

    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     *
     * _Available since v4.2._
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     *
     * _Available since v4.7._
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     *
     * _Available since v4.7._
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     *
     * _Available since v4.7._
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     *
     * _Available since v4.7._
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     *
     * _Available since v4.7._
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     *
     * _Available since v4.7._
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     *
     * _Available since v4.7._
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     *
     * _Available since v4.7._
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     *
     * _Available since v4.7._
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     *
     * _Available since v4.7._
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     *
     * _Available since v4.7._
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
        return uint136(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v2.5._
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     *
     * _Available since v4.7._
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     *
     * _Available since v4.7._
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     *
     * _Available since v4.7._
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
        return uint104(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     *
     * _Available since v4.2._
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     *
     * _Available since v4.7._
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     *
     * _Available since v4.7._
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     *
     * _Available since v4.7._
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
        return uint72(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v2.5._
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     *
     * _Available since v4.7._
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     *
     * _Available since v4.7._
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     *
     * _Available since v4.7._
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v2.5._
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     *
     * _Available since v4.7._
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
        return uint24(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v2.5._
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     *
     * _Available since v2.5._
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     *
     * _Available since v3.0._
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     *
     * _Available since v4.7._
     */
    function toInt248(int256 value) internal pure returns (int248) {
        require(value >= type(int248).min && value <= type(int248).max, "SafeCast: value doesn't fit in 248 bits");
        return int248(value);
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     *
     * _Available since v4.7._
     */
    function toInt240(int256 value) internal pure returns (int240) {
        require(value >= type(int240).min && value <= type(int240).max, "SafeCast: value doesn't fit in 240 bits");
        return int240(value);
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     *
     * _Available since v4.7._
     */
    function toInt232(int256 value) internal pure returns (int232) {
        require(value >= type(int232).min && value <= type(int232).max, "SafeCast: value doesn't fit in 232 bits");
        return int232(value);
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     *
     * _Available since v4.7._
     */
    function toInt224(int256 value) internal pure returns (int224) {
        require(value >= type(int224).min && value <= type(int224).max, "SafeCast: value doesn't fit in 224 bits");
        return int224(value);
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     *
     * _Available since v4.7._
     */
    function toInt216(int256 value) internal pure returns (int216) {
        require(value >= type(int216).min && value <= type(int216).max, "SafeCast: value doesn't fit in 216 bits");
        return int216(value);
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     *
     * _Available since v4.7._
     */
    function toInt208(int256 value) internal pure returns (int208) {
        require(value >= type(int208).min && value <= type(int208).max, "SafeCast: value doesn't fit in 208 bits");
        return int208(value);
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     *
     * _Available since v4.7._
     */
    function toInt200(int256 value) internal pure returns (int200) {
        require(value >= type(int200).min && value <= type(int200).max, "SafeCast: value doesn't fit in 200 bits");
        return int200(value);
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     *
     * _Available since v4.7._
     */
    function toInt192(int256 value) internal pure returns (int192) {
        require(value >= type(int192).min && value <= type(int192).max, "SafeCast: value doesn't fit in 192 bits");
        return int192(value);
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     *
     * _Available since v4.7._
     */
    function toInt184(int256 value) internal pure returns (int184) {
        require(value >= type(int184).min && value <= type(int184).max, "SafeCast: value doesn't fit in 184 bits");
        return int184(value);
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     *
     * _Available since v4.7._
     */
    function toInt176(int256 value) internal pure returns (int176) {
        require(value >= type(int176).min && value <= type(int176).max, "SafeCast: value doesn't fit in 176 bits");
        return int176(value);
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     *
     * _Available since v4.7._
     */
    function toInt168(int256 value) internal pure returns (int168) {
        require(value >= type(int168).min && value <= type(int168).max, "SafeCast: value doesn't fit in 168 bits");
        return int168(value);
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     *
     * _Available since v4.7._
     */
    function toInt160(int256 value) internal pure returns (int160) {
        require(value >= type(int160).min && value <= type(int160).max, "SafeCast: value doesn't fit in 160 bits");
        return int160(value);
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     *
     * _Available since v4.7._
     */
    function toInt152(int256 value) internal pure returns (int152) {
        require(value >= type(int152).min && value <= type(int152).max, "SafeCast: value doesn't fit in 152 bits");
        return int152(value);
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     *
     * _Available since v4.7._
     */
    function toInt144(int256 value) internal pure returns (int144) {
        require(value >= type(int144).min && value <= type(int144).max, "SafeCast: value doesn't fit in 144 bits");
        return int144(value);
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     *
     * _Available since v4.7._
     */
    function toInt136(int256 value) internal pure returns (int136) {
        require(value >= type(int136).min && value <= type(int136).max, "SafeCast: value doesn't fit in 136 bits");
        return int136(value);
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v3.1._
     */
    function toInt128(int256 value) internal pure returns (int128) {
        require(value >= type(int128).min && value <= type(int128).max, "SafeCast: value doesn't fit in 128 bits");
        return int128(value);
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     *
     * _Available since v4.7._
     */
    function toInt120(int256 value) internal pure returns (int120) {
        require(value >= type(int120).min && value <= type(int120).max, "SafeCast: value doesn't fit in 120 bits");
        return int120(value);
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     *
     * _Available since v4.7._
     */
    function toInt112(int256 value) internal pure returns (int112) {
        require(value >= type(int112).min && value <= type(int112).max, "SafeCast: value doesn't fit in 112 bits");
        return int112(value);
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     *
     * _Available since v4.7._
     */
    function toInt104(int256 value) internal pure returns (int104) {
        require(value >= type(int104).min && value <= type(int104).max, "SafeCast: value doesn't fit in 104 bits");
        return int104(value);
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     *
     * _Available since v4.7._
     */
    function toInt96(int256 value) internal pure returns (int96) {
        require(value >= type(int96).min && value <= type(int96).max, "SafeCast: value doesn't fit in 96 bits");
        return int96(value);
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     *
     * _Available since v4.7._
     */
    function toInt88(int256 value) internal pure returns (int88) {
        require(value >= type(int88).min && value <= type(int88).max, "SafeCast: value doesn't fit in 88 bits");
        return int88(value);
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     *
     * _Available since v4.7._
     */
    function toInt80(int256 value) internal pure returns (int80) {
        require(value >= type(int80).min && value <= type(int80).max, "SafeCast: value doesn't fit in 80 bits");
        return int80(value);
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     *
     * _Available since v4.7._
     */
    function toInt72(int256 value) internal pure returns (int72) {
        require(value >= type(int72).min && value <= type(int72).max, "SafeCast: value doesn't fit in 72 bits");
        return int72(value);
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v3.1._
     */
    function toInt64(int256 value) internal pure returns (int64) {
        require(value >= type(int64).min && value <= type(int64).max, "SafeCast: value doesn't fit in 64 bits");
        return int64(value);
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     *
     * _Available since v4.7._
     */
    function toInt56(int256 value) internal pure returns (int56) {
        require(value >= type(int56).min && value <= type(int56).max, "SafeCast: value doesn't fit in 56 bits");
        return int56(value);
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     *
     * _Available since v4.7._
     */
    function toInt48(int256 value) internal pure returns (int48) {
        require(value >= type(int48).min && value <= type(int48).max, "SafeCast: value doesn't fit in 48 bits");
        return int48(value);
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     *
     * _Available since v4.7._
     */
    function toInt40(int256 value) internal pure returns (int40) {
        require(value >= type(int40).min && value <= type(int40).max, "SafeCast: value doesn't fit in 40 bits");
        return int40(value);
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v3.1._
     */
    function toInt32(int256 value) internal pure returns (int32) {
        require(value >= type(int32).min && value <= type(int32).max, "SafeCast: value doesn't fit in 32 bits");
        return int32(value);
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     *
     * _Available since v4.7._
     */
    function toInt24(int256 value) internal pure returns (int24) {
        require(value >= type(int24).min && value <= type(int24).max, "SafeCast: value doesn't fit in 24 bits");
        return int24(value);
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v3.1._
     */
    function toInt16(int256 value) internal pure returns (int16) {
        require(value >= type(int16).min && value <= type(int16).max, "SafeCast: value doesn't fit in 16 bits");
        return int16(value);
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     *
     * _Available since v3.1._
     */
    function toInt8(int256 value) internal pure returns (int8) {
        require(value >= type(int8).min && value <= type(int8).max, "SafeCast: value doesn't fit in 8 bits");
        return int8(value);
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     *
     * _Available since v3.0._
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
        return int256(value);
    }
}

File 12 of 41 : FixedAndVariableMath.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity =0.8.9;
import "prb-math/contracts/PRBMathSD59x18.sol";
import "prb-math/contracts/PRBMathUD60x18.sol";
import "./Time.sol";

/// @title A utility library for mathematics of fixed and variable token amounts.
library FixedAndVariableMath {
    using PRBMathSD59x18 for int256;
    using PRBMathUD60x18 for uint256;

    /// @notice Number of wei-seconds in a year
    /// @dev Ignoring leap years since we're only using it to calculate the eventual APY rate

    uint256 public constant SECONDS_IN_YEAR_IN_WAD = 31536000e18;
    uint256 public constant ONE_HUNDRED_IN_WAD = 100e18;

    /// @notice Caclulate the remaining cashflow to settle a position
    /// @param fixedTokenBalance The current balance of the fixed side of the position
    /// @param variableTokenBalance The current balance of the variable side of the position
    /// @param termStartTimestampWad When did the position begin, in seconds
    /// @param termEndTimestampWad When does the position reach maturity, in seconds
    /// @param variableFactorToMaturityWad What factor expresses the current remaining variable rate, up to position maturity? (in wad)
    /// @return cashflow The remaining cashflow of the position
    function calculateSettlementCashflow(
        int256 fixedTokenBalance,
        int256 variableTokenBalance,
        uint256 termStartTimestampWad,
        uint256 termEndTimestampWad,
        uint256 variableFactorToMaturityWad
    ) internal view returns (int256 cashflow) {
        /// @dev convert fixed and variable token balances to their respective fixed token representations

        int256 fixedTokenBalanceWad = fixedTokenBalance.fromInt();
        int256 variableTokenBalanceWad = variableTokenBalance.fromInt();
        int256 fixedCashflowWad = fixedTokenBalanceWad.mul(
            int256(
                fixedFactor(true, termStartTimestampWad, termEndTimestampWad)
            )
        );

        int256 variableCashflowWad = variableTokenBalanceWad.mul(
            int256(variableFactorToMaturityWad)
        );

        int256 cashflowWad = fixedCashflowWad + variableCashflowWad;

        /// @dev convert back to non-fixed point representation
        cashflow = cashflowWad.toInt();
    }

    /// @notice Divide a given time in seconds by the number of seconds in a year
    /// @param timeInSecondsAsWad A time in seconds in Wad (i.e. scaled up by 10^18)
    /// @return timeInYearsWad An annualised factor of timeInSeconds, also in Wad
    function accrualFact(uint256 timeInSecondsAsWad)
        internal
        pure
        returns (uint256 timeInYearsWad)
    {
        timeInYearsWad = timeInSecondsAsWad.div(SECONDS_IN_YEAR_IN_WAD);
    }

    /// @notice Calculate the fixed factor for a position - that is, the percentage earned over
    /// the specified period of time, assuming 1% per year
    /// @param atMaturity Whether to calculate the factor at maturity (true), or now (false)
    /// @param termStartTimestampWad When does the period of time begin, in wei-seconds
    /// @param termEndTimestampWad When does the period of time end, in wei-seconds
    /// @return fixedFactorValueWad The fixed factor for the position (in Wad)
    function fixedFactor(
        bool atMaturity,
        uint256 termStartTimestampWad,
        uint256 termEndTimestampWad
    ) internal view returns (uint256 fixedFactorValueWad) {
        require(termEndTimestampWad > termStartTimestampWad, "E<=S");

        uint256 currentTimestampWad = Time.blockTimestampScaled();

        require(currentTimestampWad >= termStartTimestampWad, "B.T<S");

        uint256 timeInSecondsWad;

        if (atMaturity || (currentTimestampWad >= termEndTimestampWad)) {
            timeInSecondsWad = termEndTimestampWad - termStartTimestampWad;
        } else {
            timeInSecondsWad = currentTimestampWad - termStartTimestampWad;
        }

        fixedFactorValueWad = accrualFact(timeInSecondsWad).div(
            ONE_HUNDRED_IN_WAD
        );
    }

    /// @notice Calculate the fixed token balance for a position over a timespan
    /// @param amountFixedWad  A fixed amount
    /// @param excessBalanceWad Cashflows accrued to the fixed and variable token amounts since the inception of the IRS AMM
    /// @param termStartTimestampWad When does the period of time begin, in wei-seconds
    /// @param termEndTimestampWad When does the period of time end, in wei-seconds
    /// @return fixedTokenBalanceWad The fixed token balance for that time period
    function calculateFixedTokenBalance(
        int256 amountFixedWad,
        int256 excessBalanceWad,
        uint256 termStartTimestampWad,
        uint256 termEndTimestampWad
    ) internal view returns (int256 fixedTokenBalanceWad) {
        require(termEndTimestampWad > termStartTimestampWad, "E<=S");

        return
            amountFixedWad -
            excessBalanceWad.div(
                int256(
                    fixedFactor(
                        true,
                        termStartTimestampWad,
                        termEndTimestampWad
                    )
                )
            );
    }

    /// @notice Calculate the excess balance of both sides of a position in Wad
    /// @param amountFixedWad A fixed balance
    /// @param amountVariableWad A variable balance
    /// @param accruedVariableFactorWad An annualised factor in wei-years
    /// @param termStartTimestampWad When does the period of time begin, in wei-seconds
    /// @param termEndTimestampWad When does the period of time end, in wei-seconds
    /// @return excessBalanceWad The excess balance in wad
    function getExcessBalance(
        int256 amountFixedWad,
        int256 amountVariableWad,
        uint256 accruedVariableFactorWad,
        uint256 termStartTimestampWad,
        uint256 termEndTimestampWad
    ) internal view returns (int256) {
        /// @dev cashflows accrued since the inception of the IRS AMM

        return
            amountFixedWad.mul(
                int256(
                    fixedFactor(
                        false,
                        termStartTimestampWad,
                        termEndTimestampWad
                    )
                )
            ) + amountVariableWad.mul(int256(accruedVariableFactorWad));
    }

    /// @notice Calculate the fixed token balance given both fixed and variable balances
    /// @param amountFixed A fixed balance
    /// @param amountVariable A variable balance
    /// @param accruedVariableFactorWad An annualised factor in wei-years
    /// @param termStartTimestampWad When does the period of time begin, in wei-seconds
    /// @param termEndTimestampWad When does the period of time end, in wei-seconds
    /// @return fixedTokenBalance The fixed token balance for that time period
    function getFixedTokenBalance(
        int256 amountFixed,
        int256 amountVariable,
        uint256 accruedVariableFactorWad,
        uint256 termStartTimestampWad,
        uint256 termEndTimestampWad
    ) internal view returns (int256 fixedTokenBalance) {
        require(termEndTimestampWad > termStartTimestampWad, "E<=S");

        if (amountFixed == 0 && amountVariable == 0) return 0;

        int256 amountFixedWad = amountFixed.fromInt();
        int256 amountVariableWad = amountVariable.fromInt();

        int256 excessBalanceWad = getExcessBalance(
            amountFixedWad,
            amountVariableWad,
            accruedVariableFactorWad,
            termStartTimestampWad,
            termEndTimestampWad
        );

        int256 fixedTokenBalanceWad = calculateFixedTokenBalance(
            amountFixedWad,
            excessBalanceWad,
            termStartTimestampWad,
            termEndTimestampWad
        );

        fixedTokenBalance = fixedTokenBalanceWad.toInt();
    }
}

File 13 of 41 : Position.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity =0.8.9;

import "../utils/LiquidityMath.sol";
import "../utils/FixedPoint128.sol";
import "../core_libraries/Tick.sol";
import "../utils/FullMath.sol";
import "prb-math/contracts/PRBMathSD59x18.sol";
import "prb-math/contracts/PRBMathUD60x18.sol";
import "@openzeppelin/contracts/utils/math/SafeCast.sol";

/// @title Position
/// @notice Positions represent an owner address' liquidity between a lower and upper tick boundary
/// @dev Positions store additional state for tracking fees owed to the position as well as their fixed and variable token balances
library Position {
    using Position for Info;

    // info stored for each user's position
    struct Info {
        // has the position been already burned
        // a burned position can no longer support new IRS contracts but still needs to cover settlement cash-flows of on-going IRS contracts it entered
        // bool isBurned;, equivalent to having zero liquidity
        // is position settled
        bool isSettled;
        // the amount of liquidity owned by this position
        uint128 _liquidity;
        // current margin of the position in terms of the underlyingToken
        int256 margin;
        // fixed token growth per unit of liquidity as of the last update to liquidity or fixed/variable token balance
        int256 fixedTokenGrowthInsideLastX128;
        // variable token growth per unit of liquidity as of the last update to liquidity or fixed/variable token balance
        int256 variableTokenGrowthInsideLastX128;
        // current Fixed Token balance of the position, 1 fixed token can be redeemed for 1% APY * (annualised amm term) at the maturity of the amm
        // assuming 1 token worth of notional "deposited" in the underlying pool at the inception of the amm
        // can be negative/positive/zero
        int256 fixedTokenBalance;
        // current Variable Token Balance of the position, 1 variable token can be redeemed for underlyingPoolAPY*(annualised amm term) at the maturity of the amm
        // assuming 1 token worth of notional "deposited" in the underlying pool at the inception of the amm
        // can be negative/positive/zero
        int256 variableTokenBalance;
        // fee growth per unit of liquidity as of the last update to liquidity or fees owed (via the margin)
        uint256 feeGrowthInsideLastX128;
        // amount of variable tokens at the initiation of liquidity
        uint256 rewardPerAmount;
        // amount of fees accumulated
        uint256 accumulatedFees;
    }

    /// @notice Returns the Info struct of a position, given an owner and position boundaries
    /// @param self The mapping containing all user positions
    /// @param owner The address of the position owner
    /// @param tickLower The lower tick boundary of the position
    /// @param tickUpper The upper tick boundary of the position
    /// @return position The position info struct of the given owners' position
    function get(
        mapping(bytes32 => Info) storage self,
        address owner,
        int24 tickLower,
        int24 tickUpper
    ) internal view returns (Position.Info storage position) {
        Tick.checkTicks(tickLower, tickUpper);

        position = self[
            keccak256(abi.encodePacked(owner, tickLower, tickUpper))
        ];
    }

    function settlePosition(Info storage self) internal {
        require(!self.isSettled, "already settled");
        self.isSettled = true;
    }

    /// @notice Updates the Info struct of a position by changing the amount of margin according to marginDelta
    /// @param self Position Info Struct of the Liquidity Provider
    /// @param marginDelta Change in the margin account of the position (in wei)
    function updateMarginViaDelta(Info storage self, int256 marginDelta)
        internal
    {
        self.margin += marginDelta;
    }

    /// @notice Updates the Info struct of a position by changing the fixed and variable token balances of the position
    /// @param self Position Info struct of the liquidity provider
    /// @param fixedTokenBalanceDelta Change in the number of fixed tokens in the position's fixed token balance
    /// @param variableTokenBalanceDelta Change in the number of variable tokens in the position's variable token balance
    function updateBalancesViaDeltas(
        Info storage self,
        int256 fixedTokenBalanceDelta,
        int256 variableTokenBalanceDelta
    ) internal {
        if (fixedTokenBalanceDelta | variableTokenBalanceDelta != 0) {
            self.fixedTokenBalance += fixedTokenBalanceDelta;
            self.variableTokenBalance += variableTokenBalanceDelta;
        }
    }

    /// @notice Returns Fee Delta = (feeGrowthInside-feeGrowthInsideLast) * liquidity of the position
    /// @param self position info struct represeting a liquidity provider
    /// @param feeGrowthInsideX128 fee growth per unit of liquidity as of now
    /// @return _feeDelta Fee Delta
    function calculateFeeDelta(Info storage self, uint256 feeGrowthInsideX128)
        internal
        pure
        returns (uint256 _feeDelta)
    {
        Info memory _self = self;

        /// @dev 0xZenus: The multiplication overflows, need to wrap the below expression in an unchecked block.
        unchecked {
            _feeDelta = FullMath.mulDiv(
                feeGrowthInsideX128 - _self.feeGrowthInsideLastX128,
                _self._liquidity,
                FixedPoint128.Q128
            );
        }
    }

    /// @notice Returns Fixed and Variable Token Deltas
    /// @param self position info struct represeting a liquidity provider
    /// @param fixedTokenGrowthInsideX128 fixed token growth per unit of liquidity as of now (in wei)
    /// @param variableTokenGrowthInsideX128 variable token growth per unit of liquidity as of now (in wei)
    /// @return _fixedTokenDelta = (fixedTokenGrowthInside-fixedTokenGrowthInsideLast) * liquidity of a position
    /// @return _variableTokenDelta = (variableTokenGrowthInside-variableTokenGrowthInsideLast) * liquidity of a position
    function calculateFixedAndVariableDelta(
        Info storage self,
        int256 fixedTokenGrowthInsideX128,
        int256 variableTokenGrowthInsideX128
    )
        internal
        pure
        returns (int256 _fixedTokenDelta, int256 _variableTokenDelta)
    {
        Info memory _self = self;

        int256 fixedTokenGrowthInsideDeltaX128 = fixedTokenGrowthInsideX128 -
            _self.fixedTokenGrowthInsideLastX128;

        _fixedTokenDelta = FullMath.mulDivSigned(
            fixedTokenGrowthInsideDeltaX128,
            _self._liquidity,
            FixedPoint128.Q128
        );

        int256 variableTokenGrowthInsideDeltaX128 = variableTokenGrowthInsideX128 -
                _self.variableTokenGrowthInsideLastX128;

        _variableTokenDelta = FullMath.mulDivSigned(
            variableTokenGrowthInsideDeltaX128,
            _self._liquidity,
            FixedPoint128.Q128
        );
    }

    /// @notice Updates fixedTokenGrowthInsideLast and variableTokenGrowthInsideLast to the current values
    /// @param self position info struct represeting a liquidity provider
    /// @param fixedTokenGrowthInsideX128 fixed token growth per unit of liquidity as of now
    /// @param variableTokenGrowthInsideX128 variable token growth per unit of liquidity as of now
    function updateFixedAndVariableTokenGrowthInside(
        Info storage self,
        int256 fixedTokenGrowthInsideX128,
        int256 variableTokenGrowthInsideX128
    ) internal {
        self.fixedTokenGrowthInsideLastX128 = fixedTokenGrowthInsideX128;
        self.variableTokenGrowthInsideLastX128 = variableTokenGrowthInsideX128;
    }

    /// @notice Updates feeGrowthInsideLast to the current value
    /// @param self position info struct represeting a liquidity provider
    /// @param feeGrowthInsideX128 fee growth per unit of liquidity as of now
    function updateFeeGrowthInside(
        Info storage self,
        uint256 feeGrowthInsideX128
    ) internal {
        self.feeGrowthInsideLastX128 = feeGrowthInsideX128;
    }

    /// @notice Updates position's liqudity following either mint or a burn
    /// @param self The individual position to update
    /// @param liquidityDelta The change in pool liquidity as a result of the position update
    function updateLiquidity(Info storage self, int128 liquidityDelta)
        internal
    {
        Info memory _self = self;

        if (liquidityDelta == 0) {
            require(_self._liquidity > 0, "NP"); // disallow pokes for 0 liquidity positions
        } else {
            self._liquidity = LiquidityMath.addDelta(
                _self._liquidity,
                liquidityDelta
            );
        }
    }
}

File 14 of 41 : SwapMath.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity =0.8.9;

import "../utils/FullMath.sol";
import "../utils/SqrtPriceMath.sol";
import "prb-math/contracts/PRBMathUD60x18.sol";
import "prb-math/contracts/PRBMathSD59x18.sol";
import "../core_libraries/FixedAndVariableMath.sol";

/// @title Computes the result of a swap within ticks
/// @notice Contains methods for computing the result of a swap within a single tick price range, i.e., a single tick.
library SwapMath {
    struct SwapStepParams {
        uint160 sqrtRatioCurrentX96;
        uint160 sqrtRatioTargetX96;
        uint128 liquidity;
        int256 amountRemaining;
        uint256 feePercentageWad;
        uint256 timeToMaturityInSecondsWad;
    }

    function computeFeeAmount(
        uint256 notionalWad,
        uint256 timeToMaturityInSecondsWad,
        uint256 feePercentageWad
    ) internal pure returns (uint256 feeAmount) {
        uint256 timeInYearsWad = FixedAndVariableMath.accrualFact(
            timeToMaturityInSecondsWad
        );

        uint256 feeAmountWad = PRBMathUD60x18.mul(
            notionalWad,
            PRBMathUD60x18.mul(feePercentageWad, timeInYearsWad)
        );

        feeAmount = PRBMathUD60x18.toUint(feeAmountWad);
    }

    /// @notice Computes the result of swapping some amount in, or amount out, given the parameters of the swap
    /// @dev The fee, plus the amount in, will never exceed the amount remaining if the swap's `amountSpecified` is positive
    /// @param params.sqrtRatioCurrentX96 The current sqrt price of the pool
    /// @param params.sqrtRatioTargetX96 The price that cannot be exceeded, from which the direction of the swap is inferred
    /// @param params.liquidity The usable params.liquidity
    /// @param params.amountRemaining How much input or output amount is remaining to be swapped in/out
    /// @return sqrtRatioNextX96 The price after swapping the amount in/out, not to exceed the price target
    /// @return amountIn The amount to be swapped in, of either token0 or token1, based on the direction of the swap
    /// @return amountOut The amount to be received, of either token0 or token1, based on the direction of the swa
    /// @return feeAmount Amount of fees in underlying tokens incurred by the position during the swap step, i.e. single iteration of the while loop in the VAMM
    function computeSwapStep(SwapStepParams memory params)
        internal
        pure
        returns (
            uint160 sqrtRatioNextX96,
            uint256 amountIn,
            uint256 amountOut,
            uint256 feeAmount
        )
    {
        bool zeroForOne = params.sqrtRatioCurrentX96 >=
            params.sqrtRatioTargetX96;
        bool exactIn = params.amountRemaining >= 0;

        uint256 amountRemainingAbsolute;

        /// @dev using unchecked block below since overflow is possible when calculating "-amountRemaining" and such overflow would cause a revert
        unchecked {
            amountRemainingAbsolute = uint256(-params.amountRemaining);
        }

        if (exactIn) {
            amountIn = zeroForOne
                ? SqrtPriceMath.getAmount0Delta(
                    params.sqrtRatioTargetX96,
                    params.sqrtRatioCurrentX96,
                    params.liquidity,
                    true
                )
                : SqrtPriceMath.getAmount1Delta(
                    params.sqrtRatioCurrentX96,
                    params.sqrtRatioTargetX96,
                    params.liquidity,
                    true
                );
            if (uint256(params.amountRemaining) >= amountIn)
                sqrtRatioNextX96 = params.sqrtRatioTargetX96;
            else
                sqrtRatioNextX96 = SqrtPriceMath.getNextSqrtPriceFromInput(
                    params.sqrtRatioCurrentX96,
                    params.liquidity,
                    uint256(params.amountRemaining),
                    zeroForOne
                );
        } else {
            amountOut = zeroForOne
                ? SqrtPriceMath.getAmount1Delta(
                    params.sqrtRatioTargetX96,
                    params.sqrtRatioCurrentX96,
                    params.liquidity,
                    false
                )
                : SqrtPriceMath.getAmount0Delta(
                    params.sqrtRatioCurrentX96,
                    params.sqrtRatioTargetX96,
                    params.liquidity,
                    false
                );
            if (amountRemainingAbsolute >= amountOut)
                sqrtRatioNextX96 = params.sqrtRatioTargetX96;
            else
                sqrtRatioNextX96 = SqrtPriceMath.getNextSqrtPriceFromOutput(
                    params.sqrtRatioCurrentX96,
                    params.liquidity,
                    amountRemainingAbsolute,
                    zeroForOne
                );
        }

        bool max = params.sqrtRatioTargetX96 == sqrtRatioNextX96;
        uint256 notional;

        // get the input/output amounts
        if (zeroForOne) {
            amountIn = max && exactIn
                ? amountIn
                : SqrtPriceMath.getAmount0Delta(
                    sqrtRatioNextX96,
                    params.sqrtRatioCurrentX96,
                    params.liquidity,
                    true
                );
            amountOut = max && !exactIn
                ? amountOut
                : SqrtPriceMath.getAmount1Delta(
                    sqrtRatioNextX96,
                    params.sqrtRatioCurrentX96,
                    params.liquidity,
                    false
                );
            // variable taker
            notional = amountOut;
        } else {
            amountIn = max && exactIn
                ? amountIn
                : SqrtPriceMath.getAmount1Delta(
                    params.sqrtRatioCurrentX96,
                    sqrtRatioNextX96,
                    params.liquidity,
                    true
                );
            amountOut = max && !exactIn
                ? amountOut
                : SqrtPriceMath.getAmount0Delta(
                    params.sqrtRatioCurrentX96,
                    sqrtRatioNextX96,
                    params.liquidity,
                    false
                );

            // fixed taker
            notional = amountIn;
        }

        // cap the output amount to not exceed the remaining output amount
        if (!exactIn && amountOut > amountRemainingAbsolute) {
            /// @dev if !exact in => fixedTaker => has no effect on notional since notional = amountIn
            amountOut = amountRemainingAbsolute;
        }

        // uint256 notionalWad = PRBMathUD60x18.fromUint(notional);

        feeAmount = computeFeeAmount(
            PRBMathUD60x18.fromUint(notional),
            params.timeToMaturityInSecondsWad,
            params.feePercentageWad
        );
    }
}

File 15 of 41 : Tick.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity =0.8.9;
import "../utils/LiquidityMath.sol";
import "../utils/TickMath.sol";
import "../utils/SafeCastUni.sol";

/// @title Tick
/// @notice Contains functions for managing tick processes and relevant calculations
library Tick {
    using SafeCastUni for int256;
    using SafeCastUni for uint256;

    int24 public constant MAXIMUM_TICK_SPACING = 16384;

    // info stored for each initialized individual tick
    struct Info {
        /// @dev the total position liquidity that references this tick (either as tick lower or tick upper)
        uint128 liquidityGross;
        /// @dev amount of net liquidity added (subtracted) when tick is crossed from left to right (right to left),
        int128 liquidityNet;
        /// @dev fee growth per unit of liquidity on the _other_ side of this tick (relative to the current tick)
        /// @dev only has relative meaning, not absolute — the value depends on when the tick is initialized
        int256 fixedTokenGrowthOutsideX128;
        int256 variableTokenGrowthOutsideX128;
        uint256 feeGrowthOutsideX128;
        /// @dev true iff the tick is initialized, i.e. the value is exactly equivalent to the expression liquidityGross != 0
        /// @dev these 8 bits are set to prevent fresh sstores when crossing newly initialized ticks
        bool initialized;
    }

    /// @notice Derives max liquidity per tick from given tick spacing
    /// @dev Executed within the pool constructor
    /// @param tickSpacing The amount of required tick separation, realized in multiples of `tickSpacing`
    ///     e.g., a tickSpacing of 3 requires ticks to be initialized every 3rd tick i.e., ..., -6, -3, 0, 3, 6, ...
    /// @return The max liquidity per tick
    function tickSpacingToMaxLiquidityPerTick(int24 tickSpacing)
        internal
        pure
        returns (uint128)
    {
        int24 minTick = TickMath.MIN_TICK - (TickMath.MIN_TICK % tickSpacing);
        int24 maxTick = -minTick;
        uint24 numTicks = uint24((maxTick - minTick) / tickSpacing) + 1;
        return type(uint128).max / numTicks;
    }

    /// @dev Common checks for valid tick inputs.
    function checkTicks(int24 tickLower, int24 tickUpper) internal pure {
        require(tickLower < tickUpper, "TLU");
        require(tickLower >= TickMath.MIN_TICK, "TLM");
        require(tickUpper <= TickMath.MAX_TICK, "TUM");
    }

    struct FeeGrowthInsideParams {
        int24 tickLower;
        int24 tickUpper;
        int24 tickCurrent;
        uint256 feeGrowthGlobalX128;
    }

    function _getGrowthInside(
        int24 _tickLower,
        int24 _tickUpper,
        int24 _tickCurrent,
        int256 _growthGlobalX128,
        int256 _lowerGrowthOutsideX128,
        int256 _upperGrowthOutsideX128
    ) private pure returns (int256) {
        // calculate the growth below
        int256 _growthBelowX128;

        if (_tickCurrent >= _tickLower) {
            _growthBelowX128 = _lowerGrowthOutsideX128;
        } else {
            _growthBelowX128 = _growthGlobalX128 - _lowerGrowthOutsideX128;
        }

        // calculate the growth above
        int256 _growthAboveX128;

        if (_tickCurrent < _tickUpper) {
            _growthAboveX128 = _upperGrowthOutsideX128;
        } else {
            _growthAboveX128 = _growthGlobalX128 - _upperGrowthOutsideX128;
        }

        int256 _growthInsideX128;

        _growthInsideX128 =
            _growthGlobalX128 -
            (_growthBelowX128 + _growthAboveX128);

        return _growthInsideX128;
    }

    function getFeeGrowthInside(
        mapping(int24 => Tick.Info) storage self,
        FeeGrowthInsideParams memory params
    ) internal view returns (uint256 feeGrowthInsideX128) {
        unchecked {
            Info storage lower = self[params.tickLower];
            Info storage upper = self[params.tickUpper];

            feeGrowthInsideX128 = uint256(
                _getGrowthInside(
                    params.tickLower,
                    params.tickUpper,
                    params.tickCurrent,
                    params.feeGrowthGlobalX128.toInt256(),
                    lower.feeGrowthOutsideX128.toInt256(),
                    upper.feeGrowthOutsideX128.toInt256()
                )
            );
        }
    }

    struct VariableTokenGrowthInsideParams {
        int24 tickLower;
        int24 tickUpper;
        int24 tickCurrent;
        int256 variableTokenGrowthGlobalX128;
    }

    function getVariableTokenGrowthInside(
        mapping(int24 => Tick.Info) storage self,
        VariableTokenGrowthInsideParams memory params
    ) internal view returns (int256 variableTokenGrowthInsideX128) {
        Info storage lower = self[params.tickLower];
        Info storage upper = self[params.tickUpper];

        variableTokenGrowthInsideX128 = _getGrowthInside(
            params.tickLower,
            params.tickUpper,
            params.tickCurrent,
            params.variableTokenGrowthGlobalX128,
            lower.variableTokenGrowthOutsideX128,
            upper.variableTokenGrowthOutsideX128
        );
    }

    struct FixedTokenGrowthInsideParams {
        int24 tickLower;
        int24 tickUpper;
        int24 tickCurrent;
        int256 fixedTokenGrowthGlobalX128;
    }

    function getFixedTokenGrowthInside(
        mapping(int24 => Tick.Info) storage self,
        FixedTokenGrowthInsideParams memory params
    ) internal view returns (int256 fixedTokenGrowthInsideX128) {
        Info storage lower = self[params.tickLower];
        Info storage upper = self[params.tickUpper];

        // do we need an unchecked block in here (given we are dealing with an int256)?
        fixedTokenGrowthInsideX128 = _getGrowthInside(
            params.tickLower,
            params.tickUpper,
            params.tickCurrent,
            params.fixedTokenGrowthGlobalX128,
            lower.fixedTokenGrowthOutsideX128,
            upper.fixedTokenGrowthOutsideX128
        );
    }

    /// @notice Updates a tick and returns true if the tick was flipped from initialized to uninitialized, or vice versa
    /// @param self The mapping containing all tick information for initialized ticks
    /// @param tick The tick that will be updated
    /// @param tickCurrent The current tick
    /// @param liquidityDelta A new amount of liquidity to be added (subtracted) when tick is crossed from left to right (right to left)
    /// @param fixedTokenGrowthGlobalX128 The fixed token growth accumulated per unit of liquidity for the entire life of the vamm
    /// @param variableTokenGrowthGlobalX128 The variable token growth accumulated per unit of liquidity for the entire life of the vamm
    /// @param upper true for updating a position's upper tick, or false for updating a position's lower tick
    /// @param maxLiquidity The maximum liquidity allocation for a single tick
    /// @return flipped Whether the tick was flipped from initialized to uninitialized, or vice versa
    function update(
        mapping(int24 => Tick.Info) storage self,
        int24 tick,
        int24 tickCurrent,
        int128 liquidityDelta,
        int256 fixedTokenGrowthGlobalX128,
        int256 variableTokenGrowthGlobalX128,
        uint256 feeGrowthGlobalX128,
        bool upper,
        uint128 maxLiquidity
    ) internal returns (bool flipped) {
        Tick.Info storage info = self[tick];

        uint128 liquidityGrossBefore = info.liquidityGross;
        require(
            int128(info.liquidityGross) + liquidityDelta >= 0,
            "not enough liquidity to burn"
        );
        uint128 liquidityGrossAfter = LiquidityMath.addDelta(
            liquidityGrossBefore,
            liquidityDelta
        );

        require(liquidityGrossAfter <= maxLiquidity, "LO");

        flipped = (liquidityGrossAfter == 0) != (liquidityGrossBefore == 0);

        if (liquidityGrossBefore == 0) {
            // by convention, we assume that all growth before a tick was initialized happened _below_ the tick
            if (tick <= tickCurrent) {
                info.feeGrowthOutsideX128 = feeGrowthGlobalX128;

                info.fixedTokenGrowthOutsideX128 = fixedTokenGrowthGlobalX128;

                info
                    .variableTokenGrowthOutsideX128 = variableTokenGrowthGlobalX128;
            }

            info.initialized = true;
        }

        /// check shouldn't we unintialize the tick if liquidityGrossAfter = 0?

        info.liquidityGross = liquidityGrossAfter;

        /// add comments
        // when the lower (upper) tick is crossed left to right (right to left), liquidity must be added (removed)
        info.liquidityNet = upper
            ? info.liquidityNet - liquidityDelta
            : info.liquidityNet + liquidityDelta;
    }

    /// @notice Clears tick data
    /// @param self The mapping containing all initialized tick information for initialized ticks
    /// @param tick The tick that will be cleared
    function clear(mapping(int24 => Tick.Info) storage self, int24 tick)
        internal
    {
        delete self[tick];
    }

    /// @notice Transitions to next tick as needed by price movement
    /// @param self The mapping containing all tick information for initialized ticks
    /// @param tick The destination tick of the transition
    /// @param fixedTokenGrowthGlobalX128 The fixed token growth accumulated per unit of liquidity for the entire life of the vamm
    /// @param variableTokenGrowthGlobalX128 The variable token growth accumulated per unit of liquidity for the entire life of the vamm
    /// @param feeGrowthGlobalX128 The fee growth collected per unit of liquidity for the entire life of the vamm
    /// @return liquidityNet The amount of liquidity added (subtracted) when tick is crossed from left to right (right to left)
    function cross(
        mapping(int24 => Tick.Info) storage self,
        int24 tick,
        int256 fixedTokenGrowthGlobalX128,
        int256 variableTokenGrowthGlobalX128,
        uint256 feeGrowthGlobalX128
    ) internal returns (int128 liquidityNet) {
        Tick.Info storage info = self[tick];

        info.feeGrowthOutsideX128 =
            feeGrowthGlobalX128 -
            info.feeGrowthOutsideX128;

        info.fixedTokenGrowthOutsideX128 =
            fixedTokenGrowthGlobalX128 -
            info.fixedTokenGrowthOutsideX128;

        info.variableTokenGrowthOutsideX128 =
            variableTokenGrowthGlobalX128 -
            info.variableTokenGrowthOutsideX128;

        liquidityNet = info.liquidityNet;
    }
}

File 16 of 41 : TickBitmap.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity =0.8.9;

import "../utils/BitMath.sol";

/// @title Packed tick initialized state library
/// @notice Stores a packed mapping of tick index to its initialized state
/// @dev The mapping uses int16 for keys since ticks are represented as int24 and there are 256 (2^8) values per word.
library TickBitmap {
    /// @notice Computes the position in the mapping where the initialized bit for a tick lives
    /// @param tick The tick for which to compute the position
    /// @return wordPos The key in the mapping containing the word in which the bit is stored
    /// @return bitPos The bit position in the word where the flag is stored
    function position(int24 tick)
        private
        pure
        returns (int16 wordPos, uint8 bitPos)
    {
        wordPos = int16(tick >> 8);
        bitPos = uint8(int8(tick % 256));
    }

    /// @notice Flips the initialized state for a given tick from false to true, or vice versa
    /// @param self The mapping in which to flip the tick
    /// @param tick The tick to flip
    /// @param tickSpacing The spacing between usable ticks
    function flipTick(
        mapping(int16 => uint256) storage self,
        int24 tick,
        int24 tickSpacing
    ) internal {
        require(tick % tickSpacing == 0, "tick must be properly spaced"); // ensure that the tick is spaced
        (int16 wordPos, uint8 bitPos) = position(tick / tickSpacing);
        uint256 mask = 1 << bitPos;
        self[wordPos] ^= mask;
    }

    /// @notice Returns the next initialized tick contained in the same word (or adjacent word) as the tick that is either
    /// to the left (less than or equal to) or right (greater than) of the given tick
    /// @param self The mapping in which to compute the next initialized tick
    /// @param tick The starting tick
    /// @param tickSpacing The spacing between usable ticks
    /// @param lte Whether to search for the next initialized tick to the left (less than or equal to the starting tick)
    /// @return next The next initialized or uninitialized tick up to 256 ticks away from the current tick
    /// @return initialized Whether the next tick is initialized, as the function only searches within up to 256 ticks
    function nextInitializedTickWithinOneWord(
        mapping(int16 => uint256) storage self,
        int24 tick,
        int24 tickSpacing,
        bool lte
    ) internal view returns (int24 next, bool initialized) {
        int24 compressed = tick / tickSpacing;
        if (tick < 0 && tick % tickSpacing != 0) compressed--; // round towards negative infinity

        if (lte) {
            (int16 wordPos, uint8 bitPos) = position(compressed);
            // all the 1s at or to the right of the current bitPos
            uint256 mask = (1 << bitPos) - 1 + (1 << bitPos);
            uint256 masked = self[wordPos] & mask;

            // if there are no initialized ticks to the right of or at the current tick, return rightmost in the word
            initialized = masked != 0;
            // overflow/underflow is possible, but prevented externally by limiting both tickSpacing and tick
            next = initialized
                ? (compressed -
                    int24(
                        uint24(bitPos - BitMath.mostSignificantBit(masked))
                    )) * tickSpacing
                : (compressed - int24(uint24(bitPos))) * tickSpacing;
        } else {
            // start from the word of the next tick, since the current tick state doesn't matter
            (int16 wordPos, uint8 bitPos) = position(compressed + 1);
            // all the 1s at or to the left of the bitPos
            uint256 mask = ~((1 << bitPos) - 1);
            uint256 masked = self[wordPos] & mask;

            // if there are no initialized ticks to the left of the current tick, return leftmost in the word
            initialized = masked != 0;
            // overflow/underflow is possible, but prevented externally by limiting both tickSpacing and tick
            next = initialized
                ? (compressed +
                    1 +
                    int24(
                        uint24(BitMath.leastSignificantBit(masked) - bitPos)
                    )) * tickSpacing
                : (compressed + 1 + int24(uint24(type(uint8).max - bitPos))) *
                    tickSpacing;
        }
    }
}

File 17 of 41 : Time.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity =0.8.9;
import "prb-math/contracts/PRBMathUD60x18.sol";

library Time {
    uint256 public constant SECONDS_IN_DAY_WAD = 86400e18;

    /// @notice Calculate block.timestamp to wei precision
    /// @return Current timestamp in wei-seconds (1/1e18)
    function blockTimestampScaled() internal view returns (uint256) {
        // solhint-disable-next-line not-rely-on-time
        return PRBMathUD60x18.fromUint(block.timestamp);
    }

    /// @dev Returns the block timestamp truncated to 32 bits, checking for overflow.
    function blockTimestampTruncated() internal view returns (uint32) {
        return timestampAsUint32(block.timestamp);
    }

    function timestampAsUint32(uint256 _timestamp)
        internal
        pure
        returns (uint32 timestamp)
    {
        require((timestamp = uint32(_timestamp)) == _timestamp, "TSOFLOW");
    }

    function isCloseToMaturityOrBeyondMaturity(uint256 termEndTimestampWad)
        internal
        view
        returns (bool vammInactive)
    {
        return
            Time.blockTimestampScaled() + SECONDS_IN_DAY_WAD >=
            termEndTimestampWad;
    }
}

File 18 of 41 : TraderWithYieldBearingAssets.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity =0.8.9;
import "./FixedAndVariableMath.sol";

/// @title Trader
library TraderWithYieldBearingAssets {
    // info stored for each user's position
    struct Info {
        // For Aave v2 The scaled balance is the sum of all the updated stored balances in the
        // underlying token, divided by the reserve's liquidity index at the moment of the update
        //
        // For componund, the scaled balance is the sum of all the updated stored balances in the
        // underlying token, divided by the cToken exchange rate at the moment of the update.
        // This is simply the number of cTokens!
        uint256 marginInScaledYieldBearingTokens;
        int256 fixedTokenBalance;
        int256 variableTokenBalance;
        bool isSettled;
    }

    function updateMarginInScaledYieldBearingTokens(
        Info storage self,
        uint256 _marginInScaledYieldBearingTokens
    ) internal {
        self
            .marginInScaledYieldBearingTokens = _marginInScaledYieldBearingTokens;
    }

    function settleTrader(Info storage self) internal {
        require(!self.isSettled, "already settled");
        self.isSettled = true;
    }

    function updateBalancesViaDeltas(
        Info storage self,
        int256 fixedTokenBalanceDelta,
        int256 variableTokenBalanceDelta
    )
        internal
        returns (int256 _fixedTokenBalance, int256 _variableTokenBalance)
    {
        _fixedTokenBalance = self.fixedTokenBalance + fixedTokenBalanceDelta;
        _variableTokenBalance =
            self.variableTokenBalance +
            variableTokenBalanceDelta;

        self.fixedTokenBalance = _fixedTokenBalance;
        self.variableTokenBalance = _variableTokenBalance;
    }
}

File 19 of 41 : IERC20Minimal.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity =0.8.9;

/// @title Minimal ERC20 interface for Voltz
/// @notice Contains a subset of the full ERC20 interface that is used in Voltz
interface IERC20Minimal {
    /// @notice Returns the balance of a token
    /// @param account The account for which to look up the number of tokens it has, i.e. its balance
    /// @return The number of tokens held by the account
    function balanceOf(address account) external view returns (uint256);

    /// @notice Transfers the amount of token from the `msg.sender` to the recipient
    /// @param recipient The account that will receive the amount transferred
    /// @param amount The number of tokens to send from the sender to the recipient
    /// @return Returns true for a successful transfer, false for an unsuccessful transfer
    function transfer(address recipient, uint256 amount)
        external
        returns (bool);

    /// @notice Returns the current allowance given to a spender by an owner
    /// @param owner The account of the token owner
    /// @param spender The account of the token spender
    /// @return The current allowance granted by `owner` to `spender`
    function allowance(address owner, address spender)
        external
        view
        returns (uint256);

    /// @notice Sets the allowance of a spender from the `msg.sender` to the value `amount`
    /// @param spender The account which will be allowed to spend a given amount of the owners tokens
    /// @param amount The amount of tokens allowed to be used by `spender`
    /// @return Returns true for a successful approval, false for unsuccessful
    function approve(address spender, uint256 amount) external returns (bool);

    /// @notice Transfers `amount` tokens from `sender` to `recipient` up to the allowance given to the `msg.sender`
    /// @param sender The account from which the transfer will be initiated
    /// @param recipient The recipient of the transfer
    /// @param amount The amount of the transfer
    /// @return Returns true for a successful transfer, false for unsuccessful
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    /// @dev Returns the number of decimals used to get its user representation.
    // For example, if decimals equals 2, a balance of 505 tokens should be displayed to a user as 5,05 (505 / 10 ** 2).
    // Tokens usually opt for a value of 18, imitating the relationship between Ether and Wei.
    function decimals() external view returns (uint8);

    /// @notice Event emitted when tokens are transferred from one address to another, either via `#transfer` or `#transferFrom`.
    /// @param from The account from which the tokens were sent, i.e. the balance decreased
    /// @param to The account to which the tokens were sent, i.e. the balance increased
    /// @param value The amount of tokens that were transferred
    event Transfer(address indexed from, address indexed to, uint256 value);

    /// @notice Event emitted when the approval amount for the spender of a given owner's tokens changes.
    /// @param owner The account that approved spending of its tokens
    /// @param spender The account for which the spending allowance was modified
    /// @param value The new allowance from the owner to the spender
    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );
}

File 20 of 41 : IFactory.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity =0.8.9;

import "../utils/CustomErrors.sol";
import "./rate_oracles/IRateOracle.sol";
import "./IMarginEngine.sol";
import "./IVAMM.sol";
import "./fcms/IFCM.sol";
import "./IERC20Minimal.sol";
import "./IPeriphery.sol";

/// @title The interface for the Voltz AMM Factory
/// @notice The AMM Factory facilitates creation of Voltz AMMs
interface IFactory is CustomErrors {
    event IrsInstance(
        IERC20Minimal indexed underlyingToken,
        IRateOracle indexed rateOracle,
        uint256 termStartTimestampWad,
        uint256 termEndTimestampWad,
        int24 tickSpacing,
        IMarginEngine marginEngine,
        IVAMM vamm,
        IFCM fcm,
        uint8 yieldBearingProtocolID,
        uint8 underlyingTokenDecimals
    );

    event MasterFCM(IFCM masterFCMAddress, uint8 yieldBearingProtocolID);

    event Approval(
        address indexed owner,
        address indexed intAddress,
        bool indexed isApproved
    );

    event PeripheryUpdate(IPeriphery periphery);

    // view functions

    function isApproved(address _owner, address intAddress)
        external
        view
        returns (bool);

    function masterVAMM() external view returns (IVAMM);

    function masterMarginEngine() external view returns (IMarginEngine);

    function periphery() external view returns (IPeriphery);

    // settters

    function setApproval(address intAddress, bool allowIntegration) external;

    function setMasterFCM(IFCM masterFCM, uint8 yieldBearingProtocolID)
        external;

    function setMasterVAMM(IVAMM _masterVAMM) external;

    function setMasterMarginEngine(IMarginEngine _masterMarginEngine) external;

    function setPeriphery(IPeriphery _periphery) external;

    /// @notice Deploys the contracts required for a new Interest Rate Swap instance
    function deployIrsInstance(
        IERC20Minimal _underlyingToken,
        IRateOracle _rateOracle,
        uint256 _termStartTimestampWad,
        uint256 _termEndTimestampWad,
        int24 _tickSpacing
    )
        external
        returns (
            IMarginEngine marginEngineProxy,
            IVAMM vammProxy,
            IFCM fcmProxy
        );

    function masterFCMs(uint8 yieldBearingProtocolID)
        external
        view
        returns (IFCM masterFCM);
}

File 21 of 41 : IMarginEngine.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity =0.8.9;
import "./IVAMM.sol";
import "./IPositionStructs.sol";
import "../core_libraries/Position.sol";
import "./rate_oracles/IRateOracle.sol";
import "./fcms/IFCM.sol";
import "./IFactory.sol";
import "./IERC20Minimal.sol";
import "../utils/CustomErrors.sol";

interface IMarginEngine is IPositionStructs, CustomErrors {
    // structs

    function setPausability(bool state) external;

    struct MarginCalculatorParameters {
        /// @dev Upper bound of the underlying pool (e.g. Aave v2 USDC lending pool) APY from the initiation of the IRS AMM and until its maturity (18 decimals fixed point number)
        uint256 apyUpperMultiplierWad;
        /// @dev Lower bound of the underlying pool (e.g. Aave v2 USDC lending pool) APY from the initiation of the IRS AMM and until its maturity (18 decimals)
        uint256 apyLowerMultiplierWad;
        /// @dev The volatility of the underlying pool APY (settable by the owner of the Margin Engine) (18 decimals)
        int256 sigmaSquaredWad;
        /// @dev Margin Engine Parameter estimated via CIR model calibration (for details refer to litepaper) (18 decimals)
        int256 alphaWad;
        /// @dev Margin Engine Parameter estimated via CIR model calibration (for details refer to litepaper) (18 decimals)
        int256 betaWad;
        /// @dev Standard normal critical value used in the computation of the Upper APY Bound of the underlying pool
        int256 xiUpperWad;
        /// @dev Standard normal critical value used in the computation of the Lower APY Bound of the underlying pool
        int256 xiLowerWad;
        /// @dev Max term possible for a Voltz IRS AMM in seconds (18 decimals)
        int256 tMaxWad;
        /// @dev Margin Engine Parameter used for initial minimum margin requirement
        uint256 etaIMWad;
        /// @dev Margin Engine Parameter used for initial minimum margin requirement
        uint256 etaLMWad;
        /// @dev Gap
        uint256 gap1;
        /// @dev Gap
        uint256 gap2;
        /// @dev Gap
        uint256 gap3;
        /// @dev Gap
        uint256 gap4;
        /// @dev Gap
        uint256 gap5;
        /// @dev Gap
        uint256 gap6;
        /// @dev Gap
        uint256 gap7;
        /// @dev settable parameter that ensures that minimumMarginRequirement is always above or equal to the minMarginToIncentiviseLiquidators which ensures there is always sufficient incentive for liquidators to liquidate positions given the fact their income is a proportion of position margin
        uint256 minMarginToIncentiviseLiquidators;
    }

    // Events
    event HistoricalApyWindowSetting(uint256 secondsAgo);
    event CacheMaxAgeSetting(uint256 cacheMaxAgeInSeconds);
    event RateOracle(uint256 cacheMaxAgeInSeconds);

    event ProtocolCollection(
        address sender,
        address indexed recipient,
        uint256 amount
    );
    event LiquidatorRewardSetting(uint256 liquidatorRewardWad);

    event VAMMSetting(IVAMM indexed vamm);

    event RateOracleSetting(IRateOracle indexed rateOracle);

    event FCMSetting(IFCM indexed fcm);

    event MarginCalculatorParametersSetting(
        MarginCalculatorParameters marginCalculatorParameters
    );

    event PositionMarginUpdate(
        address sender,
        address indexed owner,
        int24 indexed tickLower,
        int24 indexed tickUpper,
        int256 marginDelta
    );

    event HistoricalApy(uint256 value);

    event PositionSettlement(
        address indexed owner,
        int24 indexed tickLower,
        int24 indexed tickUpper,
        int256 settlementCashflow
    );

    event PositionLiquidation(
        address indexed owner,
        int24 indexed tickLower,
        int24 indexed tickUpper,
        address liquidator,
        int256 notionalUnwound,
        uint256 liquidatorReward
    );

    event PositionUpdate(
        address indexed owner,
        int24 indexed tickLower,
        int24 indexed tickUpper,
        uint128 _liquidity,
        int256 margin,
        int256 fixedTokenBalance,
        int256 variableTokenBalance,
        uint256 accumulatedFees
    );

    /// @dev emitted after the _isAlpha boolean is updated by the owner of the Margin Engine
    /// @dev _isAlpha boolean dictates whether the Margin Engine is in the Alpha State, i.e. margin updates can only be done via the periphery
    /// @dev additionally, the periphery has the logic to take care of lp margin caps in the Alpha State phase of the Margin Engine
    /// @dev __isAlpha is the newly set value for the _isAlpha boolean
    event IsAlpha(bool __isAlpha);

    // immutables

    /// @notice The Full Collateralisation Module (FCM)
    /// @dev The FCM is a smart contract that acts as an intermediary Position between the Voltz Core and traders who wish to take fully collateralised fixed taker positions
    /// @dev An example FCM is the AaveFCM.sol module which inherits from the IFCM interface, it lets fixed takers deposit underlying yield bearing tokens (e.g.) aUSDC as margin to enter into a fixed taker swap without the need to worry about liquidations
    /// @dev since the MarginEngine is confident the FCM is always fully collateralised, it does not let liquidators liquidate the FCM Position
    /// @return The Full Collateralisation Module linked to the MarginEngine
    function fcm() external view returns (IFCM);

    /// @notice The Factory
    /// @dev the factory that deployed the master Margin Engine
    function factory() external view returns (IFactory);

    /// @notice The address of the underlying (non-yield bearing) token - e.g. USDC
    /// @return The underlying ERC20 token (e.g. USDC)
    function underlyingToken() external view returns (IERC20Minimal);

    /// @notice The rateOracle contract which lets the protocol access historical apys in the yield bearing pools it is built on top of
    /// @return The underlying ERC20 token (e.g. USDC)
    function rateOracle() external view returns (IRateOracle);

    /// @notice The unix termStartTimestamp of the MarginEngine in Wad
    /// @return Term Start Timestamp in Wad
    function termStartTimestampWad() external view returns (uint256);

    /// @notice The unix termEndTimestamp of the MarginEngine in Wad
    /// @return Term End Timestamp in Wad
    function termEndTimestampWad() external view returns (uint256);

    function marginEngineParameters()
        external
        view
        returns (MarginCalculatorParameters memory);

    /// @dev "constructor" for proxy instances
    function initialize(
        IERC20Minimal __underlyingToken,
        IRateOracle __rateOracle,
        uint256 __termStartTimestampWad,
        uint256 __termEndTimestampWad
    ) external;

    // view functions

    /// @notice The liquidator Reward Percentage (in Wad)
    /// @dev liquidatorReward (in wad) is the percentage of the margin (of a liquidated position) that is sent to the liquidator
    /// @dev following a successful liquidation that results in a trader/position unwind; example value:  2 * 10**16 => 2% of position margin is used to cover liquidator reward
    /// @return Liquidator Reward in Wad
    function liquidatorRewardWad() external view returns (uint256);

    /// @notice VAMM (Virtual Automated Market Maker) linked to the MarginEngine
    /// @dev The VAMM is responsible for pricing only (determining the effective fixed rate at which a given Interest Rate Swap notional will be executed)
    /// @return The VAMM
    function vamm() external view returns (IVAMM);

    /// @return If true, the Margin Engine Proxy is currently in alpha state, hence margin updates of LPs can only be done via the periphery. If false, lps can directly update their margin via Margin Engine.
    function isAlpha() external view returns (bool);

    /// @notice Returns the information about a position by the position's key
    /// @param _owner The address of the position owner
    /// @param _tickLower The lower tick boundary of the position
    /// @param _tickUpper The upper tick boundary of the position
    /// Returns position The Position.Info corresponding to the requested position
    function getPosition(
        address _owner,
        int24 _tickLower,
        int24 _tickUpper
    ) external returns (Position.Info memory position);

    /// @notice Gets the look-back window size that's used to request the historical APY from the rate Oracle
    /// @dev The historical APY of the Rate Oracle is necessary for MarginEngine computations
    /// @dev The look-back window is seconds from the current timestamp
    /// @dev This value is only settable by the the Factory owner and may be unique for each MarginEngine
    /// @dev When setting secondAgo, the setter needs to take into consideration the underlying volatility of the APYs in the reference yield-bearing pool (e.g. Aave v2 USDC)
    function lookbackWindowInSeconds() external view returns (uint256);

    // non-view functions

    /// @notice Sets secondsAgo: The look-back window size used to calculate the historical APY for margin purposes
    /// @param _secondsAgo the duration of the lookback window in seconds
    /// @dev Can only be set by the Factory Owner
    function setLookbackWindowInSeconds(uint256 _secondsAgo) external;

    /// @notice Set the MarginCalculatorParameters (each margin engine can have its own custom set of margin calculator parameters)
    /// @param _marginCalculatorParameters the MarginCalculatorParameters to set
    /// @dev marginCalculatorParameteres is of type MarginCalculatorParameters (refer to the definition of the struct for elaboration on what each parameter means)
    function setMarginCalculatorParameters(
        MarginCalculatorParameters memory _marginCalculatorParameters
    ) external;

    /// @notice Sets the liquidator reward: proportion of liquidated position's margin paid as a reward to the liquidator
    function setLiquidatorReward(uint256 _liquidatorRewardWad) external;

    /// @notice Function that sets the _isAlpha state variable, if it is set to true the protocol is in the Alpha State
    /// @dev if the Margin Engine is at the alpha state, lp margin updates can only be done via the periphery which in turn takes care of margin caps for the LPs
    /// @dev this function can only be called by the owner of the VAMM
    function setIsAlpha(bool __isAlpha) external;

    /// @notice updates the margin account of a position which can be uniquily identified with its _owner, tickLower, tickUpper
    /// @dev if the position has positive liquidity then before the margin update, we call the updatePositionTokenBalancesAndAccountForFees functon that calculates up to date
    /// @dev margin, fixed and variable token balances by taking into account the fee income from their tick range and fixed and variable deltas settled along their tick range
    /// @dev marginDelta is the delta applied to the current margin of a position, if the marginDelta is negative, the position is withdrawing margin, if the marginDelta is positive, the position is depositing funds in terms of the underlying tokens
    /// @dev if marginDelta is negative, we need to check if the msg.sender is either the _owner of the position or the msg.sender is apporved by the _owner to act on their behalf in Voltz Protocol
    /// @dev the approval logic is implemented in the Factory.sol
    /// @dev if marginDelta is negative, we additionally need to check if post the initial margin requirement is still satisfied post withdrawal
    /// @dev if marginDelta is positive, the depositor of the margin is either the msg.sender or the owner who interacted through an approved peripheral contract
    function updatePositionMargin(
        address _owner,
        int24 _tickLower,
        int24 _tickUpper,
        int256 marginDelta
    ) external;

    /// @notice Settles a Position
    /// @dev Can be called by anyone
    /// @dev A position cannot be settled before maturity
    /// @dev Steps to settle a position:
    /// @dev 1. Retrieve the current fixed and variable token growth inside the tick range of a position
    /// @dev 2. Calculate accumulated fixed and variable balances of the position since the last mint/poke/burn
    /// @dev 3. Update the postion's fixed and variable token balances
    /// @dev 4. Update the postion's fixed and varaible token growth inside last to enable future updates
    /// @dev 5. Calculates the settlement cashflow from all of the IRS contracts the position has entered since entering the AMM
    /// @dev 6. Updates the fixed and variable token balances of the position to be zero, adds the settlement cashflow to the position's current margin
    function settlePosition(
        address _owner,
        int24 _tickLower,
        int24 _tickUpper
    ) external;

    /// @notice Liquidate a Position
    /// @dev Steps to liquidate: update position's fixed and variable token balances to account for balances accumulated throughout the trades made since the last mint/burn/poke,
    /// @dev Check if the position is liquidatable by calling the isLiquidatablePosition function of the calculator, revert if that is not the case,
    /// @dev Calculate the liquidation reward = current margin of the position * liquidatorReward, subtract the liquidator reward from the position margin,
    /// @dev Burn the position's liquidity, unwind unnetted fixed and variable balances of a position, transfer the reward to the liquidator
    function liquidatePosition(
        address _owner,
        int24 _tickLower,
        int24 _tickUpper
    ) external returns (uint256);

    /// @notice Update a Position post VAMM induced mint or burn
    /// @dev Steps taken:
    /// @dev 1. Update position liquidity based on params.liquidityDelta
    /// @dev 2. Update fixed and variable token balances of the position based on how much has been accumulated since the last mint/burn/poke
    /// @dev 3. Update position's margin by taking into account the position accumulated fees since the last mint/burn/poke
    /// @dev 4. Update fixed and variable token growth + fee growth in the position info struct for future interactions with the position
    /// @param _params necessary for the purposes of referencing the position being updated (owner, tickLower, tickUpper, _) and the liquidity delta that needs to be applied to position._liquidity
    function updatePositionPostVAMMInducedMintBurn(
        IPositionStructs.ModifyPositionParams memory _params
    ) external returns (int256 _positionMarginRequirement);

    // @notive Update a position post VAMM induced swap
    /// @dev Since every position can also engage in swaps with the VAMM, this function needs to be invoked after non-external calls are made to the VAMM's swap function
    /// @dev This purpose of this function is to:
    /// @dev 1. updatePositionTokenBalancesAndAccountForFees
    /// @dev 2. update position margin to account for fees paid to execute the swap
    /// @dev 3. calculate the position margin requrement given the swap, check if the position marigin satisfies the most up to date requirement
    /// @dev 4. if all the requirements are satisfied then position gets updated to take into account the swap that it just entered, if the minimum margin requirement is not satisfied then the transaction will revert
    function updatePositionPostVAMMInducedSwap(
        address _owner,
        int24 _tickLower,
        int24 _tickUpper,
        int256 _fixedTokenDelta,
        int256 _variableTokenDelta,
        uint256 _cumulativeFeeIncurred,
        int256 _fixedTokenDeltaUnbalanced
    ) external returns (int256 _positionMarginRequirement);

    /// @notice function that can only be called by the owner enables collection of protocol generated fees from any give margin engine
    /// @param _recipient the address which collects the protocol generated fees
    /// @param _amount the amount in terms of underlying tokens collected from the protocol's earnings
    function collectProtocol(address _recipient, uint256 _amount) external;

    /// @notice sets the Virtual Automated Market Maker (VAMM) attached to the MarginEngine
    /// @dev the VAMM is responsible for price discovery, whereas the management of the underlying collateral and liquidations are handled by the Margin Engine
    function setVAMM(IVAMM _vAMM) external;

    /// @notice sets the Virtual Automated Market Maker (VAMM) attached to the MarginEngine
    /// @dev the VAMM is responsible for price discovery, whereas the management of the underlying collateral and liquidations are handled by the Margin Engine
    function setRateOracle(IRateOracle __rateOracle) external;

    /// @notice sets the Full Collateralisation Module
    function setFCM(IFCM _newFCM) external;

    /// @notice transfers margin in terms of underlying tokens to a trader from the Full Collateralisation Module
    /// @dev post maturity date of the MarginEngine, the traders from the Full Collateralisation module will be able to settle with the MarginEngine
    /// @dev to ensure their fixed yield is guaranteed, in order to collect the funds from the MarginEngine, the FCM needs to invoke the transferMarginToFCMTrader function whcih is only callable by the FCM attached to a particular Margin Engine
    function transferMarginToFCMTrader(address _account, uint256 _marginDelta)
        external;

    /// @notice Gets the maximum age of the cached historical APY value can be without being refreshed
    function cacheMaxAgeInSeconds() external view returns (uint256);

    /// @notice Sets the maximum age that the cached historical APY value
    /// @param _cacheMaxAgeInSeconds The new maximum age that the historical APY cache can be before being considered stale
    function setCacheMaxAgeInSeconds(uint256 _cacheMaxAgeInSeconds) external;

    /// @notice Get Historical APY
    /// @dev The lookback window used by this function is determined by `lookbackWindowInSeconds`
    /// @dev refresh the historical apy cache if necessary
    /// @return historicalAPY (Wad)
    function getHistoricalApy() external returns (uint256);

    /// @notice Computes the historical APY value of the RateOracle, without updating the cached value
    /// @dev The lookback window used by this function is determined by `lookbackWindowInSeconds`
    function getHistoricalApyReadOnly() external view returns (uint256);

    function getPositionMarginRequirement(
        address _recipient,
        int24 _tickLower,
        int24 _tickUpper,
        bool _isLM
    ) external returns (uint256);
}

File 22 of 41 : IPeriphery.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity =0.8.9;

import "../interfaces/IMarginEngine.sol";
import "../interfaces/IVAMM.sol";
import "../utils/CustomErrors.sol";
import "../interfaces/IWETH.sol";

interface IPeriphery is CustomErrors {
    // events

    /// @dev emitted after new lp margin cap is set
    event MarginCap(IVAMM vamm, int256 lpMarginCapNew);

    // structs

    struct MintOrBurnParams {
        IMarginEngine marginEngine;
        int24 tickLower;
        int24 tickUpper;
        uint256 notional;
        bool isMint;
        int256 marginDelta;
    }

    struct SwapPeripheryParams {
        IMarginEngine marginEngine;
        bool isFT;
        uint256 notional;
        uint160 sqrtPriceLimitX96;
        int24 tickLower;
        int24 tickUpper;
        int256 marginDelta;
    }

    /// @dev "constructor" for proxy instances
    function initialize(IWETH weth_) external;

    // view functions

    function getCurrentTick(IMarginEngine marginEngine)
        external
        view
        returns (int24 currentTick);

    /// @param vamm VAMM for which to get the lp cap in underlying tokens
    /// @return Notional Cap for liquidity providers that mint or burn via periphery (enforced in the core if isAlpha is set to true)
    function lpMarginCaps(IVAMM vamm) external view returns (int256);

    /// @param vamm VAMM for which to get the lp notional cumulative in underlying tokens
    /// @return Total amount of notional supplied by the LPs to a given VAMM via the periphery
    function lpMarginCumulatives(IVAMM vamm) external view returns (int256);

    function weth() external view returns (IWETH);

    // non-view functions

    function mintOrBurn(MintOrBurnParams memory params)
        external
        payable
        returns (int256 positionMarginRequirement);

    function swap(SwapPeripheryParams memory params)
        external
        payable
        returns (
            int256 _fixedTokenDelta,
            int256 _variableTokenDelta,
            uint256 _cumulativeFeeIncurred,
            int256 _fixedTokenDeltaUnbalanced,
            int256 _marginRequirement,
            int24 _tickAfter,
            int256 marginDelta
        );

    /// @dev Ensures a fully collateralised VT swap given that a proper value of the variable factor is passed.
    /// @param params Parameters to be passed to the swap function in the periphery.
    /// @param variableFactorFromStartToNowWad The variable factor between pool's start date and present (in wad).
    function fullyCollateralisedVTSwap(
        SwapPeripheryParams memory params,
        uint256 variableFactorFromStartToNowWad
    )
        external
        payable
        returns (
            int256 _fixedTokenDelta,
            int256 _variableTokenDelta,
            uint256 _cumulativeFeeIncurred,
            int256 _fixedTokenDeltaUnbalanced,
            int256 _marginRequirement,
            int24 _tickAfter,
            int256 marginDelta
        );

    function updatePositionMargin(
        IMarginEngine marginEngine,
        int24 tickLower,
        int24 tickUpper,
        int256 marginDelta,
        bool fullyWithdraw
    ) external payable returns (int256);

    function setLPMarginCap(IVAMM vamm, int256 lpMarginCapNew) external;

    function setLPMarginCumulative(IVAMM vamm, int256 lpMarginCumulative)
        external;

    function settlePositionAndWithdrawMargin(
        IMarginEngine marginEngine,
        address owner,
        int24 tickLower,
        int24 tickUpper
    ) external;

    function rolloverWithMint(
        IMarginEngine marginEngine,
        address owner,
        int24 tickLower,
        int24 tickUpper,
        MintOrBurnParams memory paramsNewPosition
    ) external payable returns (int256 newPositionMarginRequirement);

    function rolloverWithSwap(
        IMarginEngine marginEngine,
        address owner,
        int24 tickLower,
        int24 tickUpper,
        SwapPeripheryParams memory paramsNewPosition
    )
        external
        payable
        returns (
            int256 _fixedTokenDelta,
            int256 _variableTokenDelta,
            uint256 _cumulativeFeeIncurred,
            int256 _fixedTokenDeltaUnbalanced,
            int256 _marginRequirement,
            int24 _tickAfter
        );
}

File 23 of 41 : IPositionStructs.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity =0.8.9;

interface IPositionStructs {
    struct ModifyPositionParams {
        // the address that owns the position
        address owner;
        // the lower and upper tick of the position
        int24 tickLower;
        int24 tickUpper;
        // any change in liquidity
        int128 liquidityDelta;
    }
}

File 24 of 41 : IVAMM.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity =0.8.9;
import "./IMarginEngine.sol";
import "./IFactory.sol";
import "./IPositionStructs.sol";
import "../core_libraries/Tick.sol";
import "../utils/CustomErrors.sol";
import "./rate_oracles/IRateOracle.sol";

interface IVAMM is IPositionStructs, CustomErrors {
    function setPausability(bool state) external;

    // events
    event Swap(
        address sender,
        address indexed recipient,
        int24 indexed tickLower,
        int24 indexed tickUpper,
        int256 desiredNotional,
        uint160 sqrtPriceLimitX96,
        uint256 cumulativeFeeIncurred,
        int256 fixedTokenDelta,
        int256 variableTokenDelta,
        int256 fixedTokenDeltaUnbalanced
    );

    /// @dev emitted after a given vamm is successfully initialized
    event VAMMInitialization(uint160 sqrtPriceX96, int24 tick);

    /// @dev emitted after a successful minting of a given LP position
    event Mint(
        address sender,
        address indexed owner,
        int24 indexed tickLower,
        int24 indexed tickUpper,
        uint128 amount
    );

    /// @dev emitted after a successful burning of a given LP position
    event Burn(
        address sender,
        address indexed owner,
        int24 indexed tickLower,
        int24 indexed tickUpper,
        uint128 amount
    );

    /// @dev emitted after setting feeProtocol
    event FeeProtocol(uint8 feeProtocol);

    /// @dev emitted after fee is set
    event Fee(uint256 feeWad);

    /// @dev emitted after the _isAlpha boolean is updated by the owner of the VAMM
    /// @dev _isAlpha boolean dictates whether the VAMM is in the Alpha State, i.e. mints can only be done via the periphery
    /// @dev additionally, the periphery has the logic to take care of lp notional caps in the Alpha State phase of VAMM
    /// @dev __isAlpha is the newly set value for the _isAlpha boolean
    event IsAlpha(bool __isAlpha);

    event VAMMPriceChange(int24 tick);

    // structs

    struct VAMMVars {
        /// @dev The current price of the pool as a sqrt(variableToken/fixedToken) Q64.96 value
        uint160 sqrtPriceX96;
        /// @dev The current tick of the vamm, i.e. according to the last tick transition that was run.
        int24 tick;
        // the current protocol fee as a percentage of the swap fee taken on withdrawal
        // represented as an integer denominator (1/x)
        uint8 feeProtocol;
    }

    struct SwapParams {
        /// @dev Address of the trader initiating the swap
        address recipient;
        /// @dev The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
        int256 amountSpecified;
        /// @dev The Q64.96 sqrt price limit. If !isFT, the price cannot be less than this
        uint160 sqrtPriceLimitX96;
        /// @dev lower tick of the position
        int24 tickLower;
        /// @dev upper tick of the position
        int24 tickUpper;
    }

    struct SwapCache {
        /// @dev liquidity at the beginning of the swap
        uint128 liquidityStart;
        // the current protocol fee as a percentage of the swap fee taken on withdrawal
        // represented as an integer denominator (1/x)%
        uint8 feeProtocol;
    }

    /// @dev the top level state of the swap, the results of which are recorded in storage at the end
    struct SwapState {
        /// @dev the amount remaining to be swapped in/out of the input/output asset
        int256 amountSpecifiedRemaining;
        /// @dev the amount already swapped out/in of the output/input asset
        int256 amountCalculated;
        /// @dev current sqrt(price)
        uint160 sqrtPriceX96;
        /// @dev the tick associated with the current price
        int24 tick;
        /// @dev the global fixed token growth
        int256 fixedTokenGrowthGlobalX128;
        /// @dev the global variable token growth
        int256 variableTokenGrowthGlobalX128;
        /// @dev the current liquidity in range
        uint128 liquidity;
        /// @dev the global fee growth of the underlying token
        uint256 feeGrowthGlobalX128;
        /// @dev amount of underlying token paid as protocol fee
        uint256 protocolFee;
        /// @dev cumulative fee incurred while initiating a swap
        uint256 cumulativeFeeIncurred;
        /// @dev fixedTokenDelta that will be applied to the fixed token balance of the position executing the swap (recipient)
        int256 fixedTokenDeltaCumulative;
        /// @dev variableTokenDelta that will be applied to the variable token balance of the position executing the swap (recipient)
        int256 variableTokenDeltaCumulative;
        /// @dev fixed token delta cumulative but without rebalancings applied
        int256 fixedTokenDeltaUnbalancedCumulative;
        uint256 variableFactorWad;
    }

    struct StepComputations {
        /// @dev the price at the beginning of the step
        uint160 sqrtPriceStartX96;
        /// @dev the next tick to swap to from the current tick in the swap direction
        int24 tickNext;
        /// @dev whether tickNext is initialized or not
        bool initialized;
        /// @dev sqrt(price) for the next tick (1/0)
        uint160 sqrtPriceNextX96;
        /// @dev how much is being swapped in in this step
        uint256 amountIn;
        /// @dev how much is being swapped out
        uint256 amountOut;
        /// @dev how much fee is being paid in (underlying token)
        uint256 feeAmount;
        /// @dev ...
        uint256 feeProtocolDelta;
        /// @dev ...
        int256 fixedTokenDeltaUnbalanced; // for LP
        /// @dev ...
        int256 fixedTokenDelta; // for LP
        /// @dev ...
        int256 variableTokenDelta; // for LP
    }

    /// @dev "constructor" for proxy instances
    function initialize(IMarginEngine __marginEngine, int24 __tickSpacing)
        external;

    // immutables

    /// @notice The vamm's fee (proportion) in wad
    /// @return The fee in wad
    function feeWad() external view returns (uint256);

    /// @notice The vamm tick spacing
    /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive
    /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ...
    /// This value is an int24 to avoid casting even though it is always positive.
    /// @return The tick spacing
    function tickSpacing() external view returns (int24);

    /// @notice The maximum amount of position liquidity that can use any tick in the range
    /// @dev This parameter should be enforced per tick (when setting) to prevent liquidity from overflowing a uint128 at any point, and
    /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to the vamm
    /// @return The max amount of liquidity per tick
    function maxLiquidityPerTick() external view returns (uint128);

    // state variables

    /// @return The current VAMM Vars (see struct definition for semantics)
    function vammVars() external view returns (VAMMVars memory);

    /// @return If true, the VAMM Proxy is currently in alpha state, hence minting can only be done via the periphery. If false, minting can be done directly via VAMM.
    function isAlpha() external view returns (bool);

    /// @notice The fixed token growth accumulated per unit of liquidity for the entire life of the vamm
    /// @dev This value can overflow the uint256
    function fixedTokenGrowthGlobalX128() external view returns (int256);

    /// @notice The variable token growth accumulated per unit of liquidity for the entire life of the vamm
    /// @dev This value can overflow the uint256
    function variableTokenGrowthGlobalX128() external view returns (int256);

    /// @notice The fee growth collected per unit of liquidity for the entire life of the vamm
    /// @dev This value can overflow the uint256
    function feeGrowthGlobalX128() external view returns (uint256);

    /// @notice The currently in range liquidity available to the vamm
    function liquidity() external view returns (uint128);

    /// @notice The amount underlying token that are owed to the protocol
    /// @dev Protocol fees will never exceed uint256
    function protocolFees() external view returns (uint256);

    function marginEngine() external view returns (IMarginEngine);

    function factory() external view returns (IFactory);

    /// @notice Function that sets the feeProtocol of the vamm
    /// @dev the current protocol fee as a percentage of the swap fee taken on withdrawal
    // represented as an integer denominator (1/x)
    function setFeeProtocol(uint8 feeProtocol) external;

    /// @notice Function that sets the _isAlpha state variable, if it is set to true the protocol is in the Alpha State
    /// @dev if the VAMM is at the alpha state, mints can only be done via the periphery which in turn takes care of notional caps for the LPs
    /// @dev this function can only be called by the owner of the VAMM
    function setIsAlpha(bool __isAlpha) external;

    /// @notice Function that sets fee of the vamm
    /// @dev The vamm's fee (proportion) in wad
    function setFee(uint256 _fee) external;

    /// @notice Updates internal accounting to reflect a collection of protocol fees. The actual transfer of fees must happen separately in the AMM
    /// @dev can only be done via the collectProtocol function of the parent AMM of the vamm
    function updateProtocolFees(uint256 protocolFeesCollected) external;

    /// @notice Sets the initial price for the vamm
    /// @dev Price is represented as a sqrt(amountVariableToken/amountFixedToken) Q64.96 value
    /// @param sqrtPriceX96 the initial sqrt price of the vamm as a Q64.96
    function initializeVAMM(uint160 sqrtPriceX96) external;

    /// @notice removes liquidity given recipient/tickLower/tickUpper of the position
    /// @param recipient The address for which the liquidity will be removed
    /// @param tickLower The lower tick of the position in which to remove liquidity
    /// @param tickUpper The upper tick of the position in which to remove liqudiity
    /// @param amount The amount of liquidity to burn
    function burn(
        address recipient,
        int24 tickLower,
        int24 tickUpper,
        uint128 amount
    ) external returns (int256 positionMarginRequirement);

    /// @notice Adds liquidity for the given recipient/tickLower/tickUpper position
    /// @param recipient The address for which the liquidity will be created
    /// @param tickLower The lower tick of the position in which to add liquidity
    /// @param tickUpper The upper tick of the position in which to add liquidity
    /// @param amount The amount of liquidity to mint
    function mint(
        address recipient,
        int24 tickLower,
        int24 tickUpper,
        uint128 amount
    ) external returns (int256 positionMarginRequirement);

    /// @notice Initiate an Interest Rate Swap
    /// @param params SwapParams necessary to initiate an Interest Rate Swap
    /// @return fixedTokenDelta Fixed Token Delta
    /// @return variableTokenDelta Variable Token Delta
    /// @return cumulativeFeeIncurred Cumulative Fee Incurred
    function swap(SwapParams memory params)
        external
        returns (
            int256 fixedTokenDelta,
            int256 variableTokenDelta,
            uint256 cumulativeFeeIncurred,
            int256 fixedTokenDeltaUnbalanced,
            int256 marginRequirement
        );

    /// @notice Look up information about a specific tick in the amm
    /// @param tick The tick to look up
    /// @return liquidityGross: the total amount of position liquidity that uses the vamm either as tick lower or tick upper,
    /// liquidityNet: how much liquidity changes when the vamm price crosses the tick,
    /// feeGrowthOutsideX128: the fee growth on the other side of the tick from the current tick in underlying token. i.e. if liquidityGross is greater than 0. In addition, these values are only relative.
    function ticks(int24 tick) external view returns (Tick.Info memory);

    /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information
    function tickBitmap(int16 wordPosition) external view returns (uint256);

    /// @notice Computes the current fixed and variable token growth inside a given tick range given the current tick in the vamm
    /// @param tickLower The lower tick of the position
    /// @param tickUpper The upper tick of the position
    /// @return fixedTokenGrowthInsideX128 Fixed Token Growth inside the given tick range
    /// @return variableTokenGrowthInsideX128 Variable Token Growth inside the given tick range
    /// @return feeGrowthInsideX128 Fee Growth Inside given tick range
    function computeGrowthInside(int24 tickLower, int24 tickUpper)
        external
        view
        returns (
            int256 fixedTokenGrowthInsideX128,
            int256 variableTokenGrowthInsideX128,
            uint256 feeGrowthInsideX128
        );

    /// @notice refreshes the Rate Oracle attached to the Margin Engine
    function refreshRateOracle() external;

    /// @notice The rateOracle contract which lets the protocol access historical apys in the yield bearing pools it is built on top of
    /// @return The underlying ERC20 token (e.g. USDC)
    function getRateOracle() external view returns (IRateOracle);
}

File 25 of 41 : IWETH.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity =0.8.9;

import "../interfaces/IERC20Minimal.sol";

interface IWETH {
    function deposit() external payable;

    function withdraw(uint256 amount) external;
}

File 26 of 41 : IFCM.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity =0.8.9;

import "../IMarginEngine.sol";
import "../../utils/CustomErrors.sol";
import "../IERC20Minimal.sol";
import "../../core_libraries/TraderWithYieldBearingAssets.sol";
import "../IVAMM.sol";
import "../rate_oracles/IRateOracle.sol";

interface IFCM is CustomErrors {
    function setPausability(bool state) external;

    function getTraderWithYieldBearingAssets(address trader)
        external
        view
        returns (TraderWithYieldBearingAssets.Info memory traderInfo);

    /// @notice Initiate a Fully Collateralised Fixed Taker Swap
    /// @param notional amount of notional (in terms of the underlying token) to trade
    /// @param sqrtPriceLimitX96 the sqrtPriceLimit (in binary fixed point math notation) beyond which swaps won't be executed
    /// @dev An example of an initiated fully collateralised fixed taker swap is a scenario where a trader with 100 aTokens wishes to get a fixed return on them
    /// @dev they can choose to deposit their 100aTokens into the FCM (enter into a fixed taker position with a notional of 100) to swap variable cashflows from the aTokens
    /// @dev with the fixed cashflows from the variable takers
    function initiateFullyCollateralisedFixedTakerSwap(
        uint256 notional,
        uint160 sqrtPriceLimitX96
    ) external returns (int256 fixedTokenDelta, int256 variableTokenDelta, uint256 cumulativeFeeIncurred, int256 fixedTokenDeltaUnbalanced);

    /// @notice Unwind a Fully Collateralised Fixed Taker Swap
    /// @param notionalToUnwind The amount of notional of the original Fully Collateralised Fixed Taker swap to be unwound at the current VAMM fixed rates
    /// @param sqrtPriceLimitX96 the sqrtPriceLimit (in binary fixed point math notation) beyond which the unwind swaps won't be executed
    /// @dev The purpose of this function is to let fully collateralised fixed takers to exist their swaps by entering into variable taker positions against the VAMM
    /// @dev thus effectively releasing the margin in yield bearing tokens from the fixed swap contract
    function unwindFullyCollateralisedFixedTakerSwap(
        uint256 notionalToUnwind,
        uint160 sqrtPriceLimitX96
    ) external returns (int256 fixedTokenDelta, int256 variableTokenDelta, uint256 cumulativeFeeIncurred, int256 fixedTokenDeltaUnbalanced);

    /// @notice Settle Trader
    /// @dev this function in the fcm let's traders settle with the MarginEngine based on their settlement cashflows which is a functon of their fixed and variable token balances
    function settleTrader() external returns (int256);

    /// @notice
    /// @param account address of the position owner from the MarginEngine who wishes to settle with the FCM in underlying tokens
    /// @param marginDeltaInUnderlyingTokens amount in terms of underlying tokens that needs to be settled with the trader from the MarginEngine
    function transferMarginToMarginEngineTrader(
        address account,
        uint256 marginDeltaInUnderlyingTokens
    ) external;

    /// @notice initialize is the constructor for the proxy instances of the FCM
    /// @dev "constructor" for proxy instances
    /// @dev in the initialize function we set the vamm and the margiEngine associated with the fcm
    /// @dev different FCM implementations are free to have different implementations for the initialisation logic
    function initialize(IVAMM __vamm, IMarginEngine __marginEngine)
        external;

    /// @notice Margine Engine linked to the Full Collateralisation Module
    /// @return marginEngine Margine Engine linked to the Full Collateralisation Module
    function marginEngine() external view returns (IMarginEngine);

    /// @notice VAMM linked to the Full Collateralisation Module
    /// @return VAMM linked to the Full Collateralisation Module
    function vamm() external view returns (IVAMM);

    /// @notice Rate Oracle linked to the Full Collateralisation Module
    /// @return Rate Oracle linked to the Full Collateralisation Module
    function rateOracle() external view returns (IRateOracle);

    event FullyCollateralisedSwap(
        address indexed trader,
        uint256 desiredNotional,
        uint160 sqrtPriceLimitX96,
        uint256 cumulativeFeeIncurred,
        int256 fixedTokenDelta,
        int256 variableTokenDelta,
        int256 fixedTokenDeltaUnbalanced
    );

    event FullyCollateralisedUnwind(
        address indexed trader,
        uint256 desiredNotional,
        uint160 sqrtPriceLimitX96,
        uint256 cumulativeFeeIncurred,
        int256 fixedTokenDelta,
        int256 variableTokenDelta,
        int256 fixedTokenDeltaUnbalanced
    );

    event fcmPositionSettlement(
        address indexed trader,
        int256 settlementCashflow
    );

    event FCMTraderUpdate(
        address indexed trader,
        uint256 marginInScaledYieldBearingTokens,
        int256 fixedTokenBalance,
        int256 variableTokenBalance
    );
}

File 27 of 41 : IRateOracle.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity =0.8.9;

import "../../utils/CustomErrors.sol";
import "../IERC20Minimal.sol";

/// @dev The RateOracle is used for two purposes on the Voltz Protocol
/// @dev Settlement: in order to be able to settle IRS positions after the termEndTimestamp of a given AMM
/// @dev Margin Engine Computations: getApyFromTo is used by the MarginEngine
/// @dev It is necessary to produce margin requirements for Trader and Liquidity Providers
interface IRateOracle is CustomErrors {

    // events
    event MinSecondsSinceLastUpdate(uint256 _minSecondsSinceLastUpdate);
    event OracleBufferUpdate(
        uint256 blockTimestampScaled,
        address source,
        uint16 index,
        uint32 blockTimestamp,
        uint256 observedValue,
        uint16 cardinality,
        uint16 cardinalityNext
    );

    /// @notice Emitted by the rate oracle for increases to the number of observations that can be stored
    /// @param observationCardinalityNextNew The updated value of the next observation cardinality
    event RateCardinalityNext(
        uint16 observationCardinalityNextNew
    );

    // view functions

    /// @notice Gets minimum number of seconds that need to pass since the last update to the rates array
    /// @dev This is a throttling mechanic that needs to ensure we don't run out of space in the rates array
    /// @dev The maximum size of the rates array is 65535 entries
    // AB: as long as this doesn't affect the termEndTimestamp rateValue too much
    // AB: can have a different minSecondsSinceLastUpdate close to termEndTimestamp to have more granularity for settlement purposes
    /// @return minSecondsSinceLastUpdate in seconds
    function minSecondsSinceLastUpdate() external view returns (uint256);

    /// @notice Gets the address of the underlying token of the RateOracle
    /// @dev may be unset (`address(0)`) if the underlying is ETH
    /// @return underlying The address of the underlying token
    function underlying() external view returns (IERC20Minimal);

    /// @notice Gets the variable factor between termStartTimestamp and termEndTimestamp
    /// @return result The variable factor
    /// @dev If the current block timestamp is beyond the maturity of the AMM, then the variableFactor is getRateFromTo(termStartTimestamp, termEndTimestamp). Term end timestamps are cached for quick retrieval later.
    /// @dev If the current block timestamp is before the maturity of the AMM, then the variableFactor is getRateFromTo(termStartTimestamp,Time.blockTimestampScaled());
    /// @dev if queried before maturity then returns the rate of return between pool initiation and current timestamp (in wad)
    /// @dev if queried after maturity then returns the rate of return between pool initiation and maturity timestamp (in wad)
    function variableFactor(uint256 termStartTimestamp, uint256 termEndTimestamp) external returns(uint256 result);

    /// @notice Gets the variable factor between termStartTimestamp and termEndTimestamp
    /// @return result The variable factor
    /// @dev If the current block timestamp is beyond the maturity of the AMM, then the variableFactor is getRateFromTo(termStartTimestamp, termEndTimestamp). No caching takes place.
    /// @dev If the current block timestamp is before the maturity of the AMM, then the variableFactor is getRateFromTo(termStartTimestamp,Time.blockTimestampScaled());
    function variableFactorNoCache(uint256 termStartTimestamp, uint256 termEndTimestamp) external view returns(uint256 result);
    
    /// @notice Calculates the observed interest returned by the underlying in a given period
    /// @dev Reverts if we have no data point for `_from`
    /// @param _from The timestamp of the start of the period, in seconds
    /// @return The "floating rate" expressed in Wad, e.g. 4% is encoded as 0.04*10**18 = 4*10**16
    function getRateFrom(uint256 _from)
        external
        view
        returns (uint256);

    /// @notice Calculates the observed interest returned by the underlying in a given period
    /// @dev Reverts if we have no data point for either timestamp
    /// @param _from The timestamp of the start of the period, in seconds
    /// @param _to The timestamp of the end of the period, in seconds
    /// @return The "floating rate" expressed in Wad, e.g. 4% is encoded as 0.04*10**18 = 4*10**16
    function getRateFromTo(uint256 _from, uint256 _to)
        external
        view
        returns (uint256);

    /// @notice Calculates the observed APY returned by the rate oracle between the given timestamp and the current time
    /// @param from The timestamp of the start of the period, in seconds
    /// @dev Reverts if we have no data point for `from`
    /// @return apyFromTo The "floating rate" expressed in Wad, e.g. 4% is encoded as 0.04*10**18 = 4*10**16
    function getApyFrom(uint256 from)
        external
        view
        returns (uint256 apyFromTo);

    /// @notice Calculates the observed APY returned by the rate oracle in a given period
    /// @param from The timestamp of the start of the period, in seconds
    /// @param to The timestamp of the end of the period, in seconds
    /// @dev Reverts if we have no data point for either timestamp
    /// @return apyFromTo The "floating rate" expressed in Wad, e.g. 4% is encoded as 0.04*10**18 = 4*10**16
    function getApyFromTo(uint256 from, uint256 to)
        external
        view
        returns (uint256 apyFromTo);

    // non-view functions

    /// @notice Sets minSecondsSinceLastUpdate: The minimum number of seconds that need to pass since the last update to the rates array
    /// @dev Can only be set by the Factory Owner
    function setMinSecondsSinceLastUpdate(uint256 _minSecondsSinceLastUpdate) external;

    /// @notice Increase the maximum number of rates observations that this RateOracle will store
    /// @dev This method is no-op if the RateOracle already has an observationCardinalityNext greater than or equal to
    /// the input observationCardinalityNext.
    /// @param rateCardinalityNext The desired minimum number of observations for the pool to store
    function increaseObservationCardinalityNext(uint16 rateCardinalityNext) external;

    /// @notice Writes a rate observation to the rates array given the current rate cardinality, rate index and rate cardinality next
    /// Write oracle entry is called whenever a new position is minted via the vamm or when a swap is initiated via the vamm
    /// That way the gas costs of Rate Oracle updates can be distributed across organic interactions with the protocol
    function writeOracleEntry() external;

    /// @notice unique ID of the underlying yield bearing protocol (e.g. Aave v2 has id 1)
    /// @return yieldBearingProtocolID unique id of the underlying yield bearing protocol
    function UNDERLYING_YIELD_BEARING_PROTOCOL_ID() external view returns(uint8 yieldBearingProtocolID);

    /// @notice returns the last change in rate and time
    /// Gets the last two observations and returns the change in rate and time.
    /// This can help us to extrapolate an estiamte of the current rate from recent known rates. 
    function getLastRateSlope()
        external
        view
        returns (uint256 rateChange, uint32 timeChange);

    /// @notice Get the current "rate" in Ray at the current timestamp.
    /// This might be a direct reading if real-time readings are available, or it might be an extrapolation from recent known rates.
    /// The source and expected values of "rate" may differ by rate oracle type. All that
    /// matters is that we can divide one "rate" by another "rate" to get the factor of growth between the two timestamps.
    /// For example if we have rates of { (t=0, rate=5), (t=100, rate=5.5) }, we can divide 5.5 by 5 to get a growth factor
    /// of 1.1, suggesting that 10% growth in capital was experienced between timesamp 0 and timestamp 100.
    /// @dev For convenience, the rate is normalised to Ray for storage, so that we can perform consistent math across all rates.
    /// @dev This function should revert if a valid rate cannot be discerned
    /// @return currentRate the rate in Ray (decimal scaled up by 10^27 for storage in a uint256)
    function getCurrentRateInRay()
        external
        view
        returns (uint256 currentRate);

    /// @notice returns the last change in block number and timestamp 
    /// Some implementations may use this data to estimate timestamps for recent rate readings, if we only know the block number
    function getBlockSlope()
        external
        view
        returns (uint256 blockChange, uint32 timeChange);
}

File 28 of 41 : VAMMStorage.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity =0.8.9;
import "../interfaces/IVAMM.sol";
import "../interfaces/IFactory.sol";
import "../interfaces/IMarginEngine.sol";
import "../core_libraries/Tick.sol";

contract VAMMStorageV1 {
    // cached rateOracle from the MarginEngine associated with the VAMM
    IRateOracle internal rateOracle;
    // cached termStartTimstampWad from the MarginEngine associated with the VAMM
    uint256 internal termStartTimestampWad;
    // cached termEndTimestampWad from the MarginEngine associated with the VAMM
    uint256 internal termEndTimestampWad;
    IMarginEngine internal _marginEngine;
    uint128 internal _maxLiquidityPerTick;
    IFactory internal _factory;

    // Any variables that would implicitly implement an IVAMM function if public, must instead
    // be internal due to limitations in the solidity compiler (as of 0.8.12)
    uint256 internal _feeWad;
    // Mutex
    bool internal _unlocked;
    uint128 internal _liquidity;
    uint256 internal _feeGrowthGlobalX128;
    uint256 internal _protocolFees;
    int256 internal _fixedTokenGrowthGlobalX128;
    int256 internal _variableTokenGrowthGlobalX128;
    int24 internal _tickSpacing;
    mapping(int24 => Tick.Info) internal _ticks;
    mapping(int16 => uint256) internal _tickBitmap;
    IVAMM.VAMMVars internal _vammVars;
    bool internal _isAlpha;

    mapping(address => bool) internal pauser;
    bool public paused;
}

contract VAMMStorage is VAMMStorageV1 {
    // Reserve some storage for use in future versions, without creating conflicts
    // with other inheritted contracts
    uint256[50] private __gap;
}

File 29 of 41 : BitMath.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity =0.8.9;

/// @title BitMath
/// @dev This library provides functionality for computing bit properties of an unsigned integer
library BitMath {
    /// @notice Returns the index of the most significant bit of the number,
    ///     where the least significant bit is at index 0 and the most significant bit is at index 255
    /// @dev The function satisfies the property:
    ///     x >= 2**mostSignificantBit(x) and x < 2**(mostSignificantBit(x)+1)
    /// @param x the value for which to compute the most significant bit, must be greater than 0
    /// @return r the index of the most significant bit
    function mostSignificantBit(uint256 x) internal pure returns (uint8 r) {
        require(x > 0, "x must be > 0");

        if (x >= 0x100000000000000000000000000000000) {
            x >>= 128;
            r += 128;
        }
        if (x >= 0x10000000000000000) {
            x >>= 64;
            r += 64;
        }
        if (x >= 0x100000000) {
            x >>= 32;
            r += 32;
        }
        if (x >= 0x10000) {
            x >>= 16;
            r += 16;
        }
        if (x >= 0x100) {
            x >>= 8;
            r += 8;
        }
        if (x >= 0x10) {
            x >>= 4;
            r += 4;
        }
        if (x >= 0x4) {
            x >>= 2;
            r += 2;
        }
        if (x >= 0x2) r += 1;
    }

    /// @notice Returns the index of the least significant bit of the number,
    ///     where the least significant bit is at index 0 and the most significant bit is at index 255
    /// @dev The function satisfies the property:
    ///     (x & 2**leastSignificantBit(x)) != 0 and (x & (2**(leastSignificantBit(x)) - 1)) == 0)
    /// @param x the value for which to compute the least significant bit, must be greater than 0
    /// @return r the index of the least significant bit
    function leastSignificantBit(uint256 x) internal pure returns (uint8 r) {
        require(x > 0, "x must be > 0");

        r = 255;
        if (x & type(uint128).max > 0) {
            r -= 128;
        } else {
            x >>= 128;
        }
        if (x & type(uint64).max > 0) {
            r -= 64;
        } else {
            x >>= 64;
        }
        if (x & type(uint32).max > 0) {
            r -= 32;
        } else {
            x >>= 32;
        }
        if (x & type(uint16).max > 0) {
            r -= 16;
        } else {
            x >>= 16;
        }
        if (x & type(uint8).max > 0) {
            r -= 8;
        } else {
            x >>= 8;
        }
        if (x & 0xf > 0) {
            r -= 4;
        } else {
            x >>= 4;
        }
        if (x & 0x3 > 0) {
            r -= 2;
        } else {
            x >>= 2;
        }
        if (x & 0x1 > 0) r -= 1;
    }
}

File 30 of 41 : CustomErrors.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity =0.8.9;

interface CustomErrors {
    /// @dev No need to unwind a net zero position
    error PositionNetZero();

    error DebugError(uint256 x, uint256 y);

    /// @dev Cannot have less margin than the minimum requirement
    error MarginLessThanMinimum(int256 marginRequirement);

    /// @dev We can't withdraw more margin than we have
    error WithdrawalExceedsCurrentMargin();

    /// @dev Position must be settled after AMM has reached maturity
    error PositionNotSettled();

    /// The resulting margin does not meet minimum requirements
    error MarginRequirementNotMet(
        int256 marginRequirement,
        int24 tick,
        int256 fixedTokenDelta,
        int256 variableTokenDelta,
        uint256 cumulativeFeeIncurred,
        int256 fixedTokenDeltaUnbalanced
    );

    /// The position/trader needs to be below the liquidation threshold to be liquidated
    error CannotLiquidate();

    /// Only the position/trade owner can update the LP/Trader margin
    error OnlyOwnerCanUpdatePosition();

    error OnlyVAMM();

    error OnlyFCM();

    /// Margin delta must not equal zero
    error InvalidMarginDelta();

    /// Positions and Traders cannot be settled before the applicable interest rate swap has matured
    error CannotSettleBeforeMaturity();

    error closeToOrBeyondMaturity();

    /// @dev There are not enough funds available for the requested operation
    error NotEnoughFunds(uint256 requested, uint256 available);

    /// @dev The two values were expected to have oppostite sigs, but do not
    error ExpectedOppositeSigns(int256 amount0, int256 amount1);

    /// @dev Error which is reverted if the sqrt price of the vamm is non-zero before a vamm is initialized
    error ExpectedSqrtPriceZeroBeforeInit(uint160 sqrtPriceX96);

    /// @dev Error which ensures the liquidity delta is positive if a given LP wishes to mint further liquidity in the vamm
    error LiquidityDeltaMustBePositiveInMint(uint128 amount);

    /// @dev Error which ensures the liquidity delta is positive if a given LP wishes to burn liquidity in the vamm
    error LiquidityDeltaMustBePositiveInBurn(uint128 amount);

    /// @dev Error which ensures the amount of notional specified when initiating an IRS contract (via the swap function in the vamm) is non-zero
    error IRSNotionalAmountSpecifiedMustBeNonZero();

    /// @dev Error which ensures the VAMM is unlocked
    error CanOnlyTradeIfUnlocked(bool unlocked);

    /// @dev only the margin engine can run a certain function
    error OnlyMarginEngine();

    /// The resulting margin does not meet minimum requirements
    error MarginRequirementNotMetFCM(int256 marginRequirement);

    /// @dev getReserveNormalizedIncome() returned zero for underlying asset. Oracle only supports active Aave-V2 assets.
    error AavePoolGetReserveNormalizedIncomeReturnedZero();

    /// @dev getReserveNormalizedVariableDebt() returned zero for underlying asset. Oracle only supports active Aave-V2 assets.
    error AavePoolGetReserveNormalizedVariableDebtReturnedZero();

    /// @dev getPooledEthByShares() returned zero for Lido's stETH.
    error LidoGetPooledEthBySharesReturnedZero();

    /// @dev getEthValue() returned zero for RocketPool's RETH.
    error RocketPoolGetEthValueReturnedZero();

    /// @dev ctoken.exchangeRateStored() returned zero for a given Compound ctoken. Oracle only supports active Compound assets.
    error CTokenExchangeRateReturnedZero();

    /// @dev currentTime < queriedTime
    error OOO();
}

File 31 of 41 : FixedPoint128.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity =0.8.9;

/// @title FixedPoint128
/// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format)
library FixedPoint128 {
    uint256 internal constant Q128 = 0x100000000000000000000000000000000;
}

File 32 of 41 : FixedPoint96.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity =0.8.9;

/// @title FixedPoint96
/// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format)
/// @dev Used in SqrtPriceMath.sol
library FixedPoint96 {
    uint8 internal constant RESOLUTION = 96;
    uint256 internal constant Q96 = 0x1000000000000000000000000;
}

File 33 of 41 : FullMath.sol
// SPDX-License-Identifier: MIT

// solhint-disable no-inline-assembly

pragma solidity =0.8.9;

/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {
    /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv

    function mulDivSigned(
        int256 a,
        uint256 b,
        uint256 denominator
    ) internal pure returns (int256 result) {
        if (a < 0) return -int256(mulDiv(uint256(-a), b, denominator));
        return int256(mulDiv(uint256(a), b, denominator));
    }

    function mulDiv(
        uint256 a,
        uint256 b,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        // 512-bit multiply [prod1 prod0] = a * b
        // Compute the product mod 2**256 and mod 2**256 - 1
        // then use the Chinese Remainder Theorem to reconstruct
        // the 512 bit result. The result is stored in two 256
        // variables such that product = prod1 * 2**256 + prod0
        uint256 prod0; // Least significant 256 bits of the product
        uint256 prod1; // Most significant 256 bits of the product

        unchecked {
            assembly {
                let mm := mulmod(a, b, not(0))
                prod0 := mul(a, b)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division
            if (prod1 == 0) {
                require(denominator > 0, "Division by zero");
                assembly {
                    result := div(prod0, denominator)
                }
                return result;
            }

            // Make sure the result is less than 2**256.
            // Also prevents denominator == 0
            require(denominator > prod1, "overflow");

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0]
            // Compute remainder using mulmod
            uint256 remainder;
            assembly {
                remainder := mulmod(a, b, denominator)
            }
            // Subtract 256 bit number from 512 bit number
            assembly {
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator
            // Compute largest power of two divisor of denominator.
            // Always >= 1.
            // uint256 twos = -denominator & denominator;
            // https://ethereum.stackexchange.com/questions/96642/unary-operator-cannot-be-applied-to-type-uint256
            uint256 twos = (type(uint256).max - denominator + 1) & denominator;
            // Divide denominator by power of two
            assembly {
                denominator := div(denominator, twos)
            }

            // Divide [prod1 prod0] by the factors of two
            assembly {
                prod0 := div(prod0, twos)
            }
            // Shift in bits from prod1 into prod0. For this we need
            // to flip `twos` such that it is 2**256 / twos.
            // If twos is zero, then it becomes one
            assembly {
                twos := add(div(sub(0, twos), twos), 1)
            }
            prod0 |= prod1 * twos;

            // Invert denominator mod 2**256
            // Now that denominator is an odd number, it has an inverse
            // modulo 2**256 such that denominator * inv = 1 mod 2**256.
            // Compute the inverse by starting with a seed that is correct
            // correct for four bits. That is, denominator * inv = 1 mod 2**4
            uint256 inv = (3 * denominator) ^ 2;
            // Now use Newton-Raphson iteration to improve the precision.
            // Thanks to Hensel's lifting lemma, this also works in modular
            // arithmetic, doubling the correct bits in each step.
            inv *= 2 - denominator * inv; // inverse mod 2**8
            inv *= 2 - denominator * inv; // inverse mod 2**16
            inv *= 2 - denominator * inv; // inverse mod 2**32
            inv *= 2 - denominator * inv; // inverse mod 2**64
            inv *= 2 - denominator * inv; // inverse mod 2**128
            inv *= 2 - denominator * inv; // inverse mod 2**256

            // Because the division is now exact we can divide by multiplying
            // with the modular inverse of denominator. This will give us the
            // correct result modulo 2**256. Since the precoditions guarantee
            // that the outcome is less than 2**256, this is the final result.
            // We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inv;
            return result;
        }
    }

    /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    function mulDivRoundingUp(
        uint256 a,
        uint256 b,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        result = mulDiv(a, b, denominator);
        if (mulmod(a, b, denominator) > 0) {
            require(result < type(uint256).max, "overflow");
            result++;
        }
    }
}

File 34 of 41 : LiquidityMath.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity =0.8.9;

/// @title Math library for liquidity
library LiquidityMath {
    /// @notice Add a signed liquidity delta to liquidity and revert if it overflows or underflows
    /// @param x The liquidity before change
    /// @param y The delta by which liquidity should be changed
    /// @return z The liquidity delta
    function addDelta(uint128 x, int128 y) internal pure returns (uint128 z) {
        if (y < 0) {
            uint128 yAbsolute;

            unchecked {
                yAbsolute = uint128(-y);
            }

            z = x - yAbsolute;
        } else {
            z = x + uint128(y);
        }
    }
}

File 35 of 41 : SafeCastUni.sol
// SPDX-License-Identifier: BUSL-1.1
// With contributions from OpenZeppelin Contracts v4.4.0 (utils/math/SafeCast.sol)

pragma solidity =0.8.9;

/// @title Safe casting methods
/// @notice Contains methods for safely casting between types
library SafeCastUni {
    /// @notice Cast a uint256 to a uint160, revert on overflow
    /// @param y The uint256 to be downcasted
    /// @return z The downcasted integer, now type uint160
    function toUint160(uint256 y) internal pure returns (uint160 z) {
        require((z = uint160(y)) == y, "toUint160 oflo");
    }

    /// @notice Cast a int256 to a int128, revert on overflow or underflow
    /// @param y The int256 to be downcasted
    /// @return z The downcasted integer, now type int128
    function toInt128(int256 y) internal pure returns (int128 z) {
        require((z = int128(y)) == y, "toInt128 oflo");
    }

    /// @notice Cast a uint256 to a int256, revert on overflow
    /// @param y The uint256 to be casted
    /// @return z The casted integer, now type int256
    function toInt256(uint256 y) internal pure returns (int256 z) {
        require(y < 2**255, "toInt256 oflo");
        z = int256(y);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "toUint256 < 0");
        return uint256(value);
    }
}

File 36 of 41 : SqrtPriceMath.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity =0.8.9;

import "./SafeCastUni.sol";

import "./FullMath.sol";
import "./UnsafeMath.sol";
import "./FixedPoint96.sol";

/// @title Functions based on Q64.96 sqrt price and liquidity
/// @notice Contains the math that uses square root of price as a Q64.96 and liquidity to compute deltas
library SqrtPriceMath {
    using SafeCastUni for uint256;

    /// @notice Gets the next sqrt price given a delta of token0
    /// @dev Always rounds up, because in the exact output case (increasing price) we need to move the price at least
    /// far enough to get the desired output amount, and in the exact input case (decreasing price) we need to move the
    /// price less in order to not send too much output.
    /// The most precise formula for this is liquidity * sqrtPX96 / (liquidity +- amount * sqrtPX96),
    /// if this is impossible because of overflow, we calculate liquidity / (liquidity / sqrtPX96 +- amount).
    /// @param sqrtPX96 The starting price, i.e. before accounting for the token0 delta
    /// @param liquidity The amount of usable liquidity
    /// @param amount How much of token0 to add or remove from virtual reserves
    /// @param add Whether to add or remove the amount of token0
    /// @return The price after adding or removing amount, depending on add
    function getNextSqrtPriceFromAmount0RoundingUp(
        uint160 sqrtPX96,
        uint128 liquidity,
        uint256 amount,
        bool add
    ) internal pure returns (uint160) {
        // we short circuit amount == 0 because the result is otherwise not guaranteed to equal the input price
        if (amount == 0) return sqrtPX96;
        uint256 numerator1 = uint256(liquidity) << FixedPoint96.RESOLUTION;

        if (add) {
            uint256 product;
            if ((product = amount * sqrtPX96) / amount == sqrtPX96) {
                uint256 denominator = numerator1 + product;
                if (denominator >= numerator1)
                    // always fits in 160 bits
                    return
                        uint160(
                            FullMath.mulDivRoundingUp(
                                numerator1,
                                sqrtPX96,
                                denominator
                            )
                        );
            }

            return
                uint160(
                    UnsafeMath.divRoundingUp(
                        numerator1,
                        (numerator1 / sqrtPX96) + amount
                    )
                );
        } else {
            uint256 product;
            // if the product overflows, we know the denominator underflows
            // in addition, we must check that the denominator does not underflow
            require(
                (product = amount * sqrtPX96) / amount == sqrtPX96 &&
                    numerator1 > product,
                "denom uflow"
            );
            uint256 denominator = numerator1 - product;
            return
                FullMath
                    .mulDivRoundingUp(numerator1, sqrtPX96, denominator)
                    .toUint160();
        }
    }

    /// @notice Gets the next sqrt price given a delta of token1
    /// @dev Always rounds down, because in the exact output case (decreasing price) we need to move the price at least
    /// far enough to get the desired output amount, and in the exact input case (increasing price) we need to move the
    /// price less in order to not send too much output.
    /// The formula we compute is within <1 wei of the lossless version: sqrtPX96 +- amount / liquidity
    /// @param sqrtPX96 The starting price, i.e., before accounting for the token1 delta
    /// @param liquidity The amount of usable liquidity
    /// @param amount How much of token1 to add, or remove, from virtual reserves
    /// @param add Whether to add, or remove, the amount of token1
    /// @return The price after adding or removing `amount`
    function getNextSqrtPriceFromAmount1RoundingDown(
        uint160 sqrtPX96,
        uint128 liquidity,
        uint256 amount,
        bool add
    ) internal pure returns (uint160) {
        // if we're adding (subtracting), rounding down requires rounding the quotient down (up)
        // in both cases, avoid a mulDiv for most inputs
        if (add) {
            uint256 quotient = (
                amount <= type(uint160).max
                    ? (amount << FixedPoint96.RESOLUTION) / liquidity
                    : FullMath.mulDiv(amount, FixedPoint96.Q96, liquidity)
            );

            return sqrtPX96 + quotient.toUint160();
        } else {
            uint256 quotient = (
                amount <= type(uint160).max
                    ? UnsafeMath.divRoundingUp(
                        amount << FixedPoint96.RESOLUTION,
                        liquidity
                    )
                    : FullMath.mulDivRoundingUp(
                        amount,
                        FixedPoint96.Q96,
                        liquidity
                    )
            );

            require(sqrtPX96 > quotient, "sqrtPX96 !> quotient");
            // always fits 160 bits
            return uint160(sqrtPX96 - quotient);
        }
    }

    /// @notice Gets the next sqrt price given an input amount of token0 or token1
    /// @dev Throws if price or liquidity are 0, or if the next price is out of bounds
    /// @param sqrtPX96 The starting price, i.e., before accounting for the input amount
    /// @param liquidity The amount of usable liquidity
    /// @param amountIn How much of token0, or token1, is being swapped in
    /// @param zeroForOne Whether the amount in is token0 or token1
    /// @return sqrtQX96 The price after adding the input amount to token0 or token1
    function getNextSqrtPriceFromInput(
        uint160 sqrtPX96,
        uint128 liquidity,
        uint256 amountIn,
        bool zeroForOne
    ) internal pure returns (uint160 sqrtQX96) {
        require(sqrtPX96 > 0, "sqrtPX96 !> 0");
        require(liquidity > 0, "liq !> 0");

        // round to make sure that we don't pass the target price
        return
            zeroForOne
                ? getNextSqrtPriceFromAmount0RoundingUp(
                    sqrtPX96,
                    liquidity,
                    amountIn,
                    true
                )
                : getNextSqrtPriceFromAmount1RoundingDown(
                    sqrtPX96,
                    liquidity,
                    amountIn,
                    true
                );
    }

    /// @notice Gets the next sqrt price given an output amount of token0 or token1
    /// @dev Throws if price or liquidity are 0 or the next price is out of bounds
    /// @param sqrtPX96 The starting price before accounting for the output amount
    /// @param liquidity The amount of usable liquidity
    /// @param amountOut How much of token0, or token1, is being swapped out
    /// @param zeroForOne Whether the amount out is token0 or token1
    /// @return sqrtQX96 The price after removing the output amount of token0 or token1
    function getNextSqrtPriceFromOutput(
        uint160 sqrtPX96,
        uint128 liquidity,
        uint256 amountOut,
        bool zeroForOne
    ) internal pure returns (uint160 sqrtQX96) {
        require(sqrtPX96 > 0, "sqrtPX96 !> 0");
        require(liquidity > 0, "liq !> 0");

        // round to make sure that we pass the target price
        return
            zeroForOne
                ? getNextSqrtPriceFromAmount1RoundingDown(
                    sqrtPX96,
                    liquidity,
                    amountOut,
                    false
                )
                : getNextSqrtPriceFromAmount0RoundingUp(
                    sqrtPX96,
                    liquidity,
                    amountOut,
                    false
                );
    }

    /// @notice Gets the amount0 delta between two prices
    /// @dev Calculates liquidity / sqrt(lower) - liquidity / sqrt(upper),
    /// i.e. liquidity * (sqrt(upper) - sqrt(lower)) / (sqrt(upper) * sqrt(lower))
    /// @param sqrtRatioAX96 A sqrt price
    /// @param sqrtRatioBX96 Another sqrt price
    /// @param liquidity The amount of usable liquidity
    /// @param roundUp Whether to round the amount up or down
    /// @return amount0 Amount of token0 required to cover a position of size liquidity between the two passed prices
    function getAmount0Delta(
        uint160 sqrtRatioAX96,
        uint160 sqrtRatioBX96,
        uint128 liquidity,
        bool roundUp
    ) internal pure returns (uint256 amount0) {
        if (sqrtRatioAX96 > sqrtRatioBX96)
            (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);

        uint256 numerator1 = uint256(liquidity) << FixedPoint96.RESOLUTION;
        uint256 numerator2 = sqrtRatioBX96 - sqrtRatioAX96;

        require(sqrtRatioAX96 > 0, "sqrtRatioAX96 !> 0");

        // test the effect of he unchecked blocks
        unchecked {
            return
                roundUp
                    ? UnsafeMath.divRoundingUp(
                        FullMath.mulDivRoundingUp(
                            numerator1,
                            numerator2,
                            sqrtRatioBX96
                        ),
                        sqrtRatioAX96
                    )
                    : FullMath.mulDiv(numerator1, numerator2, sqrtRatioBX96) /
                        sqrtRatioAX96;
        }
    }

    /// @notice Gets the amount1 delta between two prices
    /// @dev Calculates liquidity * (sqrt(upper) - sqrt(lower))
    /// @param sqrtRatioAX96 A sqrt price
    /// @param sqrtRatioBX96 Another sqrt price
    /// @param liquidity The amount of usable liquidity
    /// @param roundUp Whether to round the amount up, or down
    /// @return amount1 Amount of token1 required to cover a position of size liquidity between the two passed prices
    function getAmount1Delta(
        uint160 sqrtRatioAX96,
        uint160 sqrtRatioBX96,
        uint128 liquidity,
        bool roundUp
    ) internal pure returns (uint256 amount1) {
        if (sqrtRatioAX96 > sqrtRatioBX96)
            (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);

        unchecked {
            return
                roundUp
                    ? FullMath.mulDivRoundingUp(
                        liquidity,
                        sqrtRatioBX96 - sqrtRatioAX96,
                        FixedPoint96.Q96
                    )
                    : FullMath.mulDiv(
                        liquidity,
                        sqrtRatioBX96 - sqrtRatioAX96,
                        FixedPoint96.Q96
                    );
        }
    }

    /// @notice Helper that gets signed token0 delta
    /// @param sqrtRatioAX96 A sqrt price
    /// @param sqrtRatioBX96 Another sqrt price
    /// @param liquidity The change in liquidity for which to compute the amount0 delta
    /// @return amount0 Amount of token0 corresponding to the passed liquidityDelta between the two prices
    function getAmount0Delta(
        uint160 sqrtRatioAX96,
        uint160 sqrtRatioBX96,
        int128 liquidity
    ) internal pure returns (int256 amount0) {
        return
            liquidity < 0
                ? -getAmount0Delta(
                    sqrtRatioAX96,
                    sqrtRatioBX96,
                    uint128(-liquidity),
                    false
                ).toInt256()
                : getAmount0Delta(
                    sqrtRatioAX96,
                    sqrtRatioBX96,
                    uint128(liquidity),
                    true
                ).toInt256();
    }

    /// @notice Helper that gets signed token1 delta
    /// @param sqrtRatioAX96 A sqrt price
    /// @param sqrtRatioBX96 Another sqrt price
    /// @param liquidity The change in liquidity for which to compute the amount1 delta
    /// @return amount1 Amount of token1 corresponding to the passed liquidityDelta between the two prices
    function getAmount1Delta(
        uint160 sqrtRatioAX96,
        uint160 sqrtRatioBX96,
        int128 liquidity
    ) internal pure returns (int256 amount1) {
        return
            liquidity < 0
                ? -getAmount1Delta(
                    sqrtRatioAX96,
                    sqrtRatioBX96,
                    uint128(-liquidity),
                    false
                ).toInt256()
                : getAmount1Delta(
                    sqrtRatioAX96,
                    sqrtRatioBX96,
                    uint128(liquidity),
                    true
                ).toInt256();
    }
}

File 37 of 41 : TickMath.sol
// SPDX-License-Identifier: BUSL-1.1

// solhint-disable no-inline-assembly

pragma solidity =0.8.9;

/// @title Math library for computing sqrt prices from ticks and vice versa
/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports
/// prices between 2**-128 and 2**128
library TickMath {
    /// @dev MIN_TICK corresponds to an annualized fixed rate of 1000%
    /// @dev MAX_TICK corresponds to an annualized fixed rate of 0.001%
    /// @dev MIN and MAX TICKs can't be safely changed without reinstating getSqrtRatioAtTick removed lines of code from original
    /// TickMath.sol implementation in uniswap v3

    /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128
    int24 internal constant MIN_TICK = -69100;
    /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128
    int24 internal constant MAX_TICK = -MIN_TICK;

    /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
    uint160 internal constant MIN_SQRT_RATIO = 2503036416286949174936592462;
    /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
    uint160 internal constant MAX_SQRT_RATIO = 2507794810551837817144115957740;

    /// @notice Calculates sqrt(1.0001^tick) * 2^96
    /// @dev Throws if |tick| > max tick
    /// @param tick The input tick for the above formula
    /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)
    /// at the given tick
    function getSqrtRatioAtTick(int24 tick)
        internal
        pure
        returns (uint160 sqrtPriceX96)
    {
        uint256 absTick = tick < 0
            ? uint256(-int256(tick))
            : uint256(int256(tick));
        require(absTick <= uint256(int256(MAX_TICK)), "T");

        uint256 ratio = absTick & 0x1 != 0
            ? 0xfffcb933bd6fad37aa2d162d1a594001
            : 0x100000000000000000000000000000000;
        if (absTick & 0x2 != 0)
            ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
        if (absTick & 0x4 != 0)
            ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
        if (absTick & 0x8 != 0)
            ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
        if (absTick & 0x10 != 0)
            ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;
        if (absTick & 0x20 != 0)
            ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
        if (absTick & 0x40 != 0)
            ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
        if (absTick & 0x80 != 0)
            ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
        if (absTick & 0x100 != 0)
            ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
        if (absTick & 0x200 != 0)
            ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
        if (absTick & 0x400 != 0)
            ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
        if (absTick & 0x800 != 0)
            ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
        if (absTick & 0x1000 != 0)
            ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
        if (absTick & 0x2000 != 0)
            ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
        if (absTick & 0x4000 != 0)
            ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
        if (absTick & 0x8000 != 0)
            ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;
        if (absTick & 0x10000 != 0)
            ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
        if (tick > 0) ratio = type(uint256).max / ratio;

        // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
        // we then downcast because we know the result always fits within 160 bits due to our tick input constraint
        // we round up in the division so getTickAtSqrtRatio of the output price is always consistent
        sqrtPriceX96 = uint160(
            (ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1)
        );
    }

    /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio
    /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may
    /// ever return.
    /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96
    /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio
    function getTickAtSqrtRatio(uint160 sqrtPriceX96)
        internal
        pure
        returns (int24 tick)
    {
        // second inequality must be < because the price can never reach the price at the max tick
        require(
            sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO,
            "R"
        );
        uint256 ratio = uint256(sqrtPriceX96) << 32;

        uint256 r = ratio;
        uint256 msb = 0;

        assembly {
            let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(5, gt(r, 0xFFFFFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(4, gt(r, 0xFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(3, gt(r, 0xFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(2, gt(r, 0xF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(1, gt(r, 0x3))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := gt(r, 0x1)
            msb := or(msb, f)
        }

        if (msb >= 128) r = ratio >> (msb - 127);
        else r = ratio << (127 - msb);

        // solhint-disable-next-line var-name-mixedcase
        int256 log_2 = (int256(msb) - 128) << 64;

        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(63, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(62, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(61, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(60, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(59, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(58, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(57, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(56, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(55, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(54, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(53, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(52, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(51, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(50, f))
        }

        // solhint-disable-next-line var-name-mixedcase
        int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number

        int24 tickLow = int24(
            (log_sqrt10001 - 3402992956809132418596140100660247210) >> 128
        );
        int24 tickHi = int24(
            (log_sqrt10001 + 291339464771989622907027621153398088495) >> 128
        );

        tick = tickLow == tickHi
            ? tickLow
            : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96
            ? tickHi
            : tickLow;
    }
}

File 38 of 41 : UnsafeMath.sol
// SPDX-License-Identifier: BUSL-1.1

// solhint-disable no-inline-assembly

pragma solidity =0.8.9;

/// @title Math functions that do not check inputs or outputs
/// @notice Contains methods that perform common math functions but do not do any overflow or underflow checks
library UnsafeMath {
    /// @notice Returns ceil(x / y)
    /// @dev division by 0 has unspecified behavior, and must be checked externally
    /// @param x The dividend
    /// @param y The divisor
    /// @return z The quotient, ceil(x / y)
    function divRoundingUp(uint256 x, uint256 y)
        internal
        pure
        returns (uint256 z)
    {
        assembly {
            z := add(div(x, y), gt(mod(x, y), 0))
        }
    }
}

File 39 of 41 : PRBMath.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.4;

/// @notice Emitted when the result overflows uint256.
error PRBMath__MulDivFixedPointOverflow(uint256 prod1);

/// @notice Emitted when the result overflows uint256.
error PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);

/// @notice Emitted when one of the inputs is type(int256).min.
error PRBMath__MulDivSignedInputTooSmall();

/// @notice Emitted when the intermediary absolute result overflows int256.
error PRBMath__MulDivSignedOverflow(uint256 rAbs);

/// @notice Emitted when the input is MIN_SD59x18.
error PRBMathSD59x18__AbsInputTooSmall();

/// @notice Emitted when ceiling a number overflows SD59x18.
error PRBMathSD59x18__CeilOverflow(int256 x);

/// @notice Emitted when one of the inputs is MIN_SD59x18.
error PRBMathSD59x18__DivInputTooSmall();

/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.
error PRBMathSD59x18__DivOverflow(uint256 rAbs);

/// @notice Emitted when the input is greater than 133.084258667509499441.
error PRBMathSD59x18__ExpInputTooBig(int256 x);

/// @notice Emitted when the input is greater than 192.
error PRBMathSD59x18__Exp2InputTooBig(int256 x);

/// @notice Emitted when flooring a number underflows SD59x18.
error PRBMathSD59x18__FloorUnderflow(int256 x);

/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.
error PRBMathSD59x18__FromIntOverflow(int256 x);

/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.
error PRBMathSD59x18__FromIntUnderflow(int256 x);

/// @notice Emitted when the product of the inputs is negative.
error PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);

/// @notice Emitted when multiplying the inputs overflows SD59x18.
error PRBMathSD59x18__GmOverflow(int256 x, int256 y);

/// @notice Emitted when the input is less than or equal to zero.
error PRBMathSD59x18__LogInputTooSmall(int256 x);

/// @notice Emitted when one of the inputs is MIN_SD59x18.
error PRBMathSD59x18__MulInputTooSmall();

/// @notice Emitted when the intermediary absolute result overflows SD59x18.
error PRBMathSD59x18__MulOverflow(uint256 rAbs);

/// @notice Emitted when the intermediary absolute result overflows SD59x18.
error PRBMathSD59x18__PowuOverflow(uint256 rAbs);

/// @notice Emitted when the input is negative.
error PRBMathSD59x18__SqrtNegativeInput(int256 x);

/// @notice Emitted when the calculating the square root overflows SD59x18.
error PRBMathSD59x18__SqrtOverflow(int256 x);

/// @notice Emitted when addition overflows UD60x18.
error PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);

/// @notice Emitted when ceiling a number overflows UD60x18.
error PRBMathUD60x18__CeilOverflow(uint256 x);

/// @notice Emitted when the input is greater than 133.084258667509499441.
error PRBMathUD60x18__ExpInputTooBig(uint256 x);

/// @notice Emitted when the input is greater than 192.
error PRBMathUD60x18__Exp2InputTooBig(uint256 x);

/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.
error PRBMathUD60x18__FromUintOverflow(uint256 x);

/// @notice Emitted when multiplying the inputs overflows UD60x18.
error PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);

/// @notice Emitted when the input is less than 1.
error PRBMathUD60x18__LogInputTooSmall(uint256 x);

/// @notice Emitted when the calculating the square root overflows UD60x18.
error PRBMathUD60x18__SqrtOverflow(uint256 x);

/// @notice Emitted when subtraction underflows UD60x18.
error PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);

/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library
/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point
/// representation. When it does not, it is explicitly mentioned in the NatSpec documentation.
library PRBMath {
    /// STRUCTS ///

    struct SD59x18 {
        int256 value;
    }

    struct UD60x18 {
        uint256 value;
    }

    /// STORAGE ///

    /// @dev How many trailing decimals can be represented.
    uint256 internal constant SCALE = 1e18;

    /// @dev Largest power of two divisor of SCALE.
    uint256 internal constant SCALE_LPOTD = 262144;

    /// @dev SCALE inverted mod 2^256.
    uint256 internal constant SCALE_INVERSE =
        78156646155174841979727994598816262306175212592076161876661_508869554232690281;

    /// FUNCTIONS ///

    /// @notice Calculates the binary exponent of x using the binary fraction method.
    /// @dev Has to use 192.64-bit fixed-point numbers.
    /// See https://ethereum.stackexchange.com/a/96594/24693.
    /// @param x The exponent as an unsigned 192.64-bit fixed-point number.
    /// @return result The result as an unsigned 60.18-decimal fixed-point number.
    function exp2(uint256 x) internal pure returns (uint256 result) {
        unchecked {
            // Start from 0.5 in the 192.64-bit fixed-point format.
            result = 0x800000000000000000000000000000000000000000000000;

            // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows
            // because the initial result is 2^191 and all magic factors are less than 2^65.
            if (x & 0x8000000000000000 > 0) {
                result = (result * 0x16A09E667F3BCC909) >> 64;
            }
            if (x & 0x4000000000000000 > 0) {
                result = (result * 0x1306FE0A31B7152DF) >> 64;
            }
            if (x & 0x2000000000000000 > 0) {
                result = (result * 0x1172B83C7D517ADCE) >> 64;
            }
            if (x & 0x1000000000000000 > 0) {
                result = (result * 0x10B5586CF9890F62A) >> 64;
            }
            if (x & 0x800000000000000 > 0) {
                result = (result * 0x1059B0D31585743AE) >> 64;
            }
            if (x & 0x400000000000000 > 0) {
                result = (result * 0x102C9A3E778060EE7) >> 64;
            }
            if (x & 0x200000000000000 > 0) {
                result = (result * 0x10163DA9FB33356D8) >> 64;
            }
            if (x & 0x100000000000000 > 0) {
                result = (result * 0x100B1AFA5ABCBED61) >> 64;
            }
            if (x & 0x80000000000000 > 0) {
                result = (result * 0x10058C86DA1C09EA2) >> 64;
            }
            if (x & 0x40000000000000 > 0) {
                result = (result * 0x1002C605E2E8CEC50) >> 64;
            }
            if (x & 0x20000000000000 > 0) {
                result = (result * 0x100162F3904051FA1) >> 64;
            }
            if (x & 0x10000000000000 > 0) {
                result = (result * 0x1000B175EFFDC76BA) >> 64;
            }
            if (x & 0x8000000000000 > 0) {
                result = (result * 0x100058BA01FB9F96D) >> 64;
            }
            if (x & 0x4000000000000 > 0) {
                result = (result * 0x10002C5CC37DA9492) >> 64;
            }
            if (x & 0x2000000000000 > 0) {
                result = (result * 0x1000162E525EE0547) >> 64;
            }
            if (x & 0x1000000000000 > 0) {
                result = (result * 0x10000B17255775C04) >> 64;
            }
            if (x & 0x800000000000 > 0) {
                result = (result * 0x1000058B91B5BC9AE) >> 64;
            }
            if (x & 0x400000000000 > 0) {
                result = (result * 0x100002C5C89D5EC6D) >> 64;
            }
            if (x & 0x200000000000 > 0) {
                result = (result * 0x10000162E43F4F831) >> 64;
            }
            if (x & 0x100000000000 > 0) {
                result = (result * 0x100000B1721BCFC9A) >> 64;
            }
            if (x & 0x80000000000 > 0) {
                result = (result * 0x10000058B90CF1E6E) >> 64;
            }
            if (x & 0x40000000000 > 0) {
                result = (result * 0x1000002C5C863B73F) >> 64;
            }
            if (x & 0x20000000000 > 0) {
                result = (result * 0x100000162E430E5A2) >> 64;
            }
            if (x & 0x10000000000 > 0) {
                result = (result * 0x1000000B172183551) >> 64;
            }
            if (x & 0x8000000000 > 0) {
                result = (result * 0x100000058B90C0B49) >> 64;
            }
            if (x & 0x4000000000 > 0) {
                result = (result * 0x10000002C5C8601CC) >> 64;
            }
            if (x & 0x2000000000 > 0) {
                result = (result * 0x1000000162E42FFF0) >> 64;
            }
            if (x & 0x1000000000 > 0) {
                result = (result * 0x10000000B17217FBB) >> 64;
            }
            if (x & 0x800000000 > 0) {
                result = (result * 0x1000000058B90BFCE) >> 64;
            }
            if (x & 0x400000000 > 0) {
                result = (result * 0x100000002C5C85FE3) >> 64;
            }
            if (x & 0x200000000 > 0) {
                result = (result * 0x10000000162E42FF1) >> 64;
            }
            if (x & 0x100000000 > 0) {
                result = (result * 0x100000000B17217F8) >> 64;
            }
            if (x & 0x80000000 > 0) {
                result = (result * 0x10000000058B90BFC) >> 64;
            }
            if (x & 0x40000000 > 0) {
                result = (result * 0x1000000002C5C85FE) >> 64;
            }
            if (x & 0x20000000 > 0) {
                result = (result * 0x100000000162E42FF) >> 64;
            }
            if (x & 0x10000000 > 0) {
                result = (result * 0x1000000000B17217F) >> 64;
            }
            if (x & 0x8000000 > 0) {
                result = (result * 0x100000000058B90C0) >> 64;
            }
            if (x & 0x4000000 > 0) {
                result = (result * 0x10000000002C5C860) >> 64;
            }
            if (x & 0x2000000 > 0) {
                result = (result * 0x1000000000162E430) >> 64;
            }
            if (x & 0x1000000 > 0) {
                result = (result * 0x10000000000B17218) >> 64;
            }
            if (x & 0x800000 > 0) {
                result = (result * 0x1000000000058B90C) >> 64;
            }
            if (x & 0x400000 > 0) {
                result = (result * 0x100000000002C5C86) >> 64;
            }
            if (x & 0x200000 > 0) {
                result = (result * 0x10000000000162E43) >> 64;
            }
            if (x & 0x100000 > 0) {
                result = (result * 0x100000000000B1721) >> 64;
            }
            if (x & 0x80000 > 0) {
                result = (result * 0x10000000000058B91) >> 64;
            }
            if (x & 0x40000 > 0) {
                result = (result * 0x1000000000002C5C8) >> 64;
            }
            if (x & 0x20000 > 0) {
                result = (result * 0x100000000000162E4) >> 64;
            }
            if (x & 0x10000 > 0) {
                result = (result * 0x1000000000000B172) >> 64;
            }
            if (x & 0x8000 > 0) {
                result = (result * 0x100000000000058B9) >> 64;
            }
            if (x & 0x4000 > 0) {
                result = (result * 0x10000000000002C5D) >> 64;
            }
            if (x & 0x2000 > 0) {
                result = (result * 0x1000000000000162E) >> 64;
            }
            if (x & 0x1000 > 0) {
                result = (result * 0x10000000000000B17) >> 64;
            }
            if (x & 0x800 > 0) {
                result = (result * 0x1000000000000058C) >> 64;
            }
            if (x & 0x400 > 0) {
                result = (result * 0x100000000000002C6) >> 64;
            }
            if (x & 0x200 > 0) {
                result = (result * 0x10000000000000163) >> 64;
            }
            if (x & 0x100 > 0) {
                result = (result * 0x100000000000000B1) >> 64;
            }
            if (x & 0x80 > 0) {
                result = (result * 0x10000000000000059) >> 64;
            }
            if (x & 0x40 > 0) {
                result = (result * 0x1000000000000002C) >> 64;
            }
            if (x & 0x20 > 0) {
                result = (result * 0x10000000000000016) >> 64;
            }
            if (x & 0x10 > 0) {
                result = (result * 0x1000000000000000B) >> 64;
            }
            if (x & 0x8 > 0) {
                result = (result * 0x10000000000000006) >> 64;
            }
            if (x & 0x4 > 0) {
                result = (result * 0x10000000000000003) >> 64;
            }
            if (x & 0x2 > 0) {
                result = (result * 0x10000000000000001) >> 64;
            }
            if (x & 0x1 > 0) {
                result = (result * 0x10000000000000001) >> 64;
            }

            // We're doing two things at the same time:
            //
            //   1. Multiply the result by 2^n + 1, where "2^n" is the integer part and the one is added to account for
            //      the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191
            //      rather than 192.
            //   2. Convert the result to the unsigned 60.18-decimal fixed-point format.
            //
            // This works because 2^(191-ip) = 2^ip / 2^191, where "ip" is the integer part "2^n".
            result *= SCALE;
            result >>= (191 - (x >> 64));
        }
    }

    /// @notice Finds the zero-based index of the first one in the binary representation of x.
    /// @dev See the note on msb in the "Find First Set" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set
    /// @param x The uint256 number for which to find the index of the most significant bit.
    /// @return msb The index of the most significant bit as an uint256.
    function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {
        if (x >= 2**128) {
            x >>= 128;
            msb += 128;
        }
        if (x >= 2**64) {
            x >>= 64;
            msb += 64;
        }
        if (x >= 2**32) {
            x >>= 32;
            msb += 32;
        }
        if (x >= 2**16) {
            x >>= 16;
            msb += 16;
        }
        if (x >= 2**8) {
            x >>= 8;
            msb += 8;
        }
        if (x >= 2**4) {
            x >>= 4;
            msb += 4;
        }
        if (x >= 2**2) {
            x >>= 2;
            msb += 2;
        }
        if (x >= 2**1) {
            // No need to shift x any more.
            msb += 1;
        }
    }

    /// @notice Calculates floor(x*y÷denominator) with full precision.
    ///
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.
    ///
    /// Requirements:
    /// - The denominator cannot be zero.
    /// - The result must fit within uint256.
    ///
    /// Caveats:
    /// - This function does not work with fixed-point numbers.
    ///
    /// @param x The multiplicand as an uint256.
    /// @param y The multiplier as an uint256.
    /// @param denominator The divisor as an uint256.
    /// @return result The result as an uint256.
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
        // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
        // variables such that product = prod1 * 2^256 + prod0.
        uint256 prod0; // Least significant 256 bits of the product
        uint256 prod1; // Most significant 256 bits of the product
        assembly {
            let mm := mulmod(x, y, not(0))
            prod0 := mul(x, y)
            prod1 := sub(sub(mm, prod0), lt(mm, prod0))
        }

        // Handle non-overflow cases, 256 by 256 division.
        if (prod1 == 0) {
            unchecked {
                result = prod0 / denominator;
            }
            return result;
        }

        // Make sure the result is less than 2^256. Also prevents denominator == 0.
        if (prod1 >= denominator) {
            revert PRBMath__MulDivOverflow(prod1, denominator);
        }

        ///////////////////////////////////////////////
        // 512 by 256 division.
        ///////////////////////////////////////////////

        // Make division exact by subtracting the remainder from [prod1 prod0].
        uint256 remainder;
        assembly {
            // Compute remainder using mulmod.
            remainder := mulmod(x, y, denominator)

            // Subtract 256 bit number from 512 bit number.
            prod1 := sub(prod1, gt(remainder, prod0))
            prod0 := sub(prod0, remainder)
        }

        // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
        // See https://cs.stackexchange.com/q/138556/92363.
        unchecked {
            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 lpotdod = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by lpotdod.
                denominator := div(denominator, lpotdod)

                // Divide [prod1 prod0] by lpotdod.
                prod0 := div(prod0, lpotdod)

                // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one.
                lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * lpotdod;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /// @notice Calculates floor(x*y÷1e18) with full precision.
    ///
    /// @dev Variant of "mulDiv" with constant folding, i.e. in which the denominator is always 1e18. Before returning the
    /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of
    /// being rounded to 1e-18.  See "Listing 6" and text above it at https://accu.org/index.php/journals/1717.
    ///
    /// Requirements:
    /// - The result must fit within uint256.
    ///
    /// Caveats:
    /// - The body is purposely left uncommented; see the NatSpec comments in "PRBMath.mulDiv" to understand how this works.
    /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:
    ///     1. x * y = type(uint256).max * SCALE
    ///     2. (x * y) % SCALE >= SCALE / 2
    ///
    /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.
    /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.
    /// @return result The result as an unsigned 60.18-decimal fixed-point number.
    function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {
        uint256 prod0;
        uint256 prod1;
        assembly {
            let mm := mulmod(x, y, not(0))
            prod0 := mul(x, y)
            prod1 := sub(sub(mm, prod0), lt(mm, prod0))
        }

        if (prod1 >= SCALE) {
            revert PRBMath__MulDivFixedPointOverflow(prod1);
        }

        uint256 remainder;
        uint256 roundUpUnit;
        assembly {
            remainder := mulmod(x, y, SCALE)
            roundUpUnit := gt(remainder, 499999999999999999)
        }

        if (prod1 == 0) {
            unchecked {
                result = (prod0 / SCALE) + roundUpUnit;
                return result;
            }
        }

        assembly {
            result := add(
                mul(
                    or(
                        div(sub(prod0, remainder), SCALE_LPOTD),
                        mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))
                    ),
                    SCALE_INVERSE
                ),
                roundUpUnit
            )
        }
    }

    /// @notice Calculates floor(x*y÷denominator) with full precision.
    ///
    /// @dev An extension of "mulDiv" for signed numbers. Works by computing the signs and the absolute values separately.
    ///
    /// Requirements:
    /// - None of the inputs can be type(int256).min.
    /// - The result must fit within int256.
    ///
    /// @param x The multiplicand as an int256.
    /// @param y The multiplier as an int256.
    /// @param denominator The divisor as an int256.
    /// @return result The result as an int256.
    function mulDivSigned(
        int256 x,
        int256 y,
        int256 denominator
    ) internal pure returns (int256 result) {
        if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {
            revert PRBMath__MulDivSignedInputTooSmall();
        }

        // Get hold of the absolute values of x, y and the denominator.
        uint256 ax;
        uint256 ay;
        uint256 ad;
        unchecked {
            ax = x < 0 ? uint256(-x) : uint256(x);
            ay = y < 0 ? uint256(-y) : uint256(y);
            ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);
        }

        // Compute the absolute value of (x*y)÷denominator. The result must fit within int256.
        uint256 rAbs = mulDiv(ax, ay, ad);
        if (rAbs > uint256(type(int256).max)) {
            revert PRBMath__MulDivSignedOverflow(rAbs);
        }

        // Get the signs of x, y and the denominator.
        uint256 sx;
        uint256 sy;
        uint256 sd;
        assembly {
            sx := sgt(x, sub(0, 1))
            sy := sgt(y, sub(0, 1))
            sd := sgt(denominator, sub(0, 1))
        }

        // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.
        // If yes, the result should be negative.
        result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);
    }

    /// @notice Calculates the square root of x, rounding down.
    /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
    ///
    /// Caveats:
    /// - This function does not work with fixed-point numbers.
    ///
    /// @param x The uint256 number for which to calculate the square root.
    /// @return result The result as an uint256.
    function sqrt(uint256 x) internal pure returns (uint256 result) {
        if (x == 0) {
            return 0;
        }

        // Set the initial guess to the least power of two that is greater than or equal to sqrt(x).
        uint256 xAux = uint256(x);
        result = 1;
        if (xAux >= 0x100000000000000000000000000000000) {
            xAux >>= 128;
            result <<= 64;
        }
        if (xAux >= 0x10000000000000000) {
            xAux >>= 64;
            result <<= 32;
        }
        if (xAux >= 0x100000000) {
            xAux >>= 32;
            result <<= 16;
        }
        if (xAux >= 0x10000) {
            xAux >>= 16;
            result <<= 8;
        }
        if (xAux >= 0x100) {
            xAux >>= 8;
            result <<= 4;
        }
        if (xAux >= 0x10) {
            xAux >>= 4;
            result <<= 2;
        }
        if (xAux >= 0x8) {
            result <<= 1;
        }

        // The operations can never overflow because the result is max 2^127 when it enters this block.
        unchecked {
            result = (result + x / result) >> 1;
            result = (result + x / result) >> 1;
            result = (result + x / result) >> 1;
            result = (result + x / result) >> 1;
            result = (result + x / result) >> 1;
            result = (result + x / result) >> 1;
            result = (result + x / result) >> 1; // Seven iterations should be enough
            uint256 roundedDownResult = x / result;
            return result >= roundedDownResult ? roundedDownResult : result;
        }
    }
}

File 40 of 41 : PRBMathSD59x18.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.4;

import "./PRBMath.sol";

/// @title PRBMathSD59x18
/// @author Paul Razvan Berg
/// @notice Smart contract library for advanced fixed-point math that works with int256 numbers considered to have 18
/// trailing decimals. We call this number representation signed 59.18-decimal fixed-point, since the numbers can have
/// a sign and there can be up to 59 digits in the integer part and up to 18 decimals in the fractional part. The numbers
/// are bound by the minimum and the maximum values permitted by the Solidity type int256.
library PRBMathSD59x18 {
    /// @dev log2(e) as a signed 59.18-decimal fixed-point number.
    int256 internal constant LOG2_E = 1_442695040888963407;

    /// @dev Half the SCALE number.
    int256 internal constant HALF_SCALE = 5e17;

    /// @dev The maximum value a signed 59.18-decimal fixed-point number can have.
    int256 internal constant MAX_SD59x18 =
        57896044618658097711785492504343953926634992332820282019728_792003956564819967;

    /// @dev The maximum whole value a signed 59.18-decimal fixed-point number can have.
    int256 internal constant MAX_WHOLE_SD59x18 =
        57896044618658097711785492504343953926634992332820282019728_000000000000000000;

    /// @dev The minimum value a signed 59.18-decimal fixed-point number can have.
    int256 internal constant MIN_SD59x18 =
        -57896044618658097711785492504343953926634992332820282019728_792003956564819968;

    /// @dev The minimum whole value a signed 59.18-decimal fixed-point number can have.
    int256 internal constant MIN_WHOLE_SD59x18 =
        -57896044618658097711785492504343953926634992332820282019728_000000000000000000;

    /// @dev How many trailing decimals can be represented.
    int256 internal constant SCALE = 1e18;

    /// INTERNAL FUNCTIONS ///

    /// @notice Calculate the absolute value of x.
    ///
    /// @dev Requirements:
    /// - x must be greater than MIN_SD59x18.
    ///
    /// @param x The number to calculate the absolute value for.
    /// @param result The absolute value of x.
    function abs(int256 x) internal pure returns (int256 result) {
        unchecked {
            if (x == MIN_SD59x18) {
                revert PRBMathSD59x18__AbsInputTooSmall();
            }
            result = x < 0 ? -x : x;
        }
    }

    /// @notice Calculates the arithmetic average of x and y, rounding down.
    /// @param x The first operand as a signed 59.18-decimal fixed-point number.
    /// @param y The second operand as a signed 59.18-decimal fixed-point number.
    /// @return result The arithmetic average as a signed 59.18-decimal fixed-point number.
    function avg(int256 x, int256 y) internal pure returns (int256 result) {
        // The operations can never overflow.
        unchecked {
            int256 sum = (x >> 1) + (y >> 1);
            if (sum < 0) {
                // If at least one of x and y is odd, we add 1 to the result. This is because shifting negative numbers to the
                // right rounds down to infinity.
                assembly {
                    result := add(sum, and(or(x, y), 1))
                }
            } else {
                // If both x and y are odd, we add 1 to the result. This is because if both numbers are odd, the 0.5
                // remainder gets truncated twice.
                result = sum + (x & y & 1);
            }
        }
    }

    /// @notice Yields the least greatest signed 59.18 decimal fixed-point number greater than or equal to x.
    ///
    /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.
    /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
    ///
    /// Requirements:
    /// - x must be less than or equal to MAX_WHOLE_SD59x18.
    ///
    /// @param x The signed 59.18-decimal fixed-point number to ceil.
    /// @param result The least integer greater than or equal to x, as a signed 58.18-decimal fixed-point number.
    function ceil(int256 x) internal pure returns (int256 result) {
        if (x > MAX_WHOLE_SD59x18) {
            revert PRBMathSD59x18__CeilOverflow(x);
        }
        unchecked {
            int256 remainder = x % SCALE;
            if (remainder == 0) {
                result = x;
            } else {
                // Solidity uses C fmod style, which returns a modulus with the same sign as x.
                result = x - remainder;
                if (x > 0) {
                    result += SCALE;
                }
            }
        }
    }

    /// @notice Divides two signed 59.18-decimal fixed-point numbers, returning a new signed 59.18-decimal fixed-point number.
    ///
    /// @dev Variant of "mulDiv" that works with signed numbers. Works by computing the signs and the absolute values separately.
    ///
    /// Requirements:
    /// - All from "PRBMath.mulDiv".
    /// - None of the inputs can be MIN_SD59x18.
    /// - The denominator cannot be zero.
    /// - The result must fit within int256.
    ///
    /// Caveats:
    /// - All from "PRBMath.mulDiv".
    ///
    /// @param x The numerator as a signed 59.18-decimal fixed-point number.
    /// @param y The denominator as a signed 59.18-decimal fixed-point number.
    /// @param result The quotient as a signed 59.18-decimal fixed-point number.
    function div(int256 x, int256 y) internal pure returns (int256 result) {
        if (x == MIN_SD59x18 || y == MIN_SD59x18) {
            revert PRBMathSD59x18__DivInputTooSmall();
        }

        // Get hold of the absolute values of x and y.
        uint256 ax;
        uint256 ay;
        unchecked {
            ax = x < 0 ? uint256(-x) : uint256(x);
            ay = y < 0 ? uint256(-y) : uint256(y);
        }

        // Compute the absolute value of (x*SCALE)÷y. The result must fit within int256.
        uint256 rAbs = PRBMath.mulDiv(ax, uint256(SCALE), ay);
        if (rAbs > uint256(MAX_SD59x18)) {
            revert PRBMathSD59x18__DivOverflow(rAbs);
        }

        // Get the signs of x and y.
        uint256 sx;
        uint256 sy;
        assembly {
            sx := sgt(x, sub(0, 1))
            sy := sgt(y, sub(0, 1))
        }

        // XOR over sx and sy. This is basically checking whether the inputs have the same sign. If yes, the result
        // should be positive. Otherwise, it should be negative.
        result = sx ^ sy == 1 ? -int256(rAbs) : int256(rAbs);
    }

    /// @notice Returns Euler's number as a signed 59.18-decimal fixed-point number.
    /// @dev See https://en.wikipedia.org/wiki/E_(mathematical_constant).
    function e() internal pure returns (int256 result) {
        result = 2_718281828459045235;
    }

    /// @notice Calculates the natural exponent of x.
    ///
    /// @dev Based on the insight that e^x = 2^(x * log2(e)).
    ///
    /// Requirements:
    /// - All from "log2".
    /// - x must be less than 133.084258667509499441.
    ///
    /// Caveats:
    /// - All from "exp2".
    /// - For any x less than -41.446531673892822322, the result is zero.
    ///
    /// @param x The exponent as a signed 59.18-decimal fixed-point number.
    /// @return result The result as a signed 59.18-decimal fixed-point number.
    function exp(int256 x) internal pure returns (int256 result) {
        // Without this check, the value passed to "exp2" would be less than -59.794705707972522261.
        if (x < -41_446531673892822322) {
            return 0;
        }

        // Without this check, the value passed to "exp2" would be greater than 192.
        if (x >= 133_084258667509499441) {
            revert PRBMathSD59x18__ExpInputTooBig(x);
        }

        // Do the fixed-point multiplication inline to save gas.
        unchecked {
            int256 doubleScaleProduct = x * LOG2_E;
            result = exp2((doubleScaleProduct + HALF_SCALE) / SCALE);
        }
    }

    /// @notice Calculates the binary exponent of x using the binary fraction method.
    ///
    /// @dev See https://ethereum.stackexchange.com/q/79903/24693.
    ///
    /// Requirements:
    /// - x must be 192 or less.
    /// - The result must fit within MAX_SD59x18.
    ///
    /// Caveats:
    /// - For any x less than -59.794705707972522261, the result is zero.
    ///
    /// @param x The exponent as a signed 59.18-decimal fixed-point number.
    /// @return result The result as a signed 59.18-decimal fixed-point number.
    function exp2(int256 x) internal pure returns (int256 result) {
        // This works because 2^(-x) = 1/2^x.
        if (x < 0) {
            // 2^59.794705707972522262 is the maximum number whose inverse does not truncate down to zero.
            if (x < -59_794705707972522261) {
                return 0;
            }

            // Do the fixed-point inversion inline to save gas. The numerator is SCALE * SCALE.
            unchecked {
                result = 1e36 / exp2(-x);
            }
        } else {
            // 2^192 doesn't fit within the 192.64-bit format used internally in this function.
            if (x >= 192e18) {
                revert PRBMathSD59x18__Exp2InputTooBig(x);
            }

            unchecked {
                // Convert x to the 192.64-bit fixed-point format.
                uint256 x192x64 = (uint256(x) << 64) / uint256(SCALE);

                // Safe to convert the result to int256 directly because the maximum input allowed is 192.
                result = int256(PRBMath.exp2(x192x64));
            }
        }
    }

    /// @notice Yields the greatest signed 59.18 decimal fixed-point number less than or equal to x.
    ///
    /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.
    /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
    ///
    /// Requirements:
    /// - x must be greater than or equal to MIN_WHOLE_SD59x18.
    ///
    /// @param x The signed 59.18-decimal fixed-point number to floor.
    /// @param result The greatest integer less than or equal to x, as a signed 58.18-decimal fixed-point number.
    function floor(int256 x) internal pure returns (int256 result) {
        if (x < MIN_WHOLE_SD59x18) {
            revert PRBMathSD59x18__FloorUnderflow(x);
        }
        unchecked {
            int256 remainder = x % SCALE;
            if (remainder == 0) {
                result = x;
            } else {
                // Solidity uses C fmod style, which returns a modulus with the same sign as x.
                result = x - remainder;
                if (x < 0) {
                    result -= SCALE;
                }
            }
        }
    }

    /// @notice Yields the excess beyond the floor of x for positive numbers and the part of the number to the right
    /// of the radix point for negative numbers.
    /// @dev Based on the odd function definition. https://en.wikipedia.org/wiki/Fractional_part
    /// @param x The signed 59.18-decimal fixed-point number to get the fractional part of.
    /// @param result The fractional part of x as a signed 59.18-decimal fixed-point number.
    function frac(int256 x) internal pure returns (int256 result) {
        unchecked {
            result = x % SCALE;
        }
    }

    /// @notice Converts a number from basic integer form to signed 59.18-decimal fixed-point representation.
    ///
    /// @dev Requirements:
    /// - x must be greater than or equal to MIN_SD59x18 divided by SCALE.
    /// - x must be less than or equal to MAX_SD59x18 divided by SCALE.
    ///
    /// @param x The basic integer to convert.
    /// @param result The same number in signed 59.18-decimal fixed-point representation.
    function fromInt(int256 x) internal pure returns (int256 result) {
        unchecked {
            if (x < MIN_SD59x18 / SCALE) {
                revert PRBMathSD59x18__FromIntUnderflow(x);
            }
            if (x > MAX_SD59x18 / SCALE) {
                revert PRBMathSD59x18__FromIntOverflow(x);
            }
            result = x * SCALE;
        }
    }

    /// @notice Calculates geometric mean of x and y, i.e. sqrt(x * y), rounding down.
    ///
    /// @dev Requirements:
    /// - x * y must fit within MAX_SD59x18, lest it overflows.
    /// - x * y cannot be negative.
    ///
    /// @param x The first operand as a signed 59.18-decimal fixed-point number.
    /// @param y The second operand as a signed 59.18-decimal fixed-point number.
    /// @return result The result as a signed 59.18-decimal fixed-point number.
    function gm(int256 x, int256 y) internal pure returns (int256 result) {
        if (x == 0) {
            return 0;
        }

        unchecked {
            // Checking for overflow this way is faster than letting Solidity do it.
            int256 xy = x * y;
            if (xy / x != y) {
                revert PRBMathSD59x18__GmOverflow(x, y);
            }

            // The product cannot be negative.
            if (xy < 0) {
                revert PRBMathSD59x18__GmNegativeProduct(x, y);
            }

            // We don't need to multiply by the SCALE here because the x*y product had already picked up a factor of SCALE
            // during multiplication. See the comments within the "sqrt" function.
            result = int256(PRBMath.sqrt(uint256(xy)));
        }
    }

    /// @notice Calculates 1 / x, rounding toward zero.
    ///
    /// @dev Requirements:
    /// - x cannot be zero.
    ///
    /// @param x The signed 59.18-decimal fixed-point number for which to calculate the inverse.
    /// @return result The inverse as a signed 59.18-decimal fixed-point number.
    function inv(int256 x) internal pure returns (int256 result) {
        unchecked {
            // 1e36 is SCALE * SCALE.
            result = 1e36 / x;
        }
    }

    /// @notice Calculates the natural logarithm of x.
    ///
    /// @dev Based on the insight that ln(x) = log2(x) / log2(e).
    ///
    /// Requirements:
    /// - All from "log2".
    ///
    /// Caveats:
    /// - All from "log2".
    /// - This doesn't return exactly 1 for 2718281828459045235, for that we would need more fine-grained precision.
    ///
    /// @param x The signed 59.18-decimal fixed-point number for which to calculate the natural logarithm.
    /// @return result The natural logarithm as a signed 59.18-decimal fixed-point number.
    function ln(int256 x) internal pure returns (int256 result) {
        // Do the fixed-point multiplication inline to save gas. This is overflow-safe because the maximum value that log2(x)
        // can return is 195205294292027477728.
        unchecked {
            result = (log2(x) * SCALE) / LOG2_E;
        }
    }

    /// @notice Calculates the common logarithm of x.
    ///
    /// @dev First checks if x is an exact power of ten and it stops if yes. If it's not, calculates the common
    /// logarithm based on the insight that log10(x) = log2(x) / log2(10).
    ///
    /// Requirements:
    /// - All from "log2".
    ///
    /// Caveats:
    /// - All from "log2".
    ///
    /// @param x The signed 59.18-decimal fixed-point number for which to calculate the common logarithm.
    /// @return result The common logarithm as a signed 59.18-decimal fixed-point number.
    function log10(int256 x) internal pure returns (int256 result) {
        if (x <= 0) {
            revert PRBMathSD59x18__LogInputTooSmall(x);
        }

        // Note that the "mul" in this block is the assembly mul operation, not the "mul" function defined in this contract.
        // prettier-ignore
        assembly {
            switch x
            case 1 { result := mul(SCALE, sub(0, 18)) }
            case 10 { result := mul(SCALE, sub(1, 18)) }
            case 100 { result := mul(SCALE, sub(2, 18)) }
            case 1000 { result := mul(SCALE, sub(3, 18)) }
            case 10000 { result := mul(SCALE, sub(4, 18)) }
            case 100000 { result := mul(SCALE, sub(5, 18)) }
            case 1000000 { result := mul(SCALE, sub(6, 18)) }
            case 10000000 { result := mul(SCALE, sub(7, 18)) }
            case 100000000 { result := mul(SCALE, sub(8, 18)) }
            case 1000000000 { result := mul(SCALE, sub(9, 18)) }
            case 10000000000 { result := mul(SCALE, sub(10, 18)) }
            case 100000000000 { result := mul(SCALE, sub(11, 18)) }
            case 1000000000000 { result := mul(SCALE, sub(12, 18)) }
            case 10000000000000 { result := mul(SCALE, sub(13, 18)) }
            case 100000000000000 { result := mul(SCALE, sub(14, 18)) }
            case 1000000000000000 { result := mul(SCALE, sub(15, 18)) }
            case 10000000000000000 { result := mul(SCALE, sub(16, 18)) }
            case 100000000000000000 { result := mul(SCALE, sub(17, 18)) }
            case 1000000000000000000 { result := 0 }
            case 10000000000000000000 { result := SCALE }
            case 100000000000000000000 { result := mul(SCALE, 2) }
            case 1000000000000000000000 { result := mul(SCALE, 3) }
            case 10000000000000000000000 { result := mul(SCALE, 4) }
            case 100000000000000000000000 { result := mul(SCALE, 5) }
            case 1000000000000000000000000 { result := mul(SCALE, 6) }
            case 10000000000000000000000000 { result := mul(SCALE, 7) }
            case 100000000000000000000000000 { result := mul(SCALE, 8) }
            case 1000000000000000000000000000 { result := mul(SCALE, 9) }
            case 10000000000000000000000000000 { result := mul(SCALE, 10) }
            case 100000000000000000000000000000 { result := mul(SCALE, 11) }
            case 1000000000000000000000000000000 { result := mul(SCALE, 12) }
            case 10000000000000000000000000000000 { result := mul(SCALE, 13) }
            case 100000000000000000000000000000000 { result := mul(SCALE, 14) }
            case 1000000000000000000000000000000000 { result := mul(SCALE, 15) }
            case 10000000000000000000000000000000000 { result := mul(SCALE, 16) }
            case 100000000000000000000000000000000000 { result := mul(SCALE, 17) }
            case 1000000000000000000000000000000000000 { result := mul(SCALE, 18) }
            case 10000000000000000000000000000000000000 { result := mul(SCALE, 19) }
            case 100000000000000000000000000000000000000 { result := mul(SCALE, 20) }
            case 1000000000000000000000000000000000000000 { result := mul(SCALE, 21) }
            case 10000000000000000000000000000000000000000 { result := mul(SCALE, 22) }
            case 100000000000000000000000000000000000000000 { result := mul(SCALE, 23) }
            case 1000000000000000000000000000000000000000000 { result := mul(SCALE, 24) }
            case 10000000000000000000000000000000000000000000 { result := mul(SCALE, 25) }
            case 100000000000000000000000000000000000000000000 { result := mul(SCALE, 26) }
            case 1000000000000000000000000000000000000000000000 { result := mul(SCALE, 27) }
            case 10000000000000000000000000000000000000000000000 { result := mul(SCALE, 28) }
            case 100000000000000000000000000000000000000000000000 { result := mul(SCALE, 29) }
            case 1000000000000000000000000000000000000000000000000 { result := mul(SCALE, 30) }
            case 10000000000000000000000000000000000000000000000000 { result := mul(SCALE, 31) }
            case 100000000000000000000000000000000000000000000000000 { result := mul(SCALE, 32) }
            case 1000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 33) }
            case 10000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 34) }
            case 100000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 35) }
            case 1000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 36) }
            case 10000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 37) }
            case 100000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 38) }
            case 1000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 39) }
            case 10000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 40) }
            case 100000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 41) }
            case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 42) }
            case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 43) }
            case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 44) }
            case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 45) }
            case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 46) }
            case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 47) }
            case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 48) }
            case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 49) }
            case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 50) }
            case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 51) }
            case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 52) }
            case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 53) }
            case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 54) }
            case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 55) }
            case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 56) }
            case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 57) }
            case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 58) }
            default {
                result := MAX_SD59x18
            }
        }

        if (result == MAX_SD59x18) {
            // Do the fixed-point division inline to save gas. The denominator is log2(10).
            unchecked {
                result = (log2(x) * SCALE) / 3_321928094887362347;
            }
        }
    }

    /// @notice Calculates the binary logarithm of x.
    ///
    /// @dev Based on the iterative approximation algorithm.
    /// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation
    ///
    /// Requirements:
    /// - x must be greater than zero.
    ///
    /// Caveats:
    /// - The results are not perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation.
    ///
    /// @param x The signed 59.18-decimal fixed-point number for which to calculate the binary logarithm.
    /// @return result The binary logarithm as a signed 59.18-decimal fixed-point number.
    function log2(int256 x) internal pure returns (int256 result) {
        if (x <= 0) {
            revert PRBMathSD59x18__LogInputTooSmall(x);
        }
        unchecked {
            // This works because log2(x) = -log2(1/x).
            int256 sign;
            if (x >= SCALE) {
                sign = 1;
            } else {
                sign = -1;
                // Do the fixed-point inversion inline to save gas. The numerator is SCALE * SCALE.
                assembly {
                    x := div(1000000000000000000000000000000000000, x)
                }
            }

            // Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n).
            uint256 n = PRBMath.mostSignificantBit(uint256(x / SCALE));

            // The integer part of the logarithm as a signed 59.18-decimal fixed-point number. The operation can't overflow
            // because n is maximum 255, SCALE is 1e18 and sign is either 1 or -1.
            result = int256(n) * SCALE;

            // This is y = x * 2^(-n).
            int256 y = x >> n;

            // If y = 1, the fractional part is zero.
            if (y == SCALE) {
                return result * sign;
            }

            // Calculate the fractional part via the iterative approximation.
            // The "delta >>= 1" part is equivalent to "delta /= 2", but shifting bits is faster.
            for (int256 delta = int256(HALF_SCALE); delta > 0; delta >>= 1) {
                y = (y * y) / SCALE;

                // Is y^2 > 2 and so in the range [2,4)?
                if (y >= 2 * SCALE) {
                    // Add the 2^(-m) factor to the logarithm.
                    result += delta;

                    // Corresponds to z/2 on Wikipedia.
                    y >>= 1;
                }
            }
            result *= sign;
        }
    }

    /// @notice Multiplies two signed 59.18-decimal fixed-point numbers together, returning a new signed 59.18-decimal
    /// fixed-point number.
    ///
    /// @dev Variant of "mulDiv" that works with signed numbers and employs constant folding, i.e. the denominator is
    /// always 1e18.
    ///
    /// Requirements:
    /// - All from "PRBMath.mulDivFixedPoint".
    /// - None of the inputs can be MIN_SD59x18
    /// - The result must fit within MAX_SD59x18.
    ///
    /// Caveats:
    /// - The body is purposely left uncommented; see the NatSpec comments in "PRBMath.mulDiv" to understand how this works.
    ///
    /// @param x The multiplicand as a signed 59.18-decimal fixed-point number.
    /// @param y The multiplier as a signed 59.18-decimal fixed-point number.
    /// @return result The product as a signed 59.18-decimal fixed-point number.
    function mul(int256 x, int256 y) internal pure returns (int256 result) {
        if (x == MIN_SD59x18 || y == MIN_SD59x18) {
            revert PRBMathSD59x18__MulInputTooSmall();
        }

        unchecked {
            uint256 ax;
            uint256 ay;
            ax = x < 0 ? uint256(-x) : uint256(x);
            ay = y < 0 ? uint256(-y) : uint256(y);

            uint256 rAbs = PRBMath.mulDivFixedPoint(ax, ay);
            if (rAbs > uint256(MAX_SD59x18)) {
                revert PRBMathSD59x18__MulOverflow(rAbs);
            }

            uint256 sx;
            uint256 sy;
            assembly {
                sx := sgt(x, sub(0, 1))
                sy := sgt(y, sub(0, 1))
            }
            result = sx ^ sy == 1 ? -int256(rAbs) : int256(rAbs);
        }
    }

    /// @notice Returns PI as a signed 59.18-decimal fixed-point number.
    function pi() internal pure returns (int256 result) {
        result = 3_141592653589793238;
    }

    /// @notice Raises x to the power of y.
    ///
    /// @dev Based on the insight that x^y = 2^(log2(x) * y).
    ///
    /// Requirements:
    /// - All from "exp2", "log2" and "mul".
    /// - z cannot be zero.
    ///
    /// Caveats:
    /// - All from "exp2", "log2" and "mul".
    /// - Assumes 0^0 is 1.
    ///
    /// @param x Number to raise to given power y, as a signed 59.18-decimal fixed-point number.
    /// @param y Exponent to raise x to, as a signed 59.18-decimal fixed-point number.
    /// @return result x raised to power y, as a signed 59.18-decimal fixed-point number.
    function pow(int256 x, int256 y) internal pure returns (int256 result) {
        if (x == 0) {
            result = y == 0 ? SCALE : int256(0);
        } else {
            result = exp2(mul(log2(x), y));
        }
    }

    /// @notice Raises x (signed 59.18-decimal fixed-point number) to the power of y (basic unsigned integer) using the
    /// famous algorithm "exponentiation by squaring".
    ///
    /// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring
    ///
    /// Requirements:
    /// - All from "abs" and "PRBMath.mulDivFixedPoint".
    /// - The result must fit within MAX_SD59x18.
    ///
    /// Caveats:
    /// - All from "PRBMath.mulDivFixedPoint".
    /// - Assumes 0^0 is 1.
    ///
    /// @param x The base as a signed 59.18-decimal fixed-point number.
    /// @param y The exponent as an uint256.
    /// @return result The result as a signed 59.18-decimal fixed-point number.
    function powu(int256 x, uint256 y) internal pure returns (int256 result) {
        uint256 xAbs = uint256(abs(x));

        // Calculate the first iteration of the loop in advance.
        uint256 rAbs = y & 1 > 0 ? xAbs : uint256(SCALE);

        // Equivalent to "for(y /= 2; y > 0; y /= 2)" but faster.
        uint256 yAux = y;
        for (yAux >>= 1; yAux > 0; yAux >>= 1) {
            xAbs = PRBMath.mulDivFixedPoint(xAbs, xAbs);

            // Equivalent to "y % 2 == 1" but faster.
            if (yAux & 1 > 0) {
                rAbs = PRBMath.mulDivFixedPoint(rAbs, xAbs);
            }
        }

        // The result must fit within the 59.18-decimal fixed-point representation.
        if (rAbs > uint256(MAX_SD59x18)) {
            revert PRBMathSD59x18__PowuOverflow(rAbs);
        }

        // Is the base negative and the exponent an odd number?
        bool isNegative = x < 0 && y & 1 == 1;
        result = isNegative ? -int256(rAbs) : int256(rAbs);
    }

    /// @notice Returns 1 as a signed 59.18-decimal fixed-point number.
    function scale() internal pure returns (int256 result) {
        result = SCALE;
    }

    /// @notice Calculates the square root of x, rounding down.
    /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
    ///
    /// Requirements:
    /// - x cannot be negative.
    /// - x must be less than MAX_SD59x18 / SCALE.
    ///
    /// @param x The signed 59.18-decimal fixed-point number for which to calculate the square root.
    /// @return result The result as a signed 59.18-decimal fixed-point .
    function sqrt(int256 x) internal pure returns (int256 result) {
        unchecked {
            if (x < 0) {
                revert PRBMathSD59x18__SqrtNegativeInput(x);
            }
            if (x > MAX_SD59x18 / SCALE) {
                revert PRBMathSD59x18__SqrtOverflow(x);
            }
            // Multiply x by the SCALE to account for the factor of SCALE that is picked up when multiplying two signed
            // 59.18-decimal fixed-point numbers together (in this case, those two numbers are both the square root).
            result = int256(PRBMath.sqrt(uint256(x * SCALE)));
        }
    }

    /// @notice Converts a signed 59.18-decimal fixed-point number to basic integer form, rounding down in the process.
    /// @param x The signed 59.18-decimal fixed-point number to convert.
    /// @return result The same number in basic integer form.
    function toInt(int256 x) internal pure returns (int256 result) {
        unchecked {
            result = x / SCALE;
        }
    }
}

File 41 of 41 : PRBMathUD60x18.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.4;

import "./PRBMath.sol";

/// @title PRBMathUD60x18
/// @author Paul Razvan Berg
/// @notice Smart contract library for advanced fixed-point math that works with uint256 numbers considered to have 18
/// trailing decimals. We call this number representation unsigned 60.18-decimal fixed-point, since there can be up to 60
/// digits in the integer part and up to 18 decimals in the fractional part. The numbers are bound by the minimum and the
/// maximum values permitted by the Solidity type uint256.
library PRBMathUD60x18 {
    /// @dev Half the SCALE number.
    uint256 internal constant HALF_SCALE = 5e17;

    /// @dev log2(e) as an unsigned 60.18-decimal fixed-point number.
    uint256 internal constant LOG2_E = 1_442695040888963407;

    /// @dev The maximum value an unsigned 60.18-decimal fixed-point number can have.
    uint256 internal constant MAX_UD60x18 =
        115792089237316195423570985008687907853269984665640564039457_584007913129639935;

    /// @dev The maximum whole value an unsigned 60.18-decimal fixed-point number can have.
    uint256 internal constant MAX_WHOLE_UD60x18 =
        115792089237316195423570985008687907853269984665640564039457_000000000000000000;

    /// @dev How many trailing decimals can be represented.
    uint256 internal constant SCALE = 1e18;

    /// @notice Calculates the arithmetic average of x and y, rounding down.
    /// @param x The first operand as an unsigned 60.18-decimal fixed-point number.
    /// @param y The second operand as an unsigned 60.18-decimal fixed-point number.
    /// @return result The arithmetic average as an unsigned 60.18-decimal fixed-point number.
    function avg(uint256 x, uint256 y) internal pure returns (uint256 result) {
        // The operations can never overflow.
        unchecked {
            // The last operand checks if both x and y are odd and if that is the case, we add 1 to the result. We need
            // to do this because if both numbers are odd, the 0.5 remainder gets truncated twice.
            result = (x >> 1) + (y >> 1) + (x & y & 1);
        }
    }

    /// @notice Yields the least unsigned 60.18 decimal fixed-point number greater than or equal to x.
    ///
    /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.
    /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
    ///
    /// Requirements:
    /// - x must be less than or equal to MAX_WHOLE_UD60x18.
    ///
    /// @param x The unsigned 60.18-decimal fixed-point number to ceil.
    /// @param result The least integer greater than or equal to x, as an unsigned 60.18-decimal fixed-point number.
    function ceil(uint256 x) internal pure returns (uint256 result) {
        if (x > MAX_WHOLE_UD60x18) {
            revert PRBMathUD60x18__CeilOverflow(x);
        }
        assembly {
            // Equivalent to "x % SCALE" but faster.
            let remainder := mod(x, SCALE)

            // Equivalent to "SCALE - remainder" but faster.
            let delta := sub(SCALE, remainder)

            // Equivalent to "x + delta * (remainder > 0 ? 1 : 0)" but faster.
            result := add(x, mul(delta, gt(remainder, 0)))
        }
    }

    /// @notice Divides two unsigned 60.18-decimal fixed-point numbers, returning a new unsigned 60.18-decimal fixed-point number.
    ///
    /// @dev Uses mulDiv to enable overflow-safe multiplication and division.
    ///
    /// Requirements:
    /// - The denominator cannot be zero.
    ///
    /// @param x The numerator as an unsigned 60.18-decimal fixed-point number.
    /// @param y The denominator as an unsigned 60.18-decimal fixed-point number.
    /// @param result The quotient as an unsigned 60.18-decimal fixed-point number.
    function div(uint256 x, uint256 y) internal pure returns (uint256 result) {
        result = PRBMath.mulDiv(x, SCALE, y);
    }

    /// @notice Returns Euler's number as an unsigned 60.18-decimal fixed-point number.
    /// @dev See https://en.wikipedia.org/wiki/E_(mathematical_constant).
    function e() internal pure returns (uint256 result) {
        result = 2_718281828459045235;
    }

    /// @notice Calculates the natural exponent of x.
    ///
    /// @dev Based on the insight that e^x = 2^(x * log2(e)).
    ///
    /// Requirements:
    /// - All from "log2".
    /// - x must be less than 133.084258667509499441.
    ///
    /// @param x The exponent as an unsigned 60.18-decimal fixed-point number.
    /// @return result The result as an unsigned 60.18-decimal fixed-point number.
    function exp(uint256 x) internal pure returns (uint256 result) {
        // Without this check, the value passed to "exp2" would be greater than 192.
        if (x >= 133_084258667509499441) {
            revert PRBMathUD60x18__ExpInputTooBig(x);
        }

        // Do the fixed-point multiplication inline to save gas.
        unchecked {
            uint256 doubleScaleProduct = x * LOG2_E;
            result = exp2((doubleScaleProduct + HALF_SCALE) / SCALE);
        }
    }

    /// @notice Calculates the binary exponent of x using the binary fraction method.
    ///
    /// @dev See https://ethereum.stackexchange.com/q/79903/24693.
    ///
    /// Requirements:
    /// - x must be 192 or less.
    /// - The result must fit within MAX_UD60x18.
    ///
    /// @param x The exponent as an unsigned 60.18-decimal fixed-point number.
    /// @return result The result as an unsigned 60.18-decimal fixed-point number.
    function exp2(uint256 x) internal pure returns (uint256 result) {
        // 2^192 doesn't fit within the 192.64-bit format used internally in this function.
        if (x >= 192e18) {
            revert PRBMathUD60x18__Exp2InputTooBig(x);
        }

        unchecked {
            // Convert x to the 192.64-bit fixed-point format.
            uint256 x192x64 = (x << 64) / SCALE;

            // Pass x to the PRBMath.exp2 function, which uses the 192.64-bit fixed-point number representation.
            result = PRBMath.exp2(x192x64);
        }
    }

    /// @notice Yields the greatest unsigned 60.18 decimal fixed-point number less than or equal to x.
    /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.
    /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
    /// @param x The unsigned 60.18-decimal fixed-point number to floor.
    /// @param result The greatest integer less than or equal to x, as an unsigned 60.18-decimal fixed-point number.
    function floor(uint256 x) internal pure returns (uint256 result) {
        assembly {
            // Equivalent to "x % SCALE" but faster.
            let remainder := mod(x, SCALE)

            // Equivalent to "x - remainder * (remainder > 0 ? 1 : 0)" but faster.
            result := sub(x, mul(remainder, gt(remainder, 0)))
        }
    }

    /// @notice Yields the excess beyond the floor of x.
    /// @dev Based on the odd function definition https://en.wikipedia.org/wiki/Fractional_part.
    /// @param x The unsigned 60.18-decimal fixed-point number to get the fractional part of.
    /// @param result The fractional part of x as an unsigned 60.18-decimal fixed-point number.
    function frac(uint256 x) internal pure returns (uint256 result) {
        assembly {
            result := mod(x, SCALE)
        }
    }

    /// @notice Converts a number from basic integer form to unsigned 60.18-decimal fixed-point representation.
    ///
    /// @dev Requirements:
    /// - x must be less than or equal to MAX_UD60x18 divided by SCALE.
    ///
    /// @param x The basic integer to convert.
    /// @param result The same number in unsigned 60.18-decimal fixed-point representation.
    function fromUint(uint256 x) internal pure returns (uint256 result) {
        unchecked {
            if (x > MAX_UD60x18 / SCALE) {
                revert PRBMathUD60x18__FromUintOverflow(x);
            }
            result = x * SCALE;
        }
    }

    /// @notice Calculates geometric mean of x and y, i.e. sqrt(x * y), rounding down.
    ///
    /// @dev Requirements:
    /// - x * y must fit within MAX_UD60x18, lest it overflows.
    ///
    /// @param x The first operand as an unsigned 60.18-decimal fixed-point number.
    /// @param y The second operand as an unsigned 60.18-decimal fixed-point number.
    /// @return result The result as an unsigned 60.18-decimal fixed-point number.
    function gm(uint256 x, uint256 y) internal pure returns (uint256 result) {
        if (x == 0) {
            return 0;
        }

        unchecked {
            // Checking for overflow this way is faster than letting Solidity do it.
            uint256 xy = x * y;
            if (xy / x != y) {
                revert PRBMathUD60x18__GmOverflow(x, y);
            }

            // We don't need to multiply by the SCALE here because the x*y product had already picked up a factor of SCALE
            // during multiplication. See the comments within the "sqrt" function.
            result = PRBMath.sqrt(xy);
        }
    }

    /// @notice Calculates 1 / x, rounding toward zero.
    ///
    /// @dev Requirements:
    /// - x cannot be zero.
    ///
    /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the inverse.
    /// @return result The inverse as an unsigned 60.18-decimal fixed-point number.
    function inv(uint256 x) internal pure returns (uint256 result) {
        unchecked {
            // 1e36 is SCALE * SCALE.
            result = 1e36 / x;
        }
    }

    /// @notice Calculates the natural logarithm of x.
    ///
    /// @dev Based on the insight that ln(x) = log2(x) / log2(e).
    ///
    /// Requirements:
    /// - All from "log2".
    ///
    /// Caveats:
    /// - All from "log2".
    /// - This doesn't return exactly 1 for 2.718281828459045235, for that we would need more fine-grained precision.
    ///
    /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the natural logarithm.
    /// @return result The natural logarithm as an unsigned 60.18-decimal fixed-point number.
    function ln(uint256 x) internal pure returns (uint256 result) {
        // Do the fixed-point multiplication inline to save gas. This is overflow-safe because the maximum value that log2(x)
        // can return is 196205294292027477728.
        unchecked {
            result = (log2(x) * SCALE) / LOG2_E;
        }
    }

    /// @notice Calculates the common logarithm of x.
    ///
    /// @dev First checks if x is an exact power of ten and it stops if yes. If it's not, calculates the common
    /// logarithm based on the insight that log10(x) = log2(x) / log2(10).
    ///
    /// Requirements:
    /// - All from "log2".
    ///
    /// Caveats:
    /// - All from "log2".
    ///
    /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the common logarithm.
    /// @return result The common logarithm as an unsigned 60.18-decimal fixed-point number.
    function log10(uint256 x) internal pure returns (uint256 result) {
        if (x < SCALE) {
            revert PRBMathUD60x18__LogInputTooSmall(x);
        }

        // Note that the "mul" in this block is the assembly multiplication operation, not the "mul" function defined
        // in this contract.
        // prettier-ignore
        assembly {
            switch x
            case 1 { result := mul(SCALE, sub(0, 18)) }
            case 10 { result := mul(SCALE, sub(1, 18)) }
            case 100 { result := mul(SCALE, sub(2, 18)) }
            case 1000 { result := mul(SCALE, sub(3, 18)) }
            case 10000 { result := mul(SCALE, sub(4, 18)) }
            case 100000 { result := mul(SCALE, sub(5, 18)) }
            case 1000000 { result := mul(SCALE, sub(6, 18)) }
            case 10000000 { result := mul(SCALE, sub(7, 18)) }
            case 100000000 { result := mul(SCALE, sub(8, 18)) }
            case 1000000000 { result := mul(SCALE, sub(9, 18)) }
            case 10000000000 { result := mul(SCALE, sub(10, 18)) }
            case 100000000000 { result := mul(SCALE, sub(11, 18)) }
            case 1000000000000 { result := mul(SCALE, sub(12, 18)) }
            case 10000000000000 { result := mul(SCALE, sub(13, 18)) }
            case 100000000000000 { result := mul(SCALE, sub(14, 18)) }
            case 1000000000000000 { result := mul(SCALE, sub(15, 18)) }
            case 10000000000000000 { result := mul(SCALE, sub(16, 18)) }
            case 100000000000000000 { result := mul(SCALE, sub(17, 18)) }
            case 1000000000000000000 { result := 0 }
            case 10000000000000000000 { result := SCALE }
            case 100000000000000000000 { result := mul(SCALE, 2) }
            case 1000000000000000000000 { result := mul(SCALE, 3) }
            case 10000000000000000000000 { result := mul(SCALE, 4) }
            case 100000000000000000000000 { result := mul(SCALE, 5) }
            case 1000000000000000000000000 { result := mul(SCALE, 6) }
            case 10000000000000000000000000 { result := mul(SCALE, 7) }
            case 100000000000000000000000000 { result := mul(SCALE, 8) }
            case 1000000000000000000000000000 { result := mul(SCALE, 9) }
            case 10000000000000000000000000000 { result := mul(SCALE, 10) }
            case 100000000000000000000000000000 { result := mul(SCALE, 11) }
            case 1000000000000000000000000000000 { result := mul(SCALE, 12) }
            case 10000000000000000000000000000000 { result := mul(SCALE, 13) }
            case 100000000000000000000000000000000 { result := mul(SCALE, 14) }
            case 1000000000000000000000000000000000 { result := mul(SCALE, 15) }
            case 10000000000000000000000000000000000 { result := mul(SCALE, 16) }
            case 100000000000000000000000000000000000 { result := mul(SCALE, 17) }
            case 1000000000000000000000000000000000000 { result := mul(SCALE, 18) }
            case 10000000000000000000000000000000000000 { result := mul(SCALE, 19) }
            case 100000000000000000000000000000000000000 { result := mul(SCALE, 20) }
            case 1000000000000000000000000000000000000000 { result := mul(SCALE, 21) }
            case 10000000000000000000000000000000000000000 { result := mul(SCALE, 22) }
            case 100000000000000000000000000000000000000000 { result := mul(SCALE, 23) }
            case 1000000000000000000000000000000000000000000 { result := mul(SCALE, 24) }
            case 10000000000000000000000000000000000000000000 { result := mul(SCALE, 25) }
            case 100000000000000000000000000000000000000000000 { result := mul(SCALE, 26) }
            case 1000000000000000000000000000000000000000000000 { result := mul(SCALE, 27) }
            case 10000000000000000000000000000000000000000000000 { result := mul(SCALE, 28) }
            case 100000000000000000000000000000000000000000000000 { result := mul(SCALE, 29) }
            case 1000000000000000000000000000000000000000000000000 { result := mul(SCALE, 30) }
            case 10000000000000000000000000000000000000000000000000 { result := mul(SCALE, 31) }
            case 100000000000000000000000000000000000000000000000000 { result := mul(SCALE, 32) }
            case 1000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 33) }
            case 10000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 34) }
            case 100000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 35) }
            case 1000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 36) }
            case 10000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 37) }
            case 100000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 38) }
            case 1000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 39) }
            case 10000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 40) }
            case 100000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 41) }
            case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 42) }
            case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 43) }
            case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 44) }
            case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 45) }
            case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 46) }
            case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 47) }
            case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 48) }
            case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 49) }
            case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 50) }
            case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 51) }
            case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 52) }
            case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 53) }
            case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 54) }
            case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 55) }
            case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 56) }
            case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 57) }
            case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 58) }
            case 100000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 59) }
            default {
                result := MAX_UD60x18
            }
        }

        if (result == MAX_UD60x18) {
            // Do the fixed-point division inline to save gas. The denominator is log2(10).
            unchecked {
                result = (log2(x) * SCALE) / 3_321928094887362347;
            }
        }
    }

    /// @notice Calculates the binary logarithm of x.
    ///
    /// @dev Based on the iterative approximation algorithm.
    /// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation
    ///
    /// Requirements:
    /// - x must be greater than or equal to SCALE, otherwise the result would be negative.
    ///
    /// Caveats:
    /// - The results are nor perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation.
    ///
    /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the binary logarithm.
    /// @return result The binary logarithm as an unsigned 60.18-decimal fixed-point number.
    function log2(uint256 x) internal pure returns (uint256 result) {
        if (x < SCALE) {
            revert PRBMathUD60x18__LogInputTooSmall(x);
        }
        unchecked {
            // Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n).
            uint256 n = PRBMath.mostSignificantBit(x / SCALE);

            // The integer part of the logarithm as an unsigned 60.18-decimal fixed-point number. The operation can't overflow
            // because n is maximum 255 and SCALE is 1e18.
            result = n * SCALE;

            // This is y = x * 2^(-n).
            uint256 y = x >> n;

            // If y = 1, the fractional part is zero.
            if (y == SCALE) {
                return result;
            }

            // Calculate the fractional part via the iterative approximation.
            // The "delta >>= 1" part is equivalent to "delta /= 2", but shifting bits is faster.
            for (uint256 delta = HALF_SCALE; delta > 0; delta >>= 1) {
                y = (y * y) / SCALE;

                // Is y^2 > 2 and so in the range [2,4)?
                if (y >= 2 * SCALE) {
                    // Add the 2^(-m) factor to the logarithm.
                    result += delta;

                    // Corresponds to z/2 on Wikipedia.
                    y >>= 1;
                }
            }
        }
    }

    /// @notice Multiplies two unsigned 60.18-decimal fixed-point numbers together, returning a new unsigned 60.18-decimal
    /// fixed-point number.
    /// @dev See the documentation for the "PRBMath.mulDivFixedPoint" function.
    /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.
    /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.
    /// @return result The product as an unsigned 60.18-decimal fixed-point number.
    function mul(uint256 x, uint256 y) internal pure returns (uint256 result) {
        result = PRBMath.mulDivFixedPoint(x, y);
    }

    /// @notice Returns PI as an unsigned 60.18-decimal fixed-point number.
    function pi() internal pure returns (uint256 result) {
        result = 3_141592653589793238;
    }

    /// @notice Raises x to the power of y.
    ///
    /// @dev Based on the insight that x^y = 2^(log2(x) * y).
    ///
    /// Requirements:
    /// - All from "exp2", "log2" and "mul".
    ///
    /// Caveats:
    /// - All from "exp2", "log2" and "mul".
    /// - Assumes 0^0 is 1.
    ///
    /// @param x Number to raise to given power y, as an unsigned 60.18-decimal fixed-point number.
    /// @param y Exponent to raise x to, as an unsigned 60.18-decimal fixed-point number.
    /// @return result x raised to power y, as an unsigned 60.18-decimal fixed-point number.
    function pow(uint256 x, uint256 y) internal pure returns (uint256 result) {
        if (x == 0) {
            result = y == 0 ? SCALE : uint256(0);
        } else {
            result = exp2(mul(log2(x), y));
        }
    }

    /// @notice Raises x (unsigned 60.18-decimal fixed-point number) to the power of y (basic unsigned integer) using the
    /// famous algorithm "exponentiation by squaring".
    ///
    /// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring
    ///
    /// Requirements:
    /// - The result must fit within MAX_UD60x18.
    ///
    /// Caveats:
    /// - All from "mul".
    /// - Assumes 0^0 is 1.
    ///
    /// @param x The base as an unsigned 60.18-decimal fixed-point number.
    /// @param y The exponent as an uint256.
    /// @return result The result as an unsigned 60.18-decimal fixed-point number.
    function powu(uint256 x, uint256 y) internal pure returns (uint256 result) {
        // Calculate the first iteration of the loop in advance.
        result = y & 1 > 0 ? x : SCALE;

        // Equivalent to "for(y /= 2; y > 0; y /= 2)" but faster.
        for (y >>= 1; y > 0; y >>= 1) {
            x = PRBMath.mulDivFixedPoint(x, x);

            // Equivalent to "y % 2 == 1" but faster.
            if (y & 1 > 0) {
                result = PRBMath.mulDivFixedPoint(result, x);
            }
        }
    }

    /// @notice Returns 1 as an unsigned 60.18-decimal fixed-point number.
    function scale() internal pure returns (uint256 result) {
        result = SCALE;
    }

    /// @notice Calculates the square root of x, rounding down.
    /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
    ///
    /// Requirements:
    /// - x must be less than MAX_UD60x18 / SCALE.
    ///
    /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the square root.
    /// @return result The result as an unsigned 60.18-decimal fixed-point .
    function sqrt(uint256 x) internal pure returns (uint256 result) {
        unchecked {
            if (x > MAX_UD60x18 / SCALE) {
                revert PRBMathUD60x18__SqrtOverflow(x);
            }
            // Multiply x by the SCALE to account for the factor of SCALE that is picked up when multiplying two unsigned
            // 60.18-decimal fixed-point numbers together (in this case, those two numbers are both the square root).
            result = PRBMath.sqrt(x * SCALE);
        }
    }

    /// @notice Converts a unsigned 60.18-decimal fixed-point number to basic integer form, rounding down in the process.
    /// @param x The unsigned 60.18-decimal fixed-point number to convert.
    /// @return result The same number in basic integer form.
    function toUint(uint256 x) internal pure returns (uint256 result) {
        unchecked {
            result = x / SCALE;
        }
    }
}

Settings
{
  "evmVersion": "london",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 10
  },
  "remappings": [],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AavePoolGetReserveNormalizedIncomeReturnedZero","type":"error"},{"inputs":[],"name":"AavePoolGetReserveNormalizedVariableDebtReturnedZero","type":"error"},{"inputs":[],"name":"CTokenExchangeRateReturnedZero","type":"error"},{"inputs":[{"internalType":"bool","name":"unlocked","type":"bool"}],"name":"CanOnlyTradeIfUnlocked","type":"error"},{"inputs":[],"name":"CannotLiquidate","type":"error"},{"inputs":[],"name":"CannotSettleBeforeMaturity","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"name":"DebugError","type":"error"},{"inputs":[{"internalType":"int256","name":"amount0","type":"int256"},{"internalType":"int256","name":"amount1","type":"int256"}],"name":"ExpectedOppositeSigns","type":"error"},{"inputs":[{"internalType":"uint160","name":"sqrtPriceX96","type":"uint160"}],"name":"ExpectedSqrtPriceZeroBeforeInit","type":"error"},{"inputs":[],"name":"IRSNotionalAmountSpecifiedMustBeNonZero","type":"error"},{"inputs":[],"name":"InvalidMarginDelta","type":"error"},{"inputs":[],"name":"LidoGetPooledEthBySharesReturnedZero","type":"error"},{"inputs":[{"internalType":"uint128","name":"amount","type":"uint128"}],"name":"LiquidityDeltaMustBePositiveInBurn","type":"error"},{"inputs":[{"internalType":"uint128","name":"amount","type":"uint128"}],"name":"LiquidityDeltaMustBePositiveInMint","type":"error"},{"inputs":[{"internalType":"int256","name":"marginRequirement","type":"int256"}],"name":"MarginLessThanMinimum","type":"error"},{"inputs":[{"internalType":"int256","name":"marginRequirement","type":"int256"},{"internalType":"int24","name":"tick","type":"int24"},{"internalType":"int256","name":"fixedTokenDelta","type":"int256"},{"internalType":"int256","name":"variableTokenDelta","type":"int256"},{"internalType":"uint256","name":"cumulativeFeeIncurred","type":"uint256"},{"internalType":"int256","name":"fixedTokenDeltaUnbalanced","type":"int256"}],"name":"MarginRequirementNotMet","type":"error"},{"inputs":[{"internalType":"int256","name":"marginRequirement","type":"int256"}],"name":"MarginRequirementNotMetFCM","type":"error"},{"inputs":[{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"}],"name":"NotEnoughFunds","type":"error"},{"inputs":[],"name":"OOO","type":"error"},{"inputs":[],"name":"OnlyFCM","type":"error"},{"inputs":[],"name":"OnlyMarginEngine","type":"error"},{"inputs":[],"name":"OnlyOwnerCanUpdatePosition","type":"error"},{"inputs":[],"name":"OnlyVAMM","type":"error"},{"inputs":[],"name":"PRBMathSD59x18__DivInputTooSmall","type":"error"},{"inputs":[{"internalType":"uint256","name":"rAbs","type":"uint256"}],"name":"PRBMathSD59x18__DivOverflow","type":"error"},{"inputs":[{"internalType":"int256","name":"x","type":"int256"}],"name":"PRBMathSD59x18__FromIntOverflow","type":"error"},{"inputs":[{"internalType":"int256","name":"x","type":"int256"}],"name":"PRBMathSD59x18__FromIntUnderflow","type":"error"},{"inputs":[],"name":"PRBMathSD59x18__MulInputTooSmall","type":"error"},{"inputs":[{"internalType":"uint256","name":"rAbs","type":"uint256"}],"name":"PRBMathSD59x18__MulOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"PRBMathUD60x18__FromUintOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"prod1","type":"uint256"}],"name":"PRBMath__MulDivFixedPointOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"prod1","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"PRBMath__MulDivOverflow","type":"error"},{"inputs":[],"name":"PositionNetZero","type":"error"},{"inputs":[],"name":"PositionNotSettled","type":"error"},{"inputs":[],"name":"RocketPoolGetEthValueReturnedZero","type":"error"},{"inputs":[],"name":"WithdrawalExceedsCurrentMargin","type":"error"},{"inputs":[],"name":"closeToOrBeyondMaturity","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"int24","name":"tickLower","type":"int24"},{"indexed":true,"internalType":"int24","name":"tickUpper","type":"int24"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"feeWad","type":"uint256"}],"name":"Fee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"feeProtocol","type":"uint8"}],"name":"FeeProtocol","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"__isAlpha","type":"bool"}],"name":"IsAlpha","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"int24","name":"tickLower","type":"int24"},{"indexed":true,"internalType":"int24","name":"tickUpper","type":"int24"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"int24","name":"tickLower","type":"int24"},{"indexed":true,"internalType":"int24","name":"tickUpper","type":"int24"},{"indexed":false,"internalType":"int256","name":"desiredNotional","type":"int256"},{"indexed":false,"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"},{"indexed":false,"internalType":"uint256","name":"cumulativeFeeIncurred","type":"uint256"},{"indexed":false,"internalType":"int256","name":"fixedTokenDelta","type":"int256"},{"indexed":false,"internalType":"int256","name":"variableTokenDelta","type":"int256"},{"indexed":false,"internalType":"int256","name":"fixedTokenDeltaUnbalanced","type":"int256"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint160","name":"sqrtPriceX96","type":"uint160"},{"indexed":false,"internalType":"int24","name":"tick","type":"int24"}],"name":"VAMMInitialization","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int24","name":"tick","type":"int24"}],"name":"VAMMPriceChange","type":"event"},{"inputs":[],"name":"MAX_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VOLTZ_PAUSER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint128","name":"amount","type":"uint128"}],"name":"burn","outputs":[{"internalType":"int256","name":"positionMarginRequirement","type":"int256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"permission","type":"bool"}],"name":"changePauser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"}],"name":"computeGrowthInside","outputs":[{"internalType":"int256","name":"fixedTokenGrowthInsideX128","type":"int256"},{"internalType":"int256","name":"variableTokenGrowthInsideX128","type":"int256"},{"internalType":"uint256","name":"feeGrowthInsideX128","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract IFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeGrowthGlobalX128","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeWad","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fixedTokenGrowthGlobalX128","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRateOracle","outputs":[{"internalType":"contract IRateOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IMarginEngine","name":"__marginEngine","type":"address"},{"internalType":"int24","name":"__tickSpacing","type":"int24"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint160","name":"sqrtPriceX96","type":"uint160"}],"name":"initializeVAMM","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isAlpha","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidity","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marginEngine","outputs":[{"internalType":"contract IMarginEngine","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLiquidityPerTick","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint128","name":"amount","type":"uint128"}],"name":"mint","outputs":[{"internalType":"int256","name":"positionMarginRequirement","type":"int256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refreshRateOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeWad","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"feeProtocol","type":"uint8"}],"name":"setFeeProtocol","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"__isAlpha","type":"bool"}],"name":"setIsAlpha","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state","type":"bool"}],"name":"setPausability","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"int256","name":"amountSpecified","type":"int256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"}],"internalType":"struct IVAMM.SwapParams","name":"params","type":"tuple"}],"name":"swap","outputs":[{"internalType":"int256","name":"fixedTokenDelta","type":"int256"},{"internalType":"int256","name":"variableTokenDelta","type":"int256"},{"internalType":"uint256","name":"cumulativeFeeIncurred","type":"uint256"},{"internalType":"int256","name":"fixedTokenDeltaUnbalanced","type":"int256"},{"internalType":"int256","name":"marginRequirement","type":"int256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int16","name":"wordPosition","type":"int16"}],"name":"tickBitmap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tickSpacing","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int24","name":"tick","type":"int24"}],"name":"ticks","outputs":[{"components":[{"internalType":"uint128","name":"liquidityGross","type":"uint128"},{"internalType":"int128","name":"liquidityNet","type":"int128"},{"internalType":"int256","name":"fixedTokenGrowthOutsideX128","type":"int256"},{"internalType":"int256","name":"variableTokenGrowthOutsideX128","type":"int256"},{"internalType":"uint256","name":"feeGrowthOutsideX128","type":"uint256"},{"internalType":"bool","name":"initialized","type":"bool"}],"internalType":"struct Tick.Info","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"protocolFeesCollected","type":"uint256"}],"name":"updateProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"vammVars","outputs":[{"components":[{"internalType":"uint160","name":"sqrtPriceX96","type":"uint160"},{"internalType":"int24","name":"tick","type":"int24"},{"internalType":"uint8","name":"feeProtocol","type":"uint8"}],"internalType":"struct IVAMM.VAMMVars","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"variableTokenGrowthGlobalX128","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"}]

60a0604052306080523480156200001557600080fd5b50604554610100900460ff1615808015620000375750604554600160ff909116105b8062000067575062000054306200014160201b620029141760201c565b15801562000067575060455460ff166001145b620000cf5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b6045805460ff191660011790558015620000f3576045805461ff0019166101001790555b80156200013a576045805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5062000150565b6001600160a01b03163b151590565b608051615fd06200018860003960008181610c2701528181610c6701528181610fcf0152818161100f015261108b0152615fd06000f3fe6080604052600436106101a95760003560e01c80624006e0146101ae57806309d7b622146101de5780630bd9c1af146101fd5780630d211954146102145780631a686502146102345780631ad8b03b146102605780631b398e06146102755780631f2f0893146102a95780633659cfe6146102c95780633c8f233e146102e9578063478de3241461032457806347f75ede146103445780634e65b408146103645780634f1ef2861461037957806352d1902d1461038c5780635339c296146103a15780635c975abb146103d157806367758e6e146103fb57806369fe0e2d1461044357806370cf754a14610463578063715018a614610481578063778762361461049657806380a0f76c146104b4578063867377101461054f578063884287521461056f5780638da5cb5b14610587578063ad23b4161461059c578063b613a141146105b1578063b8cca34e146105d1578063bc063e1a146105f1578063c45a01551461060c578063cd41b3d51461062a578063d0c93a7c1461064a578063d992d9081461066d578063f2fde38b1461068d578063f30dba93146106ad578063f3f94990146107be575b600080fd5b3480156101ba57600080fd5b506003546001600160a01b03165b6040516101d5919061532b565b60405180910390f35b3480156101ea57600080fd5b50600a545b6040519081526020016101d5565b34801561020957600080fd5b506102126107d3565b005b34801561022057600080fd5b5061021261022f36600461534d565b610883565b34801561024057600080fd5b5060075461010090046001600160801b03165b6040516101d5919061536a565b34801561026c57600080fd5b506009546101ef565b34801561028157600080fd5b506101ef7fc02e2d3f2633adb184196f6ae17c8476d7912f8727b7c1cc7da0b7ddac86bc6581565b3480156102b557600080fd5b506101ef6102c43660046153a5565b610942565b3480156102d557600080fd5b506102126102e4366004615409565b610c1c565b3480156102f557600080fd5b50610309610304366004615426565b610ce5565b604080519384526020840192909252908201526060016101d5565b34801561033057600080fd5b5061021261033f366004615459565b610dc3565b34801561035057600080fd5b5061021261035f366004615409565b610df6565b34801561037057600080fd5b50600b546101ef565b6102126103873660046154d8565b610fc4565b34801561039857600080fd5b506101ef61107e565b3480156103ad57600080fd5b506101ef6103bc36600461557f565b60010b6000908152600e602052604090205490565b3480156103dd57600080fd5b506012546103eb9060ff1681565b60405190151581526020016101d5565b34801561040757600080fd5b5061041b6104163660046155a2565b61112c565b604080519586526020860194909452928401919091526060830152608082015260a0016101d5565b34801561044f57600080fd5b5061021261045e36600461562c565b612014565b34801561046f57600080fd5b506004546001600160801b0316610253565b34801561048d57600080fd5b5061021261209b565b3480156104a257600080fd5b506000546001600160a01b03166101c8565b3480156104c057600080fd5b5061051e60408051606081018252600080825260208201819052918101919091525060408051606081018252600f546001600160a01b0381168252600160a01b810460020b6020830152600160b81b900460ff169181019190915290565b6040805182516001600160a01b0316815260208084015160020b908201529181015160ff16908201526060016101d5565b34801561055b57600080fd5b5061021261056a36600461562c565b6120af565b34801561057b57600080fd5b5060105460ff166103eb565b34801561059357600080fd5b506101c8612125565b3480156105a857600080fd5b506008546101ef565b3480156105bd57600080fd5b506102126105cc366004615645565b612134565b3480156105dd57600080fd5b506101ef6105ec3660046153a5565b6121e4565b3480156105fd57600080fd5b506101ef66470de4df82000081565b34801561061857600080fd5b506005546001600160a01b03166101c8565b34801561063657600080fd5b5061021261064536600461534d565b6124ad565b34801561065657600080fd5b50600c5460405160029190910b81526020016101d5565b34801561067957600080fd5b50610212610688366004615668565b6124fc565b34801561069957600080fd5b506102126106a8366004615409565b61289e565b3480156106b957600080fd5b506107696106c8366004615686565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915250600290810b6000908152600d6020908152604091829020825160c08101845281546001600160801b0381168252600160801b9004600f0b92810192909252600181015492820192909252918101546060830152600381015460808301526004015460ff16151560a082015290565b6040516101d5919081516001600160801b03168152602080830151600f0b9082015260408083015190820152606080830151908201526080828101519082015260a09182015115159181019190915260c00190565b3480156107ca57600080fd5b506006546101ef565b6107db612923565b600360009054906101000a90046001600160a01b03166001600160a01b03166398f4b1b26040518163ffffffff1660e01b815260040160206040518083038186803b15801561082957600080fd5b505afa15801561083d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086191906156a1565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b3360009081526011602052604090205460ff166108d15760405162461bcd60e51b81526020600482015260076024820152666e6f20726f6c6560c81b60448201526064015b60405180910390fd5b6012805460ff1916821515908117909155600354604051630348465560e21b815260048101929092526001600160a01b031690630d21195490602401600060405180830381600087803b15801561092757600080fd5b505af115801561093b573d6000803e3d6000fd5b5050505050565b60105460009060ff1615610a0e5760055460408051633bd5670d60e11b815290516000926001600160a01b0316916377aace1a916004808301926020929190829003018186803b15801561099557600080fd5b505afa1580156109a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109cd91906156a1565b9050336001600160a01b03821614806109f057506003546001600160a01b031633145b610a0c5760405162461bcd60e51b81526004016108c8906156be565b505b60125460ff1615610a315760405162461bcd60e51b81526004016108c8906156e2565b60075460ff16610a535760405162461bcd60e51b81526004016108c890615702565b6007805460ff191690556001600160801b038216610a86578160405163c09d260960e01b81526004016108c8919061536a565b336001600160a01b0386161480610aa757506003546001600160a01b031633145b80610b2f57506005546040516351c4bc1f60e11b81526001600160a01b039091169063a389783e90610adf908890339060040161571f565b60206040518083038186803b158015610af757600080fd5b505afa158015610b0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2f9190615739565b610b665760405162461bcd60e51b81526020600482015260086024820152674d53206f72204d4560c01b60448201526064016108c8565b610bba6040518060800160405280876001600160a01b031681526020018660020b81526020018560020b8152602001610ba7856001600160801b0316612982565b610bb09061576c565b600f0b90526129cb565b90508260020b8460020b866001600160a01b03167ff57f161c6404e7a58d089003a260456719af3caac502550a59509b4c9d8d46283386604051610bff929190615794565b60405180910390a46007805460ff19166001179055949350505050565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161415610c655760405162461bcd60e51b81526004016108c8906157b6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610c97612c29565b6001600160a01b031614610cbd5760405162461bcd60e51b81526004016108c8906157f0565b610cc681612c45565b60408051600080825260208201909252610ce291839190612c4d565b50565b6000806000610cf48585612dc7565b60408051608081018252600287810b825286810b6020830152600f54600160a01b9004900b91810191909152600a546060820152610d3490600d90612e88565b60408051608081018252600288810b825287810b6020830152600f54600160a01b9004900b91810191909152600b546060820152909350610d7790600d90612ee1565b60408051608081018252600288810b825287810b6020830152600f54600160a01b9004900b918101919091526008546060820152909250610dba90600d90612f28565b90509250925092565b610dcb612923565b6001600160a01b03919091166000908152601160205260409020805460ff1916911515919091179055565b6001600160a01b038116610e3f5760405162461bcd60e51b815260206004820152601060248201526f7a65726f20696e70757420707269636560801b60448201526064016108c8565b6c1fa71f3f5f68a90479ee3f8fec6001600160a01b038216108015610e7957506b0816769404766de590afe04e6001600160a01b03821610155b610e955760405162461bcd60e51b81526004016108c89061582a565b6003546001600160a01b0316610ee45760405162461bcd60e51b81526020600482015260146024820152731d985b5b481b9bdd081a5b9a5d1a585b1a5e995960621b60448201526064016108c8565b600f546001600160a01b031615610f1b57600f546040516328be1c0f60e21b81526108c8916001600160a01b03169060040161532b565b6000610f2682612f8f565b604080516060810182526001600160a01b038516808252600284900b6020808401829052600093850193909352600f80546001600160b81b0319168317600160a01b62ffffff8816021760ff60b81b191690556007805460ff191660011790558351918252918101919091529192507facf59ced105c47c72de67aa00ab58b6415014ad6018644e3e8d8ca6862ec0dce910160405180910390a15050565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016141561100d5760405162461bcd60e51b81526004016108c8906157b6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661103f612c29565b6001600160a01b0316146110655760405162461bcd60e51b81526004016108c8906157f0565b61106e82612c45565b61107a82826001612c4d565b5050565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146111195760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c6044820152771b1959081d1a1c9bdd59da0819195b1959d85d1958d85b1b60421b60648201526084016108c8565b50600080516020615f5483398151915290565b601254600090819081908190819060ff161561115a5760405162461bcd60e51b81526004016108c8906156e2565b6111656002546132b3565b156111825760405162461bcd60e51b81526004016108c890615845565b61119486606001518760800151612dc7565b60408051606081018252600f546001600160a01b0381168252600160a01b810460020b602080840191909152600160b81b90910460ff1692820192909252908701516111e690889083906000126132db565b6003546001600160a01b03163314806112955750600360009054906101000a90046001600160a01b03166001600160a01b03166322d23b216040518163ffffffff1660e01b815260040160206040518083038186803b15801561124857600080fd5b505afa15801561125c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128091906156a1565b6001600160a01b0316336001600160a01b0316145b6113865786516001600160a01b031633148061132e575060055487516040516351c4bc1f60e11b81526001600160a01b039092169163a389783e916112de91339060040161571f565b60206040518083038186803b1580156112f657600080fd5b505afa15801561130a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061132e9190615739565b6113865760405162461bcd60e51b815260206004820152602360248201527f6f6e6c792073656e646572206f7220617070726f76656420696e74656772617460448201526234b7b760e91b60648201526084016108c8565b6007805460ff1916908190556040805180820182526001600160801b036101009384900481168252600f54600160b81b900460ff1660208084019190915283516101c0810185528c8201518152600081830181905287516001600160a01b039081168388015292880151600290810b6060840152600a546080840152600b5460a0840152855190941660c083015260085460e083015295810186905261012081018690526101408101869052610160810186905261018081018690528554600154935495516325f258dd60e01b815294969591946101a086019491909316926325f258dd926114819291600401918252602082015260400190565b602060405180830381600087803b15801561149b57600080fd5b505af11580156114af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d39190615876565b815250905060008054906101000a90046001600160a01b03166001600160a01b0316637aa4db136040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561152657600080fd5b505af115801561153a573d6000803e3d6000fd5b50505050600089602001511315611911575b805115801590611576575088604001516001600160a01b031681604001516001600160a01b031614155b1561190c576115836152ba565b60408201516001600160a01b031681526060820151600c546115ac91600e9160020b60006133fc565b1515604083015260020b60208201526115c862010deb1961588f565b60020b816020015160020b13156115ef576115e662010deb1961588f565b60020b60208201525b6115fc81602001516135b9565b81606001906001600160a01b031690816001600160a01b0316815250506116b76040518060c0016040528084604001516001600160a01b031681526020018c604001516001600160a01b031684606001516001600160a01b03161161166557836060015161166b565b8c604001515b6001600160a01b0316815260c08501516001600160801b031660208201528451604082015260065460608201526080016116a361394e565b6002546116b091906158a9565b905261395e565b60c085015260a0840152608083019081526001600160a01b039091166040840152516116e290613b87565b825183906116f19083906158c0565b90525060a081015161170290613b87565b8260200181815161171391906158c0565b905250608081015161172490613b87565b61014082015260a081015161173890613b87565b611741906158ff565b61010082015260c08101516101208301805161175e90839061591c565b905250602083015160ff16156117bb57826020015160ff168160c00151611785919061594a565b60e0820181905260c08201805161179d9083906158a9565b90525060e0810151610100830180516117b790839061591c565b9052505b60c08201516001600160801b031615611845576117d88282613bd0565b6101208501908152608086019190915260a085019190915260e0840191909152516101408301805161180b9083906158c0565b905250610140810151610160830180516118269083906158c0565b905250610100810151610180830180516118419083906158c0565b9052505b80606001516001600160a01b031682604001516001600160a01b031614156118cf578060400151156118bd57600061189d826020015184608001518560a001518660e00151600d613c9190949392919063ffffffff16565b90506118ad8360c0015182613cf5565b6001600160801b031660c0840152505b602081015160020b6060830152611906565b80600001516001600160a01b031682604001516001600160a01b031614611906576118fd8260400151612f8f565b60020b60608301525b5061154c565b611c7c565b80511580159061193b575088604001516001600160a01b031681604001516001600160a01b031614155b15611c7c576119486152ba565b60408201516001600160a01b031681526060820151600c5461197191600e9160020b60016133fc565b1515604083015260020b6020820181905262010deb1913156119985762010deb1960208201525b6119a581602001516135b9565b81606001906001600160a01b031690816001600160a01b031681525050611a0e6040518060c0016040528084604001516001600160a01b031681526020018c604001516001600160a01b031684606001516001600160a01b03161061166557836060015161166b565b60c085015260a0840190815260808401919091526001600160a01b03909116604084015251611a3c90613b87565b82518390611a4b90839061595e565b9052506080810151611a5c90613b87565b82602001818151611a6d919061595e565b90525060a0810151611a7e90613b87565b611a87906158ff565b6101408201526080810151611a9b90613b87565b61010082015260c0810151610120830151611ab6919061591c565b610120830152602083015160ff1615611b1657826020015160ff168160c00151611ae0919061594a565b60e0820181905260c082018051611af89083906158a9565b90525060e081015161010083018051611b1290839061591c565b9052505b60c08201516001600160801b031615611ba057611b338282613bd0565b6101208501908152608086019190915260a085019190915260e08401919091525161014083018051611b669083906158c0565b90525061014081015161016083018051611b819083906158c0565b90525061010081015161018083018051611b9c9083906158c0565b9052505b80606001516001600160a01b031682604001516001600160a01b03161415611c3f57806040015115611c21576000611bf8826020015184608001518560a001518660e00151600d613c9190949392919063ffffffff16565b9050611c118360c0015182611c0c9061576c565b613cf5565b6001600160801b031660c0840152505b60018160200151611c32919061599f565b60020b6060830152611c76565b80600001516001600160a01b031682604001516001600160a01b031614611c7657611c6d8260400151612f8f565b60020b60608301525b50611911565b6040810151600f80546001600160a01b0319166001600160a01b0390921691909117905560208301516060820151600291820b910b14611cde576060810151600f805462ffffff909216600160a01b0262ffffff60a01b199092169190911790555b8060c001516001600160801b031682600001516001600160801b031614611d2b5760c0810151600780546001600160801b0390921661010002610100600160881b03199092169190911790555b60e081015160085560a0810151600b556080810151600a55610120810151610140820151610160830151610180840151610100850151929b5090995091975090955015611d8f5780610100015160096000828254611d89919061591c565b90915550505b6003546001600160a01b0316331480611e3e5750600360009054906101000a90046001600160a01b03166001600160a01b03166322d23b216040518163ffffffff1660e01b815260040160206040518083038186803b158015611df157600080fd5b505afa158015611e05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2991906156a1565b6001600160a01b0316336001600160a01b0316145b611f1457600354895160608b015160808c015161014085015161016086015161012087015161018088015160405163604b0bd760e11b81526001600160a01b039788166004820152600296870b60248201529490950b60448501526064840192909252608483015260a482015260c481019190915291169063c09617ae9060e401602060405180830381600087803b158015611ed957600080fd5b505af1158015611eed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f119190615876565b93505b600f54604051600160a01b90910460020b81527f3de48b885df0271268324c099733a36a802c1cbb40c7272796b2b28addf04cd29060200160405180910390a1886080015160020b896060015160020b8a600001516001600160a01b03167fa24f288a343811d26ac1ec29998e37b87ff6503cefe399a3c8fb747eb0464e58338d602001518e604001518c8f8f8e604051611ff197969594939291906001600160a01b03978816815260208101969096529390951660408501526060840191909152608083015260a082019290925260c081019190915260e00190565b60405180910390a450506007805460ff1916600117905550939592945090929091565b61201c612923565b66470de4df82000081111561205f5760405162461bcd60e51b81526020600482015260096024820152686665652072616e676560b81b60448201526064016108c8565b60068190556040518181527f557809284da7314475b1582804ae28e5f1349efc1fe970ea25d50fce75eb4f43906020015b60405180910390a150565b6120a3612923565b6120ad6000613d2c565b565b6003546001600160a01b031633146120da57604051630a0d349f60e21b815260040160405180910390fd5b80600954101561210b576009546040516311920a6d60e31b81526108c8918391600401918252602082015260400190565b806009600082825461211d91906158a9565b909155505050565b6078546001600160a01b031690565b61213c612923565b60ff8116158061215f575060038160ff161015801561215f575060328160ff1611155b6121965760405162461bcd60e51b815260206004820152600860248201526750522072616e676560c01b60448201526064016108c8565b600f805460ff60b81b1916600160b81b60ff8416908102919091179091556040519081527fe949530fb25dc21f05cb65fe03447f6f68f8e21e3584c72e6e92042b8bc28f7990602001612090565b60105460009060ff161561229b5760055460408051633bd5670d60e11b815290516000926001600160a01b0316916377aace1a916004808301926020929190829003018186803b15801561223757600080fd5b505afa15801561224b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061226f91906156a1565b9050336001600160a01b038216146122995760405162461bcd60e51b81526004016108c8906156be565b505b60125460ff16156122be5760405162461bcd60e51b81526004016108c8906156e2565b6122c96002546132b3565b156122e65760405162461bcd60e51b81526004016108c890615845565b60075460ff166123085760405162461bcd60e51b81526004016108c890615702565b6007805460ff191690556001600160801b03821661233b5781604051633611668d60e21b81526004016108c8919061536a565b336001600160a01b03861614806123cf57506005546040516351c4bc1f60e11b81526001600160a01b039091169063a389783e9061237f908890339060040161571f565b60206040518083038186803b15801561239757600080fd5b505afa1580156123ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123cf9190615739565b6124275760405162461bcd60e51b8152602060048201526024808201527f6f6e6c79206d73672e73656e646572206f7220617070726f7665642063616e206044820152631b5a5b9d60e21b60648201526084016108c8565b6124686040518060800160405280876001600160a01b031681526020018660020b81526020018560020b8152602001610bb0856001600160801b0316612982565b90508260020b8460020b866001600160a01b03167f712faa344eac6399174fdfa887d9e1451e9b55ce58ee440c91c660229962a5a63386604051610bff929190615794565b6124b5612923565b6010805460ff191682151590811790915560405160ff909116151581527fa201234976cfdc556c03f06ca9366e09441724eae79256ad9da6b5f04cbdb05890602001612090565b604554610100900460ff161580801561251c5750604554600160ff909116105b8061253d575061252b30612914565b15801561253d575060455460ff166001145b6125a05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016108c8565b6045805460ff1916600117905580156125c3576045805461ff0019166101001790555b6001600160a01b0383166126025760405162461bcd60e51b815260206004820152600660248201526504d45203d20360d41b60448201526064016108c8565b60008260020b13801561261a5750614000600283900b125b61264e5760405162461bcd60e51b81526020600482015260056024820152642a29a7a7a160d91b60448201526064016108c8565b600380546001600160a01b0319166001600160a01b03851690811790915560408051634c7a58d960e11b815290516398f4b1b291600480820192602092909190829003018186803b1580156126a257600080fd5b505afa1580156126b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126da91906156a1565b600080546001600160a01b03929092166001600160a01b03199283161790556005805490911633179055600c805462ffffff841662ffffff1990911617908190556127279060020b613d7e565b600480546001600160801b0319166001600160801b03929092169190911781556003546040805163652c30b760e01b815290516001600160a01b039092169263652c30b7928282019260209290829003018186803b15801561278857600080fd5b505afa15801561279c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127c09190615876565b600155600354604080516324fb6d1560e21b815290516001600160a01b03909216916393edb45491600480820192602092909190829003018186803b15801561280857600080fd5b505afa15801561281c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128409190615876565b60025561284b613de6565b612853613e15565b8015612899576045805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6128a6612923565b6001600160a01b03811661290b5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016108c8565b610ce281613d2c565b6001600160a01b03163b151590565b3361292c612125565b6001600160a01b0316146120ad5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016108c8565b80600f81900b81146129c65760405162461bcd60e51b815260206004820152600d60248201526c746f496e74313238206f666c6f60981b60448201526064016108c8565b919050565b60006129df82602001518360400151612dc7565b6040805160608082018352600f80546001600160a01b0381168452600160a01b810460020b6020850152600160b81b900460ff1693830193909352840151909160009182910b15612a3957612a3385613e3c565b90925090505b600354600094506001600160a01b03163314612afb576003546040805163bfb5607d60e01b815287516001600160a01b0390811660048301526020890151600290810b60248401529289015190920b60448201526060880151600f0b606482015291169063bfb5607d90608401602060405180830381600087803b158015612ac057600080fd5b505af1158015612ad4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612af89190615876565b93505b60008560600151600f0b1215612b39578115612b22576020850151612b2290600d90613f1b565b8015612b39576040850151612b3990600d90613f1b565b6000805460408051637aa4db1360e01b815290516001600160a01b0390921692637aa4db139260048084019382900301818387803b158015612b7a57600080fd5b505af1158015612b8e573d6000803e3d6000fd5b505050508460600151600f0b600014612c2157846020015160020b836020015160020b12158015612bcc5750846040015160020b836020015160020b125b15612c21576000600760019054906101000a90046001600160801b03169050612bf9818760600151613cf5565b600760016101000a8154816001600160801b0302191690836001600160801b03160217905550505b505050919050565b600080516020615f54833981519152546001600160a01b031690565b610ce2612923565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612c805761289983613f54565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b815260040160206040518083038186803b158015612cb957600080fd5b505afa925050508015612ce9575060408051601f3d908101601f19168201909252612ce691810190615876565b60015b612d4c5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b60648201526084016108c8565b600080516020615f548339815191528114612dbb5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b60648201526084016108c8565b50612899838383613fee565b8060020b8260020b12612e025760405162461bcd60e51b8152602060048201526003602482015262544c5560e81b60448201526064016108c8565b62010deb19600283900b1215612e405760405162461bcd60e51b8152602060048201526003602482015262544c4d60e81b60448201526064016108c8565b612e4d62010deb1961588f565b60020b8160020b131561107a5760405162461bcd60e51b815260206004820152600360248201526254554d60e81b60448201526064016108c8565b8051600290810b600090815260208481526040808320918501805190940b83528083208551945191860151606087015160018086015490840154969795969395612ed89590949093929190614019565b95945050505050565b8051600290810b6000908152602084815260408083209185018051850b8452818420865191519287015160608801518588015497830154969795969295612ed89593614019565b8051600290810b600090815260208481526040808320918501805190940b835280832085519451918601516060870151949593949193612ed8939092909190612f7090613b87565b612f7d8760030154613b87565b612f8a8760030154613b87565b614019565b60006b0816769404766de590afe04e6001600160a01b03831610801590612fcb57506c1fa71f3f5f68a90479ee3f8fec6001600160a01b038316105b612fe75760405162461bcd60e51b81526004016108c89061582a565b600160201b600160c01b03602083901b166001600160801b03811160071b81811c6001600160401b03811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c60ff8111600390811b91821c600f811160021b90811c918211600190811b92831c9790881196179094179092171790911717176080811061308057613076607f826158a9565b83901c9150613091565b61308b81607f6158a9565b83901b91505b600060406130a06080846158c0565b901b9050828302607f1c92508260801c80603f1b8217915083811c935050828302607f1c92508260801c80603e1b8217915083811c935050828302607f1c92508260801c80603d1b8217915083811c935050828302607f1c92508260801c80603c1b8217915083811c935050828302607f1c92508260801c80603b1b8217915083811c935050828302607f1c92508260801c80603a1b8217915083811c935050828302607f1c92508260801c8060391b8217915083811c935050828302607f1c92508260801c8060381b8217915083811c935050828302607f1c92508260801c8060371b8217915083811c935050828302607f1c92508260801c8060361b8217915083811c935050828302607f1c92508260801c8060351b8217915083811c935050828302607f1c92508260801c8060341b8217915083811c935050828302607f1c92508260801c8060331b8217915083811c935050828302607f1c92508260801c8060321b8217915050600081693627a301d71055774c8561322391906159e7565b9050600060806132436f028f6481ab7f045a5af012a19d003aaa846158c0565b901d905060006080613265846fdb2df09e81959a81455e260799a0632f61595e565b901d90508060020b8260020b146132a457886001600160a01b0316613289826135b9565b6001600160a01b0316111561329e57816132a6565b806132a6565b815b9998505050505050505050565b60008169124bc0ddd92e560000006132c961394e565b6132d3919061591c565b101592915050565b60208301516132fd57604051631fa907d560e11b815260040160405180910390fd5b60075460ff1661332b57600754604051633cc7822f60e11b815260ff909116151560048201526024016108c8565b8061337f5781600001516001600160a01b031683604001516001600160a01b031610801561337a57506b0816769404766de590afe04e6001600160a01b031683604001516001600160a01b0316115b6133ca565b81600001516001600160a01b031683604001516001600160a01b03161180156133ca57506c1fa71f3f5f68a90479ee3f8fec6001600160a01b031683604001516001600160a01b0316105b6128995760405162461bcd60e51b815260206004820152600360248201526214d41360ea1b60448201526064016108c8565b6000808061340a8587615a6c565b905060008660020b12801561342a57506134248587615aa6565b60020b15155b1561343d578061343981615ac8565b9150505b83156134ea5760008061344f83614085565b90925090506000600160ff831681901b9061346a90826158a9565b613474919061591c565b600184900b600090815260208c9052604090205481168015159650909150856134b457886134a560ff85168761599f565b6134af9190615aec565b6134df565b886134be826140a2565b6134c89085615b79565b6134d59060ff168761599f565b6134df9190615aec565b9650505050506135af565b6000806135006134fb846001615b9c565b614085565b90925090506000613518600160ff841681901b6158a9565b600184900b600090815260208c905260409020549019908116801515965090915085613571578861354a8460ff615b79565b60ff16613558876001615b9c565b6135629190615b9c565b61356c9190615aec565b6135a8565b888361357c8361419f565b6135869190615b79565b60ff16613594876001615b9c565b61359e9190615b9c565b6135a89190615aec565b9650505050505b5094509492505050565b60008060008360020b126135d0578260020b6135dd565b8260020b6135dd906158ff565b90506135ec62010deb1961588f565b60020b8111156136225760405162461bcd60e51b81526020600482015260016024820152601560fa1b60448201526064016108c8565b60006001821661363657600160801b613648565b6ffffcb933bd6fad37aa2d162d1a5940015b6001600160881b03169050600282161561367d576080613678826ffff97272373d413259a46990580e213a615be3565b901c90505b60048216156136a75760806136a2826ffff2e50f5f656932ef12357cf3c7fdcc615be3565b901c90505b60088216156136d15760806136cc826fffe5caca7e10e4e61c3624eaa0941cd0615be3565b901c90505b60108216156136fb5760806136f6826fffcb9843d60f6159c9db58835c926644615be3565b901c90505b6020821615613725576080613720826fff973b41fa98c081472e6896dfb254c0615be3565b901c90505b604082161561374f57608061374a826fff2ea16466c96a3843ec78b326b52861615be3565b901c90505b6080821615613779576080613774826ffe5dee046a99a2a811c461f1969c3053615be3565b901c90505b6101008216156137a457608061379f826ffcbe86c7900a88aedcffc83b479aa3a4615be3565b901c90505b6102008216156137cf5760806137ca826ff987a7253ac413176f2b074cf7815e54615be3565b901c90505b6104008216156137fa5760806137f5826ff3392b0822b70005940c7a398e4b70f3615be3565b901c90505b610800821615613825576080613820826fe7159475a2c29b7443b29c7fa6e889d9615be3565b901c90505b61100082161561385057608061384b826fd097f3bdfd2022b8845ad8f792aa5825615be3565b901c90505b61200082161561387b576080613876826fa9f746462d870fdf8a65dc1f90e061e5615be3565b901c90505b6140008216156138a65760806138a1826f70d869a156d2a1b890bb3df62baf32f7615be3565b901c90505b6180008216156138d15760806138cc826f31be135f97d08fd981231505542fcfa6615be3565b901c90505b620100008216156138fd5760806138f8826f09aa508b5b7a84e1c677de54f3e99bc9615be3565b901c90505b60008460020b1315613918576139158160001961594a565b90505b613926600160201b82615c02565b15613932576001613935565b60005b6139469060ff16602083901c61591c565b949350505050565b6000613959426142dc565b905090565b6020810151815160608301516000928392839283926001600160a01b039081169216919091101590828112801591840390613a0757826139b6576139b1886000015189602001518a604001516001614329565b6139cf565b6139cf886020015189600001518a604001516001614399565b9550858860600151106139e85787602001519650613a6f565b613a00886000015189604001518a606001518661449c565b9650613a6f565b82613a2a57613a25886000015189602001518a604001516000614399565b613a43565b613a43886020015189600001518a604001516000614329565b9450848110613a585787602001519650613a6f565b613a6c88600001518960400151838661450e565b96505b60208801516001600160a01b0388811691161460008415613aeb57818015613a945750835b613ab257613aad898b600001518c604001516001614399565b613ab4565b875b9750818015613ac1575083155b613adf57613ada898b600001518c604001516000614329565b613ae1565b865b9650869050613b48565b818015613af55750835b613b1357613b0e8a600001518a8c604001516001614329565b613b15565b875b9750818015613b22575083155b613b4057613b3b8a600001518a8c604001516000614399565b613b42565b865b96508790505b83158015613b5557508287115b15613b5e578296505b613b79613b6a826142dc565b8b60a001518c60800151614580565b955050505050509193509193565b6000600160ff1b8210613bcc5760405162461bcd60e51b815260206004820152600d60248201526c746f496e74323536206f666c6f60981b60448201526064016108c8565b5090565b600080600080613bf68560c00151600160801b8860c001516001600160801b03166145bb565b8660e00151613c05919061591c565b9350613c27856101000151866101400151886101a001516001546002546146b9565b9050613c4a856101400151600160801b8860c001516001600160801b031661473e565b8660a00151613c59919061595e565b9250613c7781600160801b8860c001516001600160801b031661473e565b8660800151613c86919061595e565b915092959194509250565b600284900b60009081526020869052604081206003810154613cb390846158a9565b60038201556001810154613cc790866158c0565b60018201556002810154613cdb90856158c0565b600282015554600160801b9004600f0b9695505050505050565b60008082600f0b1215613d19576000829003613d118185615c16565b915050613d26565b613d238284615c3e565b90505b92915050565b607880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600080613d8f8362010deb19615aa6565b613d9d9062010deb1961599f565b90506000613daa8261588f565b9050600084613db9848461599f565b613dc39190615a6c565b613dce906001615c69565b9050612ed862ffffff82166001600160801b03615c87565b604554610100900460ff16613e0d5760405162461bcd60e51b81526004016108c890615cad565b6120ad614776565b604554610100900460ff166120ad5760405162461bcd60e51b81526004016108c890615cad565b600080613e5183602001518460400151612dc7565b6020830151600f546060850151600a54600b54600854600454613e9696600d969095600160a01b90910460020b949093909290916000906001600160801b03166147a6565b6040840151600f546060860151600a54600b54600854600454969850613eda96600d9695600160a01b900460020b94939291906001906001600160801b03166147a6565b90508115613ef9576020830151600c54613ef991600e9160020b61493b565b8015613f16576040830151600c54613f1691600e9160020b61493b565b915091565b600290810b600090815260209290925260408220828155600181018390559081018290556003810191909155600401805460ff19169055565b613f5d81612914565b613fbf5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016108c8565b600080516020615f5483398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b613ff7836149d0565b6000825111806140045750805b15612899576140138383614a10565b50505050565b6000808760020b8660020b1261403057508261403d565b61403a84866158c0565b90505b60008760020b8760020b1215614054575082614061565b61405e84876158c0565b90505b600061406d828461595e565b61407790886158c0565b9a9950505050505050505050565b600281900b60081d600061409b61010084615aa6565b9050915091565b60008082116140c35760405162461bcd60e51b81526004016108c890615cf8565b600160801b82106140e157608091821c916140de9082615d1f565b90505b600160401b82106140ff57604091821c916140fc9082615d1f565b90505b600160201b821061411d57602091821c9161411a9082615d1f565b90505b62010000821061413a57601091821c916141379082615d1f565b90505b610100821061415657600891821c916141539082615d1f565b90505b6010821061417157600491821c9161416e9082615d1f565b90505b6004821061418c57600291821c916141899082615d1f565b90505b600282106129c657613d26600182615d1f565b60008082116141c05760405162461bcd60e51b81526004016108c890615cf8565b5060ff6001600160801b038216156141e4576141dd608082615b79565b90506141ec565b608082901c91505b6001600160401b0382161561420d57614206604082615b79565b9050614215565b604082901c91505b63ffffffff8216156142335761422c602082615b79565b905061423b565b602082901c91505b61ffff82161561425757614250601082615b79565b905061425f565b601082901c91505b60ff82161561427a57614273600882615b79565b9050614282565b600882901c91505b600f82161561429d57614296600482615b79565b90506142a5565b600482901c91505b60038216156142c0576142b9600282615b79565b90506142c8565b600282901c91505b60018216156129c657613d26600182615b79565b60007812725dd1d243aba0e75fe645cc4873f9e65afe688c928e1f2182111561431b57604051633492ffd960e01b8152600481018390526024016108c8565b50670de0b6b3a76400000290565b6000836001600160a01b0316856001600160a01b03161115614349579293925b8161437657614371836001600160801b03168686036001600160a01b0316600160601b6145bb565b612ed8565b612ed8836001600160801b03168686036001600160a01b0316600160601b614af9565b6000836001600160a01b0316856001600160a01b031611156143b9579293925b600160601b600160e01b03606084901b1660006143d68787615d44565b6001600160a01b031690506000876001600160a01b03161161442f5760405162461bcd60e51b8152602060048201526012602482015271073717274526174696f4158393620213e20360741b60448201526064016108c8565b8361446557866001600160a01b03166144528383896001600160a01b03166145bb565b8161445f5761445f615934565b04614491565b61449161447c8383896001600160a01b0316614af9565b886001600160a01b0316808204910615150190565b979650505050505050565b600080856001600160a01b0316116144c65760405162461bcd60e51b81526004016108c890615d64565b6000846001600160801b0316116144ef5760405162461bcd60e51b81526004016108c890615d8b565b81614501576143718585856001614b4c565b612ed88585856001614c65565b600080856001600160a01b0316116145385760405162461bcd60e51b81526004016108c890615d64565b6000846001600160801b0316116145615760405162461bcd60e51b81526004016108c890615d8b565b81614573576143718585856000614c65565b612ed88585856000614b4c565b60008061458c84614db1565b905060006145a38661459e8685614dc8565b614dc8565b9050670de0b6b3a764000081045b9695505050505050565b60008080600019858709858702925082811083820303915050806000141561462b57600084116146205760405162461bcd60e51b815260206004820152601060248201526f4469766973696f6e206279207a65726f60801b60448201526064016108c8565b5082900490506146b2565b80841161464a5760405162461bcd60e51b81526004016108c890615dad565b600084868809851960019081018716968790049682860381900495909211909303600082900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b60008282116146da5760405162461bcd60e51b81526004016108c890615dcf565b851580156146e6575084155b156146f357506000612ed8565b60006146fe87614dd4565b9050600061470b87614dd4565b9050600061471c8383898989614e51565b9050600061472c84838989614e7d565b9050670de0b6b3a76400008105614077565b60008084121561476b5761475b614754856158ff565b84846145bb565b614764906158ff565b90506146b2565b6139468484846145bb565b604554610100900460ff1661479d5760405162461bcd60e51b81526004016108c890615cad565b6120ad33613d2c565b600288900b600090815260208a90526040812080546001600160801b0316826147cf8a83615ded565b600f0b121561481f5760405162461bcd60e51b815260206004820152601c60248201527b3737ba1032b737bab3b4103634b8bab4b234ba3c903a3790313ab93760211b60448201526064016108c8565b600061482b828b613cf5565b9050846001600160801b0316816001600160801b031611156148745760405162461bcd60e51b81526020600482015260026024820152614c4f60f01b60448201526064016108c8565b6001600160801b0382811615908216158114159450156148c1578a60020b8c60020b136148b1576003830187905560018301899055600283018890555b60048301805460ff191660011790555b82546001600160801b0319166001600160801b038216178355856148fb5782546148f6908b90600160801b9004600f0b615ded565b614912565b8254614912908b90600160801b9004600f0b615e35565b83546001600160801b03918216600160801b0291161790925550909a9950505050505050505050565b6149458183615aa6565b60020b156149945760405162461bcd60e51b815260206004820152601c60248201527b1d1a58dac81b5d5cdd081899481c1c9bdc195c9b1e481cdc1858d95960221b60448201526064016108c8565b6000806149a46134fb8486615a6c565b600191820b60009081526020979097526040909620805460ff9097169190911b90951890945550505050565b6149d981613f54565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060614a1b83612914565b614a765760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016108c8565b600080846001600160a01b031684604051614a919190615ea7565b600060405180830381855af49150503d8060008114614acc576040519150601f19603f3d011682016040523d82523d6000602084013e614ad1565b606091505b5091509150612ed88282604051806060016040528060278152602001615f7460279139614ebe565b6000614b068484846145bb565b905060008280614b1857614b18615934565b84860911156146b2576000198110614b425760405162461bcd60e51b81526004016108c890615dad565b80612ed881615ec3565b60008115614bb65760006001600160a01b03841115614b8257614b7d84600160601b876001600160801b03166145bb565b614b99565b614b996001600160801b038616606086901b61594a565b9050614ba481614ef7565b614bae9087615ede565b915050613946565b60006001600160a01b03841115614be457614bdf84600160601b876001600160801b0316614af9565b614c01565b614c01606085901b6001600160801b038716808204910615150190565b905080866001600160a01b031611614c525760405162461bcd60e51b81526020600482015260146024820152731cdc5c9d14160e4d88084f881c5d5bdd1a595b9d60621b60448201526064016108c8565b614bae816001600160a01b0388166158a9565b600082614c73575083613946565b600160601b600160e01b03606085901b168215614d1e5760006001600160a01b03871685614ca18282615be3565b9250614cad908361594a565b1415614ce8576000614cbf828461591c565b9050828110614ce657614cdc83896001600160a01b031683614af9565b9350505050613946565b505b614d158286614d006001600160a01b038b168361594a565b614d0a919061591c565b808204910615150190565b92505050613946565b60006001600160a01b03871685614d358282615be3565b9250614d41908361594a565b148015614d4d57508082115b614d875760405162461bcd60e51b815260206004820152600b60248201526a64656e6f6d2075666c6f7760a81b60448201526064016108c8565b6000614d9382846158a9565b9050614cdc614dac848a6001600160a01b031684614af9565b614ef7565b6000613d26826a1a1601fc4ea7109e000000614f41565b6000613d238383614f56565b60007809392ee8e921d5d073aff322e62439fcf32d7f344649470f8f19821215614e145760405163e608e18b60e01b8152600481018390526024016108c8565b7809392ee8e921d5d073aff322e62439fcf32d7f344649470f9082131561431b576040516371f72a3160e01b8152600481018390526024016108c8565b6000614e5d8585615018565b614e73614e6c600086866150dd565b8890615018565b6145b1919061595e565b6000828211614e9e5760405162461bcd60e51b81526004016108c890615dcf565b614eb4614ead600185856150dd565b859061518f565b612ed890866158c0565b60608315614ecd5750816146b2565b825115614edd5782518084602001fd5b8160405162461bcd60e51b81526004016108c89190615f00565b806001600160a01b03811681146129c65760405162461bcd60e51b815260206004820152600e60248201526d746f55696e74313630206f666c6f60901b60448201526064016108c8565b6000613d2383670de0b6b3a764000084615255565b60008080600019848609848602925082811083820303915050670de0b6b3a76400008110614f9a5760405163698d9a0160e11b8152600481018290526024016108c8565b600080670de0b6b3a76400008688099150506706f05b59d3b1ffff811182614fd45780670de0b6b3a7640000850401945050505050613d26565b620400008285030493909111909103600160ee1b02919091177faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106690201905092915050565b6000600160ff1b83148061502f5750600160ff1b82145b1561504d57604051630d01a11b60e21b815260040160405180910390fd5b6000806000851261505e5784615063565b846000035b9150600084126150735783615078565b836000035b905060006150868383614f56565b90506001600160ff1b038111156150b35760405163bf79e8d960e01b8152600481018290526024016108c8565b6000198087139086138082186001146150cc57826150d1565b826000035b98975050505050505050565b60008282116150fe5760405162461bcd60e51b81526004016108c890615dcf565b600061510861394e565b9050838110156151425760405162461bcd60e51b8152602060048201526005602482015264422e543c5360d81b60448201526064016108c8565b600085806151505750838210155b156151665761515f85856158a9565b9050615173565b61517085836158a9565b90505b6145b168056bc75e2d6310000061518983614db1565b90614f41565b6000600160ff1b8314806151a65750600160ff1b82145b156151c45760405163b3c754a360e01b815260040160405180910390fd5b600080600085126151d557846151da565b846000035b9150600084126151ea57836151ef565b836000035b9050600061520683670de0b6b3a764000084615255565b90506001600160ff1b0381111561523357604051637cb4bef560e01b8152600481018290526024016108c8565b60001980871390861380821860011461524c57826150d1565b6150d1836158ff565b6000808060001985870985870292508281108382030391505080600014156152905783828161528657615286615934565b04925050506146b2565b83811061464a57604051631dcf306360e21b815260048101829052602481018590526044016108c8565b60405180610160016040528060006001600160a01b03168152602001600060020b815260200160001515815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6001600160a01b0391909116815260200190565b8015158114610ce257600080fd5b60006020828403121561535f57600080fd5b81356146b28161533f565b6001600160801b0391909116815260200190565b6001600160a01b0381168114610ce257600080fd5b8035600281900b81146129c657600080fd5b600080600080608085870312156153bb57600080fd5b84356153c68161537e565b93506153d460208601615393565b92506153e260408601615393565b915060608501356001600160801b03811681146153fe57600080fd5b939692955090935050565b60006020828403121561541b57600080fd5b81356146b28161537e565b6000806040838503121561543957600080fd5b61544283615393565b915061545060208401615393565b90509250929050565b6000806040838503121561546c57600080fd5b82356154778161537e565b915060208301356154878161533f565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156154d0576154d0615492565b604052919050565b600080604083850312156154eb57600080fd5b82356154f68161537e565b91506020838101356001600160401b038082111561551357600080fd5b818601915086601f83011261552757600080fd5b81358181111561553957615539615492565b61554b601f8201601f191685016154a8565b9150808252878482850101111561556157600080fd5b80848401858401376000848284010152508093505050509250929050565b60006020828403121561559157600080fd5b81358060010b81146146b257600080fd5b600060a082840312156155b457600080fd5b60405160a081016001600160401b03811182821017156155d6576155d6615492565b60405282356155e48161537e565b81526020838101359082015260408301356155fe8161537e565b604082015261560f60608401615393565b606082015261562060808401615393565b60808201529392505050565b60006020828403121561563e57600080fd5b5035919050565b60006020828403121561565757600080fd5b813560ff811681146146b257600080fd5b6000806040838503121561567b57600080fd5b82356154428161537e565b60006020828403121561569857600080fd5b613d2382615393565b6000602082840312156156b357600080fd5b81516146b28161537e565b6020808252600a90820152697070687279206f6e6c7960b01b604082015260600190565b60208082526006908201526514185d5cd95960d21b604082015260600190565b6020808252600390820152624c4f4b60e81b604082015260600190565b6001600160a01b0392831681529116602082015260400190565b60006020828403121561574b57600080fd5b81516146b28161533f565b634e487b7160e01b600052601160045260246000fd5b6000600f82900b60016001607f1b031981141561578b5761578b615756565b60000392915050565b6001600160a01b039290921682526001600160801b0316602082015260400190565b6020808252602c90820152600080516020615f3483398151915260408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c90820152600080516020615f3483398151915260408201526b6163746976652070726f787960a01b606082015260800190565b6020808252600190820152602960f91b604082015260600190565b602080825260179082015276636c6f7365546f4f724265796f6e644d6174757269747960481b604082015260600190565b60006020828403121561588857600080fd5b5051919050565b60008160020b627fffff1981141561578b5761578b615756565b6000828210156158bb576158bb615756565b500390565b60008083128015600160ff1b8501841216156158de576158de615756565b6001600160ff1b03840183138116156158f9576158f9615756565b50500390565b6000600160ff1b82141561591557615915615756565b5060000390565b6000821982111561592f5761592f615756565b500190565b634e487b7160e01b600052601260045260246000fd5b60008261595957615959615934565b500490565b600080821280156001600160ff1b038490038513161561598057615980615756565b600160ff1b839003841281161561599957615999615756565b50500190565b60008160020b8360020b6000811281627fffff19018312811516156159c6576159c6615756565b81627fffff0183138116156159dd576159dd615756565b5090039392505050565b60006001600160ff1b0381841382841380821686840486111615615a0d57615a0d615756565b600160ff1b6000871282811687830589121615615a2c57615a2c615756565b60008712925087820587128484161615615a4857615a48615756565b87850587128184161615615a5e57615a5e615756565b505050929093029392505050565b60008160020b8360020b80615a8357615a83615934565b627fffff19821460001982141615615a9d57615a9d615756565b90059392505050565b60008260020b80615ab957615ab9615934565b808360020b0791505092915050565b60008160020b627fffff19811415615ae257615ae2615756565b6000190192915050565b60008160020b8360020b627fffff600082136000841383830485118282161615615b1857615b18615756565b627fffff196000851282811687830587121615615b3757615b37615756565b60008712925085820587128484161615615b5357615b53615756565b85850587128184161615615b6957615b69615756565b5050509290910295945050505050565b600060ff821660ff841680821015615b9357615b93615756565b90039392505050565b60008160020b8360020b6000821282627fffff03821381151615615bc257615bc2615756565b82627fffff19038212811615615bda57615bda615756565b50019392505050565b6000816000190483118215151615615bfd57615bfd615756565b500290565b600082615c1157615c11615934565b500690565b60006001600160801b0383811690831681811015615c3657615c36615756565b039392505050565b60006001600160801b03828116848216808303821115615c6057615c60615756565b01949350505050565b600062ffffff808316818516808303821115615c6057615c60615756565b60006001600160801b0383811680615ca157615ca1615934565b92169190910492915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6020808252600d908201526c078206d757374206265203e203609c1b604082015260600190565b600060ff821660ff84168060ff03821115615d3c57615d3c615756565b019392505050565b60006001600160a01b0383811690831681811015615c3657615c36615756565b6020808252600d908201526c0737172745058393620213e203609c1b604082015260600190565b60208082526008908201526706c697120213e20360c41b604082015260600190565b6020808252600890820152676f766572666c6f7760c01b604082015260600190565b602080825260049082015263453c3d5360e01b604082015260600190565b6000600f82810b9084900b828212801560016001607f1b0384900383131615615e1857615e18615756565b60016001607f1b03198390038212811615615bda57615bda615756565b6000600f82810b9084900b828112801560016001607f1b0319830184121615615e6057615e60615756565b60016001607f1b03820183138116156159dd576159dd615756565b60005b83811015615e96578181015183820152602001615e7e565b838111156140135750506000910152565b60008251615eb9818460208701615e7b565b9190910192915050565b6000600019821415615ed757615ed7615756565b5060010190565b60006001600160a01b03828116848216808303821115615c6057615c60615756565b6020815260008251806020840152615f1f816040850160208701615e7b565b601f01601f1916919091016040019291505056fe46756e6374696f6e206d7573742062652063616c6c6564207468726f75676820360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220149cb7e322dff3690c8ff73093f6f3a2452ba3d82b3f150c137603de9ccad4d564736f6c63430008090033

Deployed Bytecode

0x6080604052600436106101a95760003560e01c80624006e0146101ae57806309d7b622146101de5780630bd9c1af146101fd5780630d211954146102145780631a686502146102345780631ad8b03b146102605780631b398e06146102755780631f2f0893146102a95780633659cfe6146102c95780633c8f233e146102e9578063478de3241461032457806347f75ede146103445780634e65b408146103645780634f1ef2861461037957806352d1902d1461038c5780635339c296146103a15780635c975abb146103d157806367758e6e146103fb57806369fe0e2d1461044357806370cf754a14610463578063715018a614610481578063778762361461049657806380a0f76c146104b4578063867377101461054f578063884287521461056f5780638da5cb5b14610587578063ad23b4161461059c578063b613a141146105b1578063b8cca34e146105d1578063bc063e1a146105f1578063c45a01551461060c578063cd41b3d51461062a578063d0c93a7c1461064a578063d992d9081461066d578063f2fde38b1461068d578063f30dba93146106ad578063f3f94990146107be575b600080fd5b3480156101ba57600080fd5b506003546001600160a01b03165b6040516101d5919061532b565b60405180910390f35b3480156101ea57600080fd5b50600a545b6040519081526020016101d5565b34801561020957600080fd5b506102126107d3565b005b34801561022057600080fd5b5061021261022f36600461534d565b610883565b34801561024057600080fd5b5060075461010090046001600160801b03165b6040516101d5919061536a565b34801561026c57600080fd5b506009546101ef565b34801561028157600080fd5b506101ef7fc02e2d3f2633adb184196f6ae17c8476d7912f8727b7c1cc7da0b7ddac86bc6581565b3480156102b557600080fd5b506101ef6102c43660046153a5565b610942565b3480156102d557600080fd5b506102126102e4366004615409565b610c1c565b3480156102f557600080fd5b50610309610304366004615426565b610ce5565b604080519384526020840192909252908201526060016101d5565b34801561033057600080fd5b5061021261033f366004615459565b610dc3565b34801561035057600080fd5b5061021261035f366004615409565b610df6565b34801561037057600080fd5b50600b546101ef565b6102126103873660046154d8565b610fc4565b34801561039857600080fd5b506101ef61107e565b3480156103ad57600080fd5b506101ef6103bc36600461557f565b60010b6000908152600e602052604090205490565b3480156103dd57600080fd5b506012546103eb9060ff1681565b60405190151581526020016101d5565b34801561040757600080fd5b5061041b6104163660046155a2565b61112c565b604080519586526020860194909452928401919091526060830152608082015260a0016101d5565b34801561044f57600080fd5b5061021261045e36600461562c565b612014565b34801561046f57600080fd5b506004546001600160801b0316610253565b34801561048d57600080fd5b5061021261209b565b3480156104a257600080fd5b506000546001600160a01b03166101c8565b3480156104c057600080fd5b5061051e60408051606081018252600080825260208201819052918101919091525060408051606081018252600f546001600160a01b0381168252600160a01b810460020b6020830152600160b81b900460ff169181019190915290565b6040805182516001600160a01b0316815260208084015160020b908201529181015160ff16908201526060016101d5565b34801561055b57600080fd5b5061021261056a36600461562c565b6120af565b34801561057b57600080fd5b5060105460ff166103eb565b34801561059357600080fd5b506101c8612125565b3480156105a857600080fd5b506008546101ef565b3480156105bd57600080fd5b506102126105cc366004615645565b612134565b3480156105dd57600080fd5b506101ef6105ec3660046153a5565b6121e4565b3480156105fd57600080fd5b506101ef66470de4df82000081565b34801561061857600080fd5b506005546001600160a01b03166101c8565b34801561063657600080fd5b5061021261064536600461534d565b6124ad565b34801561065657600080fd5b50600c5460405160029190910b81526020016101d5565b34801561067957600080fd5b50610212610688366004615668565b6124fc565b34801561069957600080fd5b506102126106a8366004615409565b61289e565b3480156106b957600080fd5b506107696106c8366004615686565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915250600290810b6000908152600d6020908152604091829020825160c08101845281546001600160801b0381168252600160801b9004600f0b92810192909252600181015492820192909252918101546060830152600381015460808301526004015460ff16151560a082015290565b6040516101d5919081516001600160801b03168152602080830151600f0b9082015260408083015190820152606080830151908201526080828101519082015260a09182015115159181019190915260c00190565b3480156107ca57600080fd5b506006546101ef565b6107db612923565b600360009054906101000a90046001600160a01b03166001600160a01b03166398f4b1b26040518163ffffffff1660e01b815260040160206040518083038186803b15801561082957600080fd5b505afa15801561083d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086191906156a1565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b3360009081526011602052604090205460ff166108d15760405162461bcd60e51b81526020600482015260076024820152666e6f20726f6c6560c81b60448201526064015b60405180910390fd5b6012805460ff1916821515908117909155600354604051630348465560e21b815260048101929092526001600160a01b031690630d21195490602401600060405180830381600087803b15801561092757600080fd5b505af115801561093b573d6000803e3d6000fd5b5050505050565b60105460009060ff1615610a0e5760055460408051633bd5670d60e11b815290516000926001600160a01b0316916377aace1a916004808301926020929190829003018186803b15801561099557600080fd5b505afa1580156109a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109cd91906156a1565b9050336001600160a01b03821614806109f057506003546001600160a01b031633145b610a0c5760405162461bcd60e51b81526004016108c8906156be565b505b60125460ff1615610a315760405162461bcd60e51b81526004016108c8906156e2565b60075460ff16610a535760405162461bcd60e51b81526004016108c890615702565b6007805460ff191690556001600160801b038216610a86578160405163c09d260960e01b81526004016108c8919061536a565b336001600160a01b0386161480610aa757506003546001600160a01b031633145b80610b2f57506005546040516351c4bc1f60e11b81526001600160a01b039091169063a389783e90610adf908890339060040161571f565b60206040518083038186803b158015610af757600080fd5b505afa158015610b0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2f9190615739565b610b665760405162461bcd60e51b81526020600482015260086024820152674d53206f72204d4560c01b60448201526064016108c8565b610bba6040518060800160405280876001600160a01b031681526020018660020b81526020018560020b8152602001610ba7856001600160801b0316612982565b610bb09061576c565b600f0b90526129cb565b90508260020b8460020b866001600160a01b03167ff57f161c6404e7a58d089003a260456719af3caac502550a59509b4c9d8d46283386604051610bff929190615794565b60405180910390a46007805460ff19166001179055949350505050565b306001600160a01b037f00000000000000000000000055a6c7c923b33b4b4cb119c5ee3f10cf841f4e18161415610c655760405162461bcd60e51b81526004016108c8906157b6565b7f00000000000000000000000055a6c7c923b33b4b4cb119c5ee3f10cf841f4e186001600160a01b0316610c97612c29565b6001600160a01b031614610cbd5760405162461bcd60e51b81526004016108c8906157f0565b610cc681612c45565b60408051600080825260208201909252610ce291839190612c4d565b50565b6000806000610cf48585612dc7565b60408051608081018252600287810b825286810b6020830152600f54600160a01b9004900b91810191909152600a546060820152610d3490600d90612e88565b60408051608081018252600288810b825287810b6020830152600f54600160a01b9004900b91810191909152600b546060820152909350610d7790600d90612ee1565b60408051608081018252600288810b825287810b6020830152600f54600160a01b9004900b918101919091526008546060820152909250610dba90600d90612f28565b90509250925092565b610dcb612923565b6001600160a01b03919091166000908152601160205260409020805460ff1916911515919091179055565b6001600160a01b038116610e3f5760405162461bcd60e51b815260206004820152601060248201526f7a65726f20696e70757420707269636560801b60448201526064016108c8565b6c1fa71f3f5f68a90479ee3f8fec6001600160a01b038216108015610e7957506b0816769404766de590afe04e6001600160a01b03821610155b610e955760405162461bcd60e51b81526004016108c89061582a565b6003546001600160a01b0316610ee45760405162461bcd60e51b81526020600482015260146024820152731d985b5b481b9bdd081a5b9a5d1a585b1a5e995960621b60448201526064016108c8565b600f546001600160a01b031615610f1b57600f546040516328be1c0f60e21b81526108c8916001600160a01b03169060040161532b565b6000610f2682612f8f565b604080516060810182526001600160a01b038516808252600284900b6020808401829052600093850193909352600f80546001600160b81b0319168317600160a01b62ffffff8816021760ff60b81b191690556007805460ff191660011790558351918252918101919091529192507facf59ced105c47c72de67aa00ab58b6415014ad6018644e3e8d8ca6862ec0dce910160405180910390a15050565b306001600160a01b037f00000000000000000000000055a6c7c923b33b4b4cb119c5ee3f10cf841f4e1816141561100d5760405162461bcd60e51b81526004016108c8906157b6565b7f00000000000000000000000055a6c7c923b33b4b4cb119c5ee3f10cf841f4e186001600160a01b031661103f612c29565b6001600160a01b0316146110655760405162461bcd60e51b81526004016108c8906157f0565b61106e82612c45565b61107a82826001612c4d565b5050565b6000306001600160a01b037f00000000000000000000000055a6c7c923b33b4b4cb119c5ee3f10cf841f4e1816146111195760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c6044820152771b1959081d1a1c9bdd59da0819195b1959d85d1958d85b1b60421b60648201526084016108c8565b50600080516020615f5483398151915290565b601254600090819081908190819060ff161561115a5760405162461bcd60e51b81526004016108c8906156e2565b6111656002546132b3565b156111825760405162461bcd60e51b81526004016108c890615845565b61119486606001518760800151612dc7565b60408051606081018252600f546001600160a01b0381168252600160a01b810460020b602080840191909152600160b81b90910460ff1692820192909252908701516111e690889083906000126132db565b6003546001600160a01b03163314806112955750600360009054906101000a90046001600160a01b03166001600160a01b03166322d23b216040518163ffffffff1660e01b815260040160206040518083038186803b15801561124857600080fd5b505afa15801561125c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128091906156a1565b6001600160a01b0316336001600160a01b0316145b6113865786516001600160a01b031633148061132e575060055487516040516351c4bc1f60e11b81526001600160a01b039092169163a389783e916112de91339060040161571f565b60206040518083038186803b1580156112f657600080fd5b505afa15801561130a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061132e9190615739565b6113865760405162461bcd60e51b815260206004820152602360248201527f6f6e6c792073656e646572206f7220617070726f76656420696e74656772617460448201526234b7b760e91b60648201526084016108c8565b6007805460ff1916908190556040805180820182526001600160801b036101009384900481168252600f54600160b81b900460ff1660208084019190915283516101c0810185528c8201518152600081830181905287516001600160a01b039081168388015292880151600290810b6060840152600a546080840152600b5460a0840152855190941660c083015260085460e083015295810186905261012081018690526101408101869052610160810186905261018081018690528554600154935495516325f258dd60e01b815294969591946101a086019491909316926325f258dd926114819291600401918252602082015260400190565b602060405180830381600087803b15801561149b57600080fd5b505af11580156114af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d39190615876565b815250905060008054906101000a90046001600160a01b03166001600160a01b0316637aa4db136040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561152657600080fd5b505af115801561153a573d6000803e3d6000fd5b50505050600089602001511315611911575b805115801590611576575088604001516001600160a01b031681604001516001600160a01b031614155b1561190c576115836152ba565b60408201516001600160a01b031681526060820151600c546115ac91600e9160020b60006133fc565b1515604083015260020b60208201526115c862010deb1961588f565b60020b816020015160020b13156115ef576115e662010deb1961588f565b60020b60208201525b6115fc81602001516135b9565b81606001906001600160a01b031690816001600160a01b0316815250506116b76040518060c0016040528084604001516001600160a01b031681526020018c604001516001600160a01b031684606001516001600160a01b03161161166557836060015161166b565b8c604001515b6001600160a01b0316815260c08501516001600160801b031660208201528451604082015260065460608201526080016116a361394e565b6002546116b091906158a9565b905261395e565b60c085015260a0840152608083019081526001600160a01b039091166040840152516116e290613b87565b825183906116f19083906158c0565b90525060a081015161170290613b87565b8260200181815161171391906158c0565b905250608081015161172490613b87565b61014082015260a081015161173890613b87565b611741906158ff565b61010082015260c08101516101208301805161175e90839061591c565b905250602083015160ff16156117bb57826020015160ff168160c00151611785919061594a565b60e0820181905260c08201805161179d9083906158a9565b90525060e0810151610100830180516117b790839061591c565b9052505b60c08201516001600160801b031615611845576117d88282613bd0565b6101208501908152608086019190915260a085019190915260e0840191909152516101408301805161180b9083906158c0565b905250610140810151610160830180516118269083906158c0565b905250610100810151610180830180516118419083906158c0565b9052505b80606001516001600160a01b031682604001516001600160a01b031614156118cf578060400151156118bd57600061189d826020015184608001518560a001518660e00151600d613c9190949392919063ffffffff16565b90506118ad8360c0015182613cf5565b6001600160801b031660c0840152505b602081015160020b6060830152611906565b80600001516001600160a01b031682604001516001600160a01b031614611906576118fd8260400151612f8f565b60020b60608301525b5061154c565b611c7c565b80511580159061193b575088604001516001600160a01b031681604001516001600160a01b031614155b15611c7c576119486152ba565b60408201516001600160a01b031681526060820151600c5461197191600e9160020b60016133fc565b1515604083015260020b6020820181905262010deb1913156119985762010deb1960208201525b6119a581602001516135b9565b81606001906001600160a01b031690816001600160a01b031681525050611a0e6040518060c0016040528084604001516001600160a01b031681526020018c604001516001600160a01b031684606001516001600160a01b03161061166557836060015161166b565b60c085015260a0840190815260808401919091526001600160a01b03909116604084015251611a3c90613b87565b82518390611a4b90839061595e565b9052506080810151611a5c90613b87565b82602001818151611a6d919061595e565b90525060a0810151611a7e90613b87565b611a87906158ff565b6101408201526080810151611a9b90613b87565b61010082015260c0810151610120830151611ab6919061591c565b610120830152602083015160ff1615611b1657826020015160ff168160c00151611ae0919061594a565b60e0820181905260c082018051611af89083906158a9565b90525060e081015161010083018051611b1290839061591c565b9052505b60c08201516001600160801b031615611ba057611b338282613bd0565b6101208501908152608086019190915260a085019190915260e08401919091525161014083018051611b669083906158c0565b90525061014081015161016083018051611b819083906158c0565b90525061010081015161018083018051611b9c9083906158c0565b9052505b80606001516001600160a01b031682604001516001600160a01b03161415611c3f57806040015115611c21576000611bf8826020015184608001518560a001518660e00151600d613c9190949392919063ffffffff16565b9050611c118360c0015182611c0c9061576c565b613cf5565b6001600160801b031660c0840152505b60018160200151611c32919061599f565b60020b6060830152611c76565b80600001516001600160a01b031682604001516001600160a01b031614611c7657611c6d8260400151612f8f565b60020b60608301525b50611911565b6040810151600f80546001600160a01b0319166001600160a01b0390921691909117905560208301516060820151600291820b910b14611cde576060810151600f805462ffffff909216600160a01b0262ffffff60a01b199092169190911790555b8060c001516001600160801b031682600001516001600160801b031614611d2b5760c0810151600780546001600160801b0390921661010002610100600160881b03199092169190911790555b60e081015160085560a0810151600b556080810151600a55610120810151610140820151610160830151610180840151610100850151929b5090995091975090955015611d8f5780610100015160096000828254611d89919061591c565b90915550505b6003546001600160a01b0316331480611e3e5750600360009054906101000a90046001600160a01b03166001600160a01b03166322d23b216040518163ffffffff1660e01b815260040160206040518083038186803b158015611df157600080fd5b505afa158015611e05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2991906156a1565b6001600160a01b0316336001600160a01b0316145b611f1457600354895160608b015160808c015161014085015161016086015161012087015161018088015160405163604b0bd760e11b81526001600160a01b039788166004820152600296870b60248201529490950b60448501526064840192909252608483015260a482015260c481019190915291169063c09617ae9060e401602060405180830381600087803b158015611ed957600080fd5b505af1158015611eed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f119190615876565b93505b600f54604051600160a01b90910460020b81527f3de48b885df0271268324c099733a36a802c1cbb40c7272796b2b28addf04cd29060200160405180910390a1886080015160020b896060015160020b8a600001516001600160a01b03167fa24f288a343811d26ac1ec29998e37b87ff6503cefe399a3c8fb747eb0464e58338d602001518e604001518c8f8f8e604051611ff197969594939291906001600160a01b03978816815260208101969096529390951660408501526060840191909152608083015260a082019290925260c081019190915260e00190565b60405180910390a450506007805460ff1916600117905550939592945090929091565b61201c612923565b66470de4df82000081111561205f5760405162461bcd60e51b81526020600482015260096024820152686665652072616e676560b81b60448201526064016108c8565b60068190556040518181527f557809284da7314475b1582804ae28e5f1349efc1fe970ea25d50fce75eb4f43906020015b60405180910390a150565b6120a3612923565b6120ad6000613d2c565b565b6003546001600160a01b031633146120da57604051630a0d349f60e21b815260040160405180910390fd5b80600954101561210b576009546040516311920a6d60e31b81526108c8918391600401918252602082015260400190565b806009600082825461211d91906158a9565b909155505050565b6078546001600160a01b031690565b61213c612923565b60ff8116158061215f575060038160ff161015801561215f575060328160ff1611155b6121965760405162461bcd60e51b815260206004820152600860248201526750522072616e676560c01b60448201526064016108c8565b600f805460ff60b81b1916600160b81b60ff8416908102919091179091556040519081527fe949530fb25dc21f05cb65fe03447f6f68f8e21e3584c72e6e92042b8bc28f7990602001612090565b60105460009060ff161561229b5760055460408051633bd5670d60e11b815290516000926001600160a01b0316916377aace1a916004808301926020929190829003018186803b15801561223757600080fd5b505afa15801561224b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061226f91906156a1565b9050336001600160a01b038216146122995760405162461bcd60e51b81526004016108c8906156be565b505b60125460ff16156122be5760405162461bcd60e51b81526004016108c8906156e2565b6122c96002546132b3565b156122e65760405162461bcd60e51b81526004016108c890615845565b60075460ff166123085760405162461bcd60e51b81526004016108c890615702565b6007805460ff191690556001600160801b03821661233b5781604051633611668d60e21b81526004016108c8919061536a565b336001600160a01b03861614806123cf57506005546040516351c4bc1f60e11b81526001600160a01b039091169063a389783e9061237f908890339060040161571f565b60206040518083038186803b15801561239757600080fd5b505afa1580156123ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123cf9190615739565b6124275760405162461bcd60e51b8152602060048201526024808201527f6f6e6c79206d73672e73656e646572206f7220617070726f7665642063616e206044820152631b5a5b9d60e21b60648201526084016108c8565b6124686040518060800160405280876001600160a01b031681526020018660020b81526020018560020b8152602001610bb0856001600160801b0316612982565b90508260020b8460020b866001600160a01b03167f712faa344eac6399174fdfa887d9e1451e9b55ce58ee440c91c660229962a5a63386604051610bff929190615794565b6124b5612923565b6010805460ff191682151590811790915560405160ff909116151581527fa201234976cfdc556c03f06ca9366e09441724eae79256ad9da6b5f04cbdb05890602001612090565b604554610100900460ff161580801561251c5750604554600160ff909116105b8061253d575061252b30612914565b15801561253d575060455460ff166001145b6125a05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016108c8565b6045805460ff1916600117905580156125c3576045805461ff0019166101001790555b6001600160a01b0383166126025760405162461bcd60e51b815260206004820152600660248201526504d45203d20360d41b60448201526064016108c8565b60008260020b13801561261a5750614000600283900b125b61264e5760405162461bcd60e51b81526020600482015260056024820152642a29a7a7a160d91b60448201526064016108c8565b600380546001600160a01b0319166001600160a01b03851690811790915560408051634c7a58d960e11b815290516398f4b1b291600480820192602092909190829003018186803b1580156126a257600080fd5b505afa1580156126b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126da91906156a1565b600080546001600160a01b03929092166001600160a01b03199283161790556005805490911633179055600c805462ffffff841662ffffff1990911617908190556127279060020b613d7e565b600480546001600160801b0319166001600160801b03929092169190911781556003546040805163652c30b760e01b815290516001600160a01b039092169263652c30b7928282019260209290829003018186803b15801561278857600080fd5b505afa15801561279c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127c09190615876565b600155600354604080516324fb6d1560e21b815290516001600160a01b03909216916393edb45491600480820192602092909190829003018186803b15801561280857600080fd5b505afa15801561281c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128409190615876565b60025561284b613de6565b612853613e15565b8015612899576045805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6128a6612923565b6001600160a01b03811661290b5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016108c8565b610ce281613d2c565b6001600160a01b03163b151590565b3361292c612125565b6001600160a01b0316146120ad5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016108c8565b80600f81900b81146129c65760405162461bcd60e51b815260206004820152600d60248201526c746f496e74313238206f666c6f60981b60448201526064016108c8565b919050565b60006129df82602001518360400151612dc7565b6040805160608082018352600f80546001600160a01b0381168452600160a01b810460020b6020850152600160b81b900460ff1693830193909352840151909160009182910b15612a3957612a3385613e3c565b90925090505b600354600094506001600160a01b03163314612afb576003546040805163bfb5607d60e01b815287516001600160a01b0390811660048301526020890151600290810b60248401529289015190920b60448201526060880151600f0b606482015291169063bfb5607d90608401602060405180830381600087803b158015612ac057600080fd5b505af1158015612ad4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612af89190615876565b93505b60008560600151600f0b1215612b39578115612b22576020850151612b2290600d90613f1b565b8015612b39576040850151612b3990600d90613f1b565b6000805460408051637aa4db1360e01b815290516001600160a01b0390921692637aa4db139260048084019382900301818387803b158015612b7a57600080fd5b505af1158015612b8e573d6000803e3d6000fd5b505050508460600151600f0b600014612c2157846020015160020b836020015160020b12158015612bcc5750846040015160020b836020015160020b125b15612c21576000600760019054906101000a90046001600160801b03169050612bf9818760600151613cf5565b600760016101000a8154816001600160801b0302191690836001600160801b03160217905550505b505050919050565b600080516020615f54833981519152546001600160a01b031690565b610ce2612923565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612c805761289983613f54565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b815260040160206040518083038186803b158015612cb957600080fd5b505afa925050508015612ce9575060408051601f3d908101601f19168201909252612ce691810190615876565b60015b612d4c5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b60648201526084016108c8565b600080516020615f548339815191528114612dbb5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b60648201526084016108c8565b50612899838383613fee565b8060020b8260020b12612e025760405162461bcd60e51b8152602060048201526003602482015262544c5560e81b60448201526064016108c8565b62010deb19600283900b1215612e405760405162461bcd60e51b8152602060048201526003602482015262544c4d60e81b60448201526064016108c8565b612e4d62010deb1961588f565b60020b8160020b131561107a5760405162461bcd60e51b815260206004820152600360248201526254554d60e81b60448201526064016108c8565b8051600290810b600090815260208481526040808320918501805190940b83528083208551945191860151606087015160018086015490840154969795969395612ed89590949093929190614019565b95945050505050565b8051600290810b6000908152602084815260408083209185018051850b8452818420865191519287015160608801518588015497830154969795969295612ed89593614019565b8051600290810b600090815260208481526040808320918501805190940b835280832085519451918601516060870151949593949193612ed8939092909190612f7090613b87565b612f7d8760030154613b87565b612f8a8760030154613b87565b614019565b60006b0816769404766de590afe04e6001600160a01b03831610801590612fcb57506c1fa71f3f5f68a90479ee3f8fec6001600160a01b038316105b612fe75760405162461bcd60e51b81526004016108c89061582a565b600160201b600160c01b03602083901b166001600160801b03811160071b81811c6001600160401b03811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c60ff8111600390811b91821c600f811160021b90811c918211600190811b92831c9790881196179094179092171790911717176080811061308057613076607f826158a9565b83901c9150613091565b61308b81607f6158a9565b83901b91505b600060406130a06080846158c0565b901b9050828302607f1c92508260801c80603f1b8217915083811c935050828302607f1c92508260801c80603e1b8217915083811c935050828302607f1c92508260801c80603d1b8217915083811c935050828302607f1c92508260801c80603c1b8217915083811c935050828302607f1c92508260801c80603b1b8217915083811c935050828302607f1c92508260801c80603a1b8217915083811c935050828302607f1c92508260801c8060391b8217915083811c935050828302607f1c92508260801c8060381b8217915083811c935050828302607f1c92508260801c8060371b8217915083811c935050828302607f1c92508260801c8060361b8217915083811c935050828302607f1c92508260801c8060351b8217915083811c935050828302607f1c92508260801c8060341b8217915083811c935050828302607f1c92508260801c8060331b8217915083811c935050828302607f1c92508260801c8060321b8217915050600081693627a301d71055774c8561322391906159e7565b9050600060806132436f028f6481ab7f045a5af012a19d003aaa846158c0565b901d905060006080613265846fdb2df09e81959a81455e260799a0632f61595e565b901d90508060020b8260020b146132a457886001600160a01b0316613289826135b9565b6001600160a01b0316111561329e57816132a6565b806132a6565b815b9998505050505050505050565b60008169124bc0ddd92e560000006132c961394e565b6132d3919061591c565b101592915050565b60208301516132fd57604051631fa907d560e11b815260040160405180910390fd5b60075460ff1661332b57600754604051633cc7822f60e11b815260ff909116151560048201526024016108c8565b8061337f5781600001516001600160a01b031683604001516001600160a01b031610801561337a57506b0816769404766de590afe04e6001600160a01b031683604001516001600160a01b0316115b6133ca565b81600001516001600160a01b031683604001516001600160a01b03161180156133ca57506c1fa71f3f5f68a90479ee3f8fec6001600160a01b031683604001516001600160a01b0316105b6128995760405162461bcd60e51b815260206004820152600360248201526214d41360ea1b60448201526064016108c8565b6000808061340a8587615a6c565b905060008660020b12801561342a57506134248587615aa6565b60020b15155b1561343d578061343981615ac8565b9150505b83156134ea5760008061344f83614085565b90925090506000600160ff831681901b9061346a90826158a9565b613474919061591c565b600184900b600090815260208c9052604090205481168015159650909150856134b457886134a560ff85168761599f565b6134af9190615aec565b6134df565b886134be826140a2565b6134c89085615b79565b6134d59060ff168761599f565b6134df9190615aec565b9650505050506135af565b6000806135006134fb846001615b9c565b614085565b90925090506000613518600160ff841681901b6158a9565b600184900b600090815260208c905260409020549019908116801515965090915085613571578861354a8460ff615b79565b60ff16613558876001615b9c565b6135629190615b9c565b61356c9190615aec565b6135a8565b888361357c8361419f565b6135869190615b79565b60ff16613594876001615b9c565b61359e9190615b9c565b6135a89190615aec565b9650505050505b5094509492505050565b60008060008360020b126135d0578260020b6135dd565b8260020b6135dd906158ff565b90506135ec62010deb1961588f565b60020b8111156136225760405162461bcd60e51b81526020600482015260016024820152601560fa1b60448201526064016108c8565b60006001821661363657600160801b613648565b6ffffcb933bd6fad37aa2d162d1a5940015b6001600160881b03169050600282161561367d576080613678826ffff97272373d413259a46990580e213a615be3565b901c90505b60048216156136a75760806136a2826ffff2e50f5f656932ef12357cf3c7fdcc615be3565b901c90505b60088216156136d15760806136cc826fffe5caca7e10e4e61c3624eaa0941cd0615be3565b901c90505b60108216156136fb5760806136f6826fffcb9843d60f6159c9db58835c926644615be3565b901c90505b6020821615613725576080613720826fff973b41fa98c081472e6896dfb254c0615be3565b901c90505b604082161561374f57608061374a826fff2ea16466c96a3843ec78b326b52861615be3565b901c90505b6080821615613779576080613774826ffe5dee046a99a2a811c461f1969c3053615be3565b901c90505b6101008216156137a457608061379f826ffcbe86c7900a88aedcffc83b479aa3a4615be3565b901c90505b6102008216156137cf5760806137ca826ff987a7253ac413176f2b074cf7815e54615be3565b901c90505b6104008216156137fa5760806137f5826ff3392b0822b70005940c7a398e4b70f3615be3565b901c90505b610800821615613825576080613820826fe7159475a2c29b7443b29c7fa6e889d9615be3565b901c90505b61100082161561385057608061384b826fd097f3bdfd2022b8845ad8f792aa5825615be3565b901c90505b61200082161561387b576080613876826fa9f746462d870fdf8a65dc1f90e061e5615be3565b901c90505b6140008216156138a65760806138a1826f70d869a156d2a1b890bb3df62baf32f7615be3565b901c90505b6180008216156138d15760806138cc826f31be135f97d08fd981231505542fcfa6615be3565b901c90505b620100008216156138fd5760806138f8826f09aa508b5b7a84e1c677de54f3e99bc9615be3565b901c90505b60008460020b1315613918576139158160001961594a565b90505b613926600160201b82615c02565b15613932576001613935565b60005b6139469060ff16602083901c61591c565b949350505050565b6000613959426142dc565b905090565b6020810151815160608301516000928392839283926001600160a01b039081169216919091101590828112801591840390613a0757826139b6576139b1886000015189602001518a604001516001614329565b6139cf565b6139cf886020015189600001518a604001516001614399565b9550858860600151106139e85787602001519650613a6f565b613a00886000015189604001518a606001518661449c565b9650613a6f565b82613a2a57613a25886000015189602001518a604001516000614399565b613a43565b613a43886020015189600001518a604001516000614329565b9450848110613a585787602001519650613a6f565b613a6c88600001518960400151838661450e565b96505b60208801516001600160a01b0388811691161460008415613aeb57818015613a945750835b613ab257613aad898b600001518c604001516001614399565b613ab4565b875b9750818015613ac1575083155b613adf57613ada898b600001518c604001516000614329565b613ae1565b865b9650869050613b48565b818015613af55750835b613b1357613b0e8a600001518a8c604001516001614329565b613b15565b875b9750818015613b22575083155b613b4057613b3b8a600001518a8c604001516000614399565b613b42565b865b96508790505b83158015613b5557508287115b15613b5e578296505b613b79613b6a826142dc565b8b60a001518c60800151614580565b955050505050509193509193565b6000600160ff1b8210613bcc5760405162461bcd60e51b815260206004820152600d60248201526c746f496e74323536206f666c6f60981b60448201526064016108c8565b5090565b600080600080613bf68560c00151600160801b8860c001516001600160801b03166145bb565b8660e00151613c05919061591c565b9350613c27856101000151866101400151886101a001516001546002546146b9565b9050613c4a856101400151600160801b8860c001516001600160801b031661473e565b8660a00151613c59919061595e565b9250613c7781600160801b8860c001516001600160801b031661473e565b8660800151613c86919061595e565b915092959194509250565b600284900b60009081526020869052604081206003810154613cb390846158a9565b60038201556001810154613cc790866158c0565b60018201556002810154613cdb90856158c0565b600282015554600160801b9004600f0b9695505050505050565b60008082600f0b1215613d19576000829003613d118185615c16565b915050613d26565b613d238284615c3e565b90505b92915050565b607880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600080613d8f8362010deb19615aa6565b613d9d9062010deb1961599f565b90506000613daa8261588f565b9050600084613db9848461599f565b613dc39190615a6c565b613dce906001615c69565b9050612ed862ffffff82166001600160801b03615c87565b604554610100900460ff16613e0d5760405162461bcd60e51b81526004016108c890615cad565b6120ad614776565b604554610100900460ff166120ad5760405162461bcd60e51b81526004016108c890615cad565b600080613e5183602001518460400151612dc7565b6020830151600f546060850151600a54600b54600854600454613e9696600d969095600160a01b90910460020b949093909290916000906001600160801b03166147a6565b6040840151600f546060860151600a54600b54600854600454969850613eda96600d9695600160a01b900460020b94939291906001906001600160801b03166147a6565b90508115613ef9576020830151600c54613ef991600e9160020b61493b565b8015613f16576040830151600c54613f1691600e9160020b61493b565b915091565b600290810b600090815260209290925260408220828155600181018390559081018290556003810191909155600401805460ff19169055565b613f5d81612914565b613fbf5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016108c8565b600080516020615f5483398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b613ff7836149d0565b6000825111806140045750805b15612899576140138383614a10565b50505050565b6000808760020b8660020b1261403057508261403d565b61403a84866158c0565b90505b60008760020b8760020b1215614054575082614061565b61405e84876158c0565b90505b600061406d828461595e565b61407790886158c0565b9a9950505050505050505050565b600281900b60081d600061409b61010084615aa6565b9050915091565b60008082116140c35760405162461bcd60e51b81526004016108c890615cf8565b600160801b82106140e157608091821c916140de9082615d1f565b90505b600160401b82106140ff57604091821c916140fc9082615d1f565b90505b600160201b821061411d57602091821c9161411a9082615d1f565b90505b62010000821061413a57601091821c916141379082615d1f565b90505b610100821061415657600891821c916141539082615d1f565b90505b6010821061417157600491821c9161416e9082615d1f565b90505b6004821061418c57600291821c916141899082615d1f565b90505b600282106129c657613d26600182615d1f565b60008082116141c05760405162461bcd60e51b81526004016108c890615cf8565b5060ff6001600160801b038216156141e4576141dd608082615b79565b90506141ec565b608082901c91505b6001600160401b0382161561420d57614206604082615b79565b9050614215565b604082901c91505b63ffffffff8216156142335761422c602082615b79565b905061423b565b602082901c91505b61ffff82161561425757614250601082615b79565b905061425f565b601082901c91505b60ff82161561427a57614273600882615b79565b9050614282565b600882901c91505b600f82161561429d57614296600482615b79565b90506142a5565b600482901c91505b60038216156142c0576142b9600282615b79565b90506142c8565b600282901c91505b60018216156129c657613d26600182615b79565b60007812725dd1d243aba0e75fe645cc4873f9e65afe688c928e1f2182111561431b57604051633492ffd960e01b8152600481018390526024016108c8565b50670de0b6b3a76400000290565b6000836001600160a01b0316856001600160a01b03161115614349579293925b8161437657614371836001600160801b03168686036001600160a01b0316600160601b6145bb565b612ed8565b612ed8836001600160801b03168686036001600160a01b0316600160601b614af9565b6000836001600160a01b0316856001600160a01b031611156143b9579293925b600160601b600160e01b03606084901b1660006143d68787615d44565b6001600160a01b031690506000876001600160a01b03161161442f5760405162461bcd60e51b8152602060048201526012602482015271073717274526174696f4158393620213e20360741b60448201526064016108c8565b8361446557866001600160a01b03166144528383896001600160a01b03166145bb565b8161445f5761445f615934565b04614491565b61449161447c8383896001600160a01b0316614af9565b886001600160a01b0316808204910615150190565b979650505050505050565b600080856001600160a01b0316116144c65760405162461bcd60e51b81526004016108c890615d64565b6000846001600160801b0316116144ef5760405162461bcd60e51b81526004016108c890615d8b565b81614501576143718585856001614b4c565b612ed88585856001614c65565b600080856001600160a01b0316116145385760405162461bcd60e51b81526004016108c890615d64565b6000846001600160801b0316116145615760405162461bcd60e51b81526004016108c890615d8b565b81614573576143718585856000614c65565b612ed88585856000614b4c565b60008061458c84614db1565b905060006145a38661459e8685614dc8565b614dc8565b9050670de0b6b3a764000081045b9695505050505050565b60008080600019858709858702925082811083820303915050806000141561462b57600084116146205760405162461bcd60e51b815260206004820152601060248201526f4469766973696f6e206279207a65726f60801b60448201526064016108c8565b5082900490506146b2565b80841161464a5760405162461bcd60e51b81526004016108c890615dad565b600084868809851960019081018716968790049682860381900495909211909303600082900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b60008282116146da5760405162461bcd60e51b81526004016108c890615dcf565b851580156146e6575084155b156146f357506000612ed8565b60006146fe87614dd4565b9050600061470b87614dd4565b9050600061471c8383898989614e51565b9050600061472c84838989614e7d565b9050670de0b6b3a76400008105614077565b60008084121561476b5761475b614754856158ff565b84846145bb565b614764906158ff565b90506146b2565b6139468484846145bb565b604554610100900460ff1661479d5760405162461bcd60e51b81526004016108c890615cad565b6120ad33613d2c565b600288900b600090815260208a90526040812080546001600160801b0316826147cf8a83615ded565b600f0b121561481f5760405162461bcd60e51b815260206004820152601c60248201527b3737ba1032b737bab3b4103634b8bab4b234ba3c903a3790313ab93760211b60448201526064016108c8565b600061482b828b613cf5565b9050846001600160801b0316816001600160801b031611156148745760405162461bcd60e51b81526020600482015260026024820152614c4f60f01b60448201526064016108c8565b6001600160801b0382811615908216158114159450156148c1578a60020b8c60020b136148b1576003830187905560018301899055600283018890555b60048301805460ff191660011790555b82546001600160801b0319166001600160801b038216178355856148fb5782546148f6908b90600160801b9004600f0b615ded565b614912565b8254614912908b90600160801b9004600f0b615e35565b83546001600160801b03918216600160801b0291161790925550909a9950505050505050505050565b6149458183615aa6565b60020b156149945760405162461bcd60e51b815260206004820152601c60248201527b1d1a58dac81b5d5cdd081899481c1c9bdc195c9b1e481cdc1858d95960221b60448201526064016108c8565b6000806149a46134fb8486615a6c565b600191820b60009081526020979097526040909620805460ff9097169190911b90951890945550505050565b6149d981613f54565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060614a1b83612914565b614a765760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016108c8565b600080846001600160a01b031684604051614a919190615ea7565b600060405180830381855af49150503d8060008114614acc576040519150601f19603f3d011682016040523d82523d6000602084013e614ad1565b606091505b5091509150612ed88282604051806060016040528060278152602001615f7460279139614ebe565b6000614b068484846145bb565b905060008280614b1857614b18615934565b84860911156146b2576000198110614b425760405162461bcd60e51b81526004016108c890615dad565b80612ed881615ec3565b60008115614bb65760006001600160a01b03841115614b8257614b7d84600160601b876001600160801b03166145bb565b614b99565b614b996001600160801b038616606086901b61594a565b9050614ba481614ef7565b614bae9087615ede565b915050613946565b60006001600160a01b03841115614be457614bdf84600160601b876001600160801b0316614af9565b614c01565b614c01606085901b6001600160801b038716808204910615150190565b905080866001600160a01b031611614c525760405162461bcd60e51b81526020600482015260146024820152731cdc5c9d14160e4d88084f881c5d5bdd1a595b9d60621b60448201526064016108c8565b614bae816001600160a01b0388166158a9565b600082614c73575083613946565b600160601b600160e01b03606085901b168215614d1e5760006001600160a01b03871685614ca18282615be3565b9250614cad908361594a565b1415614ce8576000614cbf828461591c565b9050828110614ce657614cdc83896001600160a01b031683614af9565b9350505050613946565b505b614d158286614d006001600160a01b038b168361594a565b614d0a919061591c565b808204910615150190565b92505050613946565b60006001600160a01b03871685614d358282615be3565b9250614d41908361594a565b148015614d4d57508082115b614d875760405162461bcd60e51b815260206004820152600b60248201526a64656e6f6d2075666c6f7760a81b60448201526064016108c8565b6000614d9382846158a9565b9050614cdc614dac848a6001600160a01b031684614af9565b614ef7565b6000613d26826a1a1601fc4ea7109e000000614f41565b6000613d238383614f56565b60007809392ee8e921d5d073aff322e62439fcf32d7f344649470f8f19821215614e145760405163e608e18b60e01b8152600481018390526024016108c8565b7809392ee8e921d5d073aff322e62439fcf32d7f344649470f9082131561431b576040516371f72a3160e01b8152600481018390526024016108c8565b6000614e5d8585615018565b614e73614e6c600086866150dd565b8890615018565b6145b1919061595e565b6000828211614e9e5760405162461bcd60e51b81526004016108c890615dcf565b614eb4614ead600185856150dd565b859061518f565b612ed890866158c0565b60608315614ecd5750816146b2565b825115614edd5782518084602001fd5b8160405162461bcd60e51b81526004016108c89190615f00565b806001600160a01b03811681146129c65760405162461bcd60e51b815260206004820152600e60248201526d746f55696e74313630206f666c6f60901b60448201526064016108c8565b6000613d2383670de0b6b3a764000084615255565b60008080600019848609848602925082811083820303915050670de0b6b3a76400008110614f9a5760405163698d9a0160e11b8152600481018290526024016108c8565b600080670de0b6b3a76400008688099150506706f05b59d3b1ffff811182614fd45780670de0b6b3a7640000850401945050505050613d26565b620400008285030493909111909103600160ee1b02919091177faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106690201905092915050565b6000600160ff1b83148061502f5750600160ff1b82145b1561504d57604051630d01a11b60e21b815260040160405180910390fd5b6000806000851261505e5784615063565b846000035b9150600084126150735783615078565b836000035b905060006150868383614f56565b90506001600160ff1b038111156150b35760405163bf79e8d960e01b8152600481018290526024016108c8565b6000198087139086138082186001146150cc57826150d1565b826000035b98975050505050505050565b60008282116150fe5760405162461bcd60e51b81526004016108c890615dcf565b600061510861394e565b9050838110156151425760405162461bcd60e51b8152602060048201526005602482015264422e543c5360d81b60448201526064016108c8565b600085806151505750838210155b156151665761515f85856158a9565b9050615173565b61517085836158a9565b90505b6145b168056bc75e2d6310000061518983614db1565b90614f41565b6000600160ff1b8314806151a65750600160ff1b82145b156151c45760405163b3c754a360e01b815260040160405180910390fd5b600080600085126151d557846151da565b846000035b9150600084126151ea57836151ef565b836000035b9050600061520683670de0b6b3a764000084615255565b90506001600160ff1b0381111561523357604051637cb4bef560e01b8152600481018290526024016108c8565b60001980871390861380821860011461524c57826150d1565b6150d1836158ff565b6000808060001985870985870292508281108382030391505080600014156152905783828161528657615286615934565b04925050506146b2565b83811061464a57604051631dcf306360e21b815260048101829052602481018590526044016108c8565b60405180610160016040528060006001600160a01b03168152602001600060020b815260200160001515815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6001600160a01b0391909116815260200190565b8015158114610ce257600080fd5b60006020828403121561535f57600080fd5b81356146b28161533f565b6001600160801b0391909116815260200190565b6001600160a01b0381168114610ce257600080fd5b8035600281900b81146129c657600080fd5b600080600080608085870312156153bb57600080fd5b84356153c68161537e565b93506153d460208601615393565b92506153e260408601615393565b915060608501356001600160801b03811681146153fe57600080fd5b939692955090935050565b60006020828403121561541b57600080fd5b81356146b28161537e565b6000806040838503121561543957600080fd5b61544283615393565b915061545060208401615393565b90509250929050565b6000806040838503121561546c57600080fd5b82356154778161537e565b915060208301356154878161533f565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156154d0576154d0615492565b604052919050565b600080604083850312156154eb57600080fd5b82356154f68161537e565b91506020838101356001600160401b038082111561551357600080fd5b818601915086601f83011261552757600080fd5b81358181111561553957615539615492565b61554b601f8201601f191685016154a8565b9150808252878482850101111561556157600080fd5b80848401858401376000848284010152508093505050509250929050565b60006020828403121561559157600080fd5b81358060010b81146146b257600080fd5b600060a082840312156155b457600080fd5b60405160a081016001600160401b03811182821017156155d6576155d6615492565b60405282356155e48161537e565b81526020838101359082015260408301356155fe8161537e565b604082015261560f60608401615393565b606082015261562060808401615393565b60808201529392505050565b60006020828403121561563e57600080fd5b5035919050565b60006020828403121561565757600080fd5b813560ff811681146146b257600080fd5b6000806040838503121561567b57600080fd5b82356154428161537e565b60006020828403121561569857600080fd5b613d2382615393565b6000602082840312156156b357600080fd5b81516146b28161537e565b6020808252600a90820152697070687279206f6e6c7960b01b604082015260600190565b60208082526006908201526514185d5cd95960d21b604082015260600190565b6020808252600390820152624c4f4b60e81b604082015260600190565b6001600160a01b0392831681529116602082015260400190565b60006020828403121561574b57600080fd5b81516146b28161533f565b634e487b7160e01b600052601160045260246000fd5b6000600f82900b60016001607f1b031981141561578b5761578b615756565b60000392915050565b6001600160a01b039290921682526001600160801b0316602082015260400190565b6020808252602c90820152600080516020615f3483398151915260408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c90820152600080516020615f3483398151915260408201526b6163746976652070726f787960a01b606082015260800190565b6020808252600190820152602960f91b604082015260600190565b602080825260179082015276636c6f7365546f4f724265796f6e644d6174757269747960481b604082015260600190565b60006020828403121561588857600080fd5b5051919050565b60008160020b627fffff1981141561578b5761578b615756565b6000828210156158bb576158bb615756565b500390565b60008083128015600160ff1b8501841216156158de576158de615756565b6001600160ff1b03840183138116156158f9576158f9615756565b50500390565b6000600160ff1b82141561591557615915615756565b5060000390565b6000821982111561592f5761592f615756565b500190565b634e487b7160e01b600052601260045260246000fd5b60008261595957615959615934565b500490565b600080821280156001600160ff1b038490038513161561598057615980615756565b600160ff1b839003841281161561599957615999615756565b50500190565b60008160020b8360020b6000811281627fffff19018312811516156159c6576159c6615756565b81627fffff0183138116156159dd576159dd615756565b5090039392505050565b60006001600160ff1b0381841382841380821686840486111615615a0d57615a0d615756565b600160ff1b6000871282811687830589121615615a2c57615a2c615756565b60008712925087820587128484161615615a4857615a48615756565b87850587128184161615615a5e57615a5e615756565b505050929093029392505050565b60008160020b8360020b80615a8357615a83615934565b627fffff19821460001982141615615a9d57615a9d615756565b90059392505050565b60008260020b80615ab957615ab9615934565b808360020b0791505092915050565b60008160020b627fffff19811415615ae257615ae2615756565b6000190192915050565b60008160020b8360020b627fffff600082136000841383830485118282161615615b1857615b18615756565b627fffff196000851282811687830587121615615b3757615b37615756565b60008712925085820587128484161615615b5357615b53615756565b85850587128184161615615b6957615b69615756565b5050509290910295945050505050565b600060ff821660ff841680821015615b9357615b93615756565b90039392505050565b60008160020b8360020b6000821282627fffff03821381151615615bc257615bc2615756565b82627fffff19038212811615615bda57615bda615756565b50019392505050565b6000816000190483118215151615615bfd57615bfd615756565b500290565b600082615c1157615c11615934565b500690565b60006001600160801b0383811690831681811015615c3657615c36615756565b039392505050565b60006001600160801b03828116848216808303821115615c6057615c60615756565b01949350505050565b600062ffffff808316818516808303821115615c6057615c60615756565b60006001600160801b0383811680615ca157615ca1615934565b92169190910492915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6020808252600d908201526c078206d757374206265203e203609c1b604082015260600190565b600060ff821660ff84168060ff03821115615d3c57615d3c615756565b019392505050565b60006001600160a01b0383811690831681811015615c3657615c36615756565b6020808252600d908201526c0737172745058393620213e203609c1b604082015260600190565b60208082526008908201526706c697120213e20360c41b604082015260600190565b6020808252600890820152676f766572666c6f7760c01b604082015260600190565b602080825260049082015263453c3d5360e01b604082015260600190565b6000600f82810b9084900b828212801560016001607f1b0384900383131615615e1857615e18615756565b60016001607f1b03198390038212811615615bda57615bda615756565b6000600f82810b9084900b828112801560016001607f1b0319830184121615615e6057615e60615756565b60016001607f1b03820183138116156159dd576159dd615756565b60005b83811015615e96578181015183820152602001615e7e565b838111156140135750506000910152565b60008251615eb9818460208701615e7b565b9190910192915050565b6000600019821415615ed757615ed7615756565b5060010190565b60006001600160a01b03828116848216808303821115615c6057615c60615756565b6020815260008251806020840152615f1f816040850160208701615e7b565b601f01601f1916919091016040019291505056fe46756e6374696f6e206d7573742062652063616c6c6564207468726f75676820360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220149cb7e322dff3690c8ff73093f6f3a2452ba3d82b3f150c137603de9ccad4d564736f6c63430008090033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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.