Mumbai Testnet

Contract

0x571e4EF095F44991E052cE6037AFA02B050A1B75

Overview

MATIC Balance

Polygon PoS Chain LogoPolygon PoS Chain LogoPolygon PoS Chain Logo0 MATIC

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Value

There are no matching entries

Please try again later

Latest 1 internal transaction

Parent Txn Hash Block From To Value
353523212023-05-08 20:42:32325 days ago1683578552  Contract Creation0 MATIC
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x2F7FFba4...2CF5637Dc
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
LiquidationPair

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 6 : LiquidationPair.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

import "./libraries/LiquidatorLib.sol";
import "./libraries/FixedMathLib.sol";
import "./interfaces/ILiquidationSource.sol";
import { Math } from "openzeppelin/utils/math/Math.sol";

/**
 * @title PoolTogether Liquidation Pair
 * @author PoolTogether Inc. Team
 * @notice The LiquidationPair is a UniswapV2-like pair that allows the liquidation of tokens
 *          from an ILiquidationSource. Users can swap tokens in exchange for the tokens available.
 *          The LiquidationPair implements a virtual reserve system that results in the value
 *          tokens available from the ILiquidationSource to decay over time relative to the value
 *          of the token swapped in.
 * @dev Each swap consists of four steps:
 *       1. A virtual buyback of the tokens available from the ILiquidationSource. This ensures
 *          that the value of the tokens available from the ILiquidationSource decays as
 *          tokens accrue.
 *      2. The main swap of tokens the user requested.
 *      3. A virtual swap that is a small multiplier applied to the users swap. This is to
 *          push the value of the tokens being swapped back up towards the market value.
 *      4. A scaling of the virtual reserves. This is to ensure that the virtual reserves
 *          are large enough such that the next swap will have a realistic impact on the virtual
 *          reserves.
 */
contract LiquidationPair {
  /* ============ Variables ============ */

  ILiquidationSource public immutable source;
  address public immutable tokenIn;
  address public immutable tokenOut;
  UFixed32x4 public immutable swapMultiplier;
  UFixed32x4 public immutable liquidityFraction;

  uint128 public virtualReserveIn;
  uint128 public virtualReserveOut;
  uint256 public immutable minK;

  /* ============ Events ============ */

  /**
   * @notice Emitted when the pair is swapped.
   * @param account The account that swapped.
   * @param amountIn The amount of token in swapped.
   * @param amountOut The amount of token out swapped.
   * @param virtualReserveIn The updated virtual reserve of the token in.
   * @param virtualReserveOut The updated virtual reserve of the token out.
   */
  event Swapped(
    address indexed account,
    uint256 amountIn,
    uint256 amountOut,
    uint128 virtualReserveIn,
    uint128 virtualReserveOut
  );

  /* ============ Constructor ============ */

  /**
   * @notice Construct a new LiquidationPair.
   * @param _source The source of yield for the liquidation pair.
   * @param _tokenIn The token to be swapped in.
   * @param _tokenOut The token to be swapped out.
   * @param _swapMultiplier The multiplier for the users swaps.
   * @param _liquidityFraction The liquidity fraction to be applied after swapping.
   * @param _virtualReserveIn The initial virtual reserve of token in.
   * @param _virtualReserveOut The initial virtual reserve of token out.
   * @param _minK The minimum value of k.
   * @dev The swap multiplier and liquidity fraction are represented as UFixed32x4.
   */
  constructor(
    ILiquidationSource _source,
    address _tokenIn,
    address _tokenOut,
    UFixed32x4 _swapMultiplier,
    UFixed32x4 _liquidityFraction,
    uint128 _virtualReserveIn,
    uint128 _virtualReserveOut,
    uint256 _minK
  ) {
    require(
      UFixed32x4.unwrap(_liquidityFraction) > 0,
      "LiquidationPair/liquidity-fraction-greater-than-zero"
    );
    require(
      UFixed32x4.unwrap(_liquidityFraction) > 0,
      "LiquidationPair/liquidity-fraction-greater-than-zero"
    );
    require(
      UFixed32x4.unwrap(_swapMultiplier) <= 1e4,
      "LiquidationPair/swap-multiplier-less-than-one"
    );
    require(
      UFixed32x4.unwrap(_liquidityFraction) <= 1e4,
      "LiquidationPair/liquidity-fraction-less-than-one"
    );
    require(
      uint256(_virtualReserveIn) * _virtualReserveOut >= _minK,
      "LiquidationPair/virtual-reserves-greater-than-min-k"
    );
    require(_minK > 0, "LiquidationPair/min-k-greater-than-zero");
    require(_virtualReserveIn <= type(uint112).max, "LiquidationPair/virtual-reserve-in-too-large");
    require(
      _virtualReserveOut <= type(uint112).max,
      "LiquidationPair/virtual-reserve-out-too-large"
    );

    source = _source;
    tokenIn = _tokenIn;
    tokenOut = _tokenOut;
    swapMultiplier = _swapMultiplier;
    liquidityFraction = _liquidityFraction;
    virtualReserveIn = _virtualReserveIn;
    virtualReserveOut = _virtualReserveOut;
    minK = _minK;
  }

  /* ============ External Methods ============ */
  /* ============ Read Methods ============ */

  /**
   * @notice Get the address that will receive `tokenIn`.
   * @return Address of the target
   */
  function target() external view returns (address) {
    return source.targetOf(tokenIn);
  }

  /**
   * @notice Computes the maximum amount of tokens that can be swapped in given the current state of the liquidation pair.
   * @return The maximum amount of tokens that can be swapped in.
   */
  function maxAmountIn() external view returns (uint256) {
    return
      LiquidatorLib.computeExactAmountIn(
        virtualReserveIn,
        virtualReserveOut,
        _availableReserveOut(),
        _availableReserveOut()
      );
  }

  /**
   * @notice Gets the maximum amount of tokens that can be swapped out from the source.
   * @return The maximum amount of tokens that can be swapped out.
   */
  function maxAmountOut() external view returns (uint256) {
    return _availableReserveOut();
  }

  /**
   * @notice Computes the virtual reserves post virtual buyback of all available liquidity that has accrued.
   * @return The virtual reserve of the token in.
   * @return The virtual reserve of the token out.
   */
  function nextLiquidationState() external view returns (uint128, uint128) {
    return
      LiquidatorLib._virtualBuyback(virtualReserveIn, virtualReserveOut, _availableReserveOut());
  }

  /**
   * @notice Computes the exact amount of tokens to send in for the given amount of tokens to receive out.
   * @param _amountOut The amount of tokens to receive out.
   * @return The amount of tokens to send in.
   */
  function computeExactAmountIn(uint256 _amountOut) external view returns (uint256) {
    return
      LiquidatorLib.computeExactAmountIn(
        virtualReserveIn,
        virtualReserveOut,
        _availableReserveOut(),
        _amountOut
      );
  }

  /**
   * @notice Computes the exact amount of tokens to receive out for the given amount of tokens to send in.
   * @param _amountIn The amount of tokens to send in.
   * @return The amount of tokens to receive out.
   */
  function computeExactAmountOut(uint256 _amountIn) external view returns (uint256) {
    return
      LiquidatorLib.computeExactAmountOut(
        virtualReserveIn,
        virtualReserveOut,
        _availableReserveOut(),
        _amountIn
      );
  }

  /* ============ Write Methods ============ */

  /**
   * @notice Swaps the given amount of tokens in and ensures a minimum amount of tokens are received out.
   * @dev The amount of tokens being swapped in must be sent to the target before calling this function.
   * @param _account The address to send the tokens to.
   * @param _amountIn The amount of tokens sent in.
   * @param _amountOutMin The minimum amount of tokens to receive out.
   * @return The amount of tokens received out.
   */
  function swapExactAmountIn(
    address _account,
    uint256 _amountIn,
    uint256 _amountOutMin
  ) external returns (uint256) {
    uint256 availableBalance = _availableReserveOut();
    (uint128 _virtualReserveIn, uint128 _virtualReserveOut, uint256 amountOut) = LiquidatorLib
      .swapExactAmountIn(
        virtualReserveIn,
        virtualReserveOut,
        availableBalance,
        _amountIn,
        swapMultiplier,
        liquidityFraction,
        minK
      );

    virtualReserveIn = _virtualReserveIn;
    virtualReserveOut = _virtualReserveOut;

    require(amountOut >= _amountOutMin, "LiquidationPair/min-not-guaranteed");
    _swap(_account, amountOut, _amountIn);

    emit Swapped(_account, _amountIn, amountOut, _virtualReserveIn, _virtualReserveOut);

    return amountOut;
  }

  /**
   * @notice Swaps the given amount of tokens out and ensures the amount of tokens in doesn't exceed the given maximum.
   * @dev The amount of tokens being swapped in must be sent to the target before calling this function.
   * @param _account The address to send the tokens to.
   * @param _amountOut The amount of tokens to receive out.
   * @param _amountInMax The maximum amount of tokens to send in.
   * @return The amount of tokens sent in.
   */
  function swapExactAmountOut(
    address _account,
    uint256 _amountOut,
    uint256 _amountInMax
  ) external returns (uint256) {
    uint256 availableBalance = _availableReserveOut();
    (uint128 _virtualReserveIn, uint128 _virtualReserveOut, uint256 amountIn) = LiquidatorLib
      .swapExactAmountOut(
        virtualReserveIn,
        virtualReserveOut,
        availableBalance,
        _amountOut,
        swapMultiplier,
        liquidityFraction,
        minK
      );
    virtualReserveIn = _virtualReserveIn;
    virtualReserveOut = _virtualReserveOut;
    require(amountIn <= _amountInMax, "LiquidationPair/max-not-guaranteed");
    _swap(_account, _amountOut, amountIn);

    emit Swapped(_account, amountIn, _amountOut, _virtualReserveIn, _virtualReserveOut);

    return amountIn;
  }

  /* ============ Internal Functions ============ */

  /**
   * @notice Gets the available liquidity that has accrued that users can swap for.
   * @return The available liquidity that users can swap for.
   */
  function _availableReserveOut() internal view returns (uint256) {
    return source.liquidatableBalanceOf(tokenOut);
  }

  /**
   * @notice Sends the provided amounts of tokens to the address given.
   * @param _account The address to send the tokens to.
   * @param _amountOut The amount of tokens to receive out.
   * @param _amountIn The amount of tokens sent in.
   */
  function _swap(address _account, uint256 _amountOut, uint256 _amountIn) internal {
    source.liquidate(_account, tokenIn, _amountIn, tokenOut, _amountOut);
  }
}

File 2 of 6 : LiquidatorLib.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.17;

import "openzeppelin/token/ERC20/IERC20.sol";

import "./FixedMathLib.sol";

/**
 * @title PoolTogether Liquidator Library
 * @author PoolTogether Inc. Team
 * @notice A library to perform swaps on a UniswapV2-like pair of tokens. Implements logic that
 *          manipulates the token reserve amounts on swap.
 * @dev Each swap consists of four steps:
 *       1. A virtual buyback of the tokens available from the ILiquidationSource. This ensures
 *          that the value of the tokens available from the ILiquidationSource decays as
 *          tokens accrue.
 *      2. The main swap of tokens the user requested.
 *      3. A virtual swap that is a small multiplier applied to the users swap. This is to
 *          push the value of the tokens being swapped back up towards the market value.
 *      4. A scaling of the virtual reserves. This is to ensure that the virtual reserves
 *          are large enough such that the next swap will have a tailored impact on the virtual
 *          reserves.
 * @dev Numbered suffixes are used to identify the underlying token used for the parameter.
 *      For example, `amountIn1` and `reserve1` are the same token where `amountIn0` is different.
 */
library LiquidatorLib {
  /**
   * @notice Computes the amount of tokens that will be received for a given amount of tokens sent.
   * @param amountIn1 The amount of token 1 being sent in
   * @param reserve1 The amount of token 1 in the reserves
   * @param reserve0 The amount of token 0 in the reserves
   * @return amountOut0 The amount of token 0 that will be received given the amount in of token 1
   */
  function getAmountOut(
    uint256 amountIn1,
    uint128 reserve1,
    uint128 reserve0
  ) internal pure returns (uint256 amountOut0) {
    require(reserve0 > 0 && reserve1 > 0, "LiquidatorLib/insufficient-reserve-liquidity-a");
    uint256 numerator = amountIn1 * reserve0;
    uint256 denominator = amountIn1 + reserve1;
    amountOut0 = numerator / denominator;
    return amountOut0;
  }

  /**
   * @notice Computes the amount of tokens required to be sent in to receive a given amount of
   *          tokens.
   * @param amountOut0 The amount of token 0 to receive
   * @param reserve1 The amount of token 1 in the reserves
   * @param reserve0 The amount of token 0 in the reserves
   * @return amountIn1 The amount of token 1 needed to receive the given amount out of token 0
   */
  function getAmountIn(
    uint256 amountOut0,
    uint128 reserve1,
    uint128 reserve0
  ) internal pure returns (uint256 amountIn1) {
    require(amountOut0 < reserve0, "LiquidatorLib/insufficient-reserve-liquidity-c");
    require(reserve0 > 0 && reserve1 > 0, "LiquidatorLib/insufficient-reserve-liquidity-d");
    uint256 numerator = amountOut0 * reserve1;
    uint256 denominator = uint256(reserve0) - amountOut0;
    amountIn1 = (numerator / denominator) + 1;
  }

  /**
   * @notice Performs a swap of all of the available tokens from the ILiquidationSource which
   *          impacts the virtual reserves resulting in price decay as tokens accrue.
   * @param _reserve0 The amount of token 0 in the reserve
   * @param _reserve1 The amount of token 1 in the reserve
   * @param _amountIn1 The amount of token 1 to buy back
   * @return reserve0 The new amount of token 0 in the reserves
   * @return reserve1 The new amount of token 1 in the reserves
   */
  function _virtualBuyback(
    uint128 _reserve0,
    uint128 _reserve1,
    uint256 _amountIn1
  ) internal pure returns (uint128 reserve0, uint128 reserve1) {
    uint256 amountOut0 = getAmountOut(_amountIn1, _reserve1, _reserve0);
    reserve0 = _reserve0 - uint128(amountOut0);
    reserve1 = _reserve1 + uint128(_amountIn1);
  }

  /**
   * @notice Amplifies the users swap by a multiplier and then scales reserves to a configured ratio.
   * @param _reserve0 The amount of token 0 in the reserves
   * @param _reserve1 The amount of token 1 in the reserves
   * @param _amountIn1 The amount of token 1 to swap in
   * @param _amountOut1 The amount of token 1 to swap out
   * @param _swapMultiplier The multiplier to apply to the swap
   * @param _liquidityFraction The fraction relative to the amount of token 1 to scale the reserves to
   * @param _minK The minimum value of K to ensure that the reserves are not scaled too small
   * @return reserve0 The new amount of token 0 in the reserves
   * @return reserve1 The new amount of token 1 in the reserves
   */
  function _virtualSwap(
    uint128 _reserve0,
    uint128 _reserve1,
    uint256 _amountIn1,
    uint256 _amountOut1,
    UFixed32x4 _swapMultiplier,
    UFixed32x4 _liquidityFraction,
    uint256 _minK
  ) internal pure returns (uint128 reserve0, uint128 reserve1) {
    uint256 virtualAmountOut1 = FixedMathLib.mul(_amountOut1, _swapMultiplier);

    uint256 virtualAmountIn0 = 0;
    if (virtualAmountOut1 < _reserve1) {
      // Sufficient reserves to handle the multiplier on the swap
      virtualAmountIn0 = getAmountIn(virtualAmountOut1, _reserve0, _reserve1);
    } else if (virtualAmountOut1 > 0 && _reserve1 > 1) {
      // Insuffucuent reserves in so cap it to max amount
      virtualAmountOut1 = _reserve1 - 1;
      virtualAmountIn0 = getAmountIn(virtualAmountOut1, _reserve0, _reserve1);
    } else {
      // Insufficient reserves
      // _reserve1 is 1, virtualAmountOut1 is 0
      virtualAmountOut1 = 0;
    }

    reserve0 = _reserve0 + uint128(virtualAmountIn0);
    reserve1 = _reserve1 - uint128(virtualAmountOut1);

    (reserve0, reserve1) = _applyLiquidityFraction(
      reserve0,
      reserve1,
      _amountIn1,
      _liquidityFraction,
      _minK
    );
  }

  /**
   * @notice Scales the reserves to a configured ratio.
   * @dev This is to ensure that the virtual reserves are large enough such that the next swap will
   *      have a tailored impact on the virtual reserves.
   * @param _reserve0 The amount of token 0 in the reserves
   * @param _reserve1 The amount of token 1 in the reserves
   * @param _amountIn1 The amount of token 1 swapped in
   * @param _liquidityFraction The fraction relative to the amount in of token 1 to scale the
   *                            reserves to
   * @param _minK The minimum value of K to validate the scaled reserves against
   * @return reserve0 The new amount of token 0 in the reserves
   * @return reserve1 The new amount of token 1 in the reserves
   */
  function _applyLiquidityFraction(
    uint128 _reserve0,
    uint128 _reserve1,
    uint256 _amountIn1,
    UFixed32x4 _liquidityFraction,
    uint256 _minK
  ) internal pure returns (uint128 reserve0, uint128 reserve1) {
    uint256 reserve0_1 = (uint256(_reserve0) * _amountIn1 * FixedMathLib.multiplier) /
      (uint256(_reserve1) * UFixed32x4.unwrap(_liquidityFraction));
    uint256 reserve1_1 = FixedMathLib.div(_amountIn1, _liquidityFraction);

    // Ensure we can fit K into a uint256
    // Ensure new virtual reserves fit into uint112
    if (
      reserve0_1 <= type(uint112).max &&
      reserve1_1 <= type(uint112).max &&
      uint256(reserve1_1) * reserve0_1 > _minK
    ) {
      reserve0 = uint128(reserve0_1);
      reserve1 = uint128(reserve1_1);
    } else {
      reserve0 = _reserve0;
      reserve1 = _reserve1;
    }
  }

  /**
   * @notice Computes the amount of token 1 to swap in to get the provided amount of token 1 out.
   * @param _reserve0 The amount of token 0 in the reserves
   * @param _reserve1 The amount of token 1 in the reserves
   * @param _amountIn1 The amount of token 1 coming in
   * @param _amountOut1 The amount of token 1 to swap out
   * @return The amount of token 0 to swap in to receive the given amount out of token 1
   */
  function computeExactAmountIn(
    uint128 _reserve0,
    uint128 _reserve1,
    uint256 _amountIn1,
    uint256 _amountOut1
  ) internal pure returns (uint256) {
    require(_amountOut1 <= _amountIn1, "LiquidatorLib/insufficient-balance-liquidity-a");
    (uint128 reserve0, uint128 reserve1) = _virtualBuyback(_reserve0, _reserve1, _amountIn1);
    return getAmountIn(_amountOut1, reserve0, reserve1);
  }

  /**
   * @notice Computes the amount of token 1 to swap out to get the procided amount of token 1 in.
   * @param _reserve0 The amount of token 0 in the reserves
   * @param _reserve1 The amount of token 1 in the reserves
   * @param _amountIn1 The amount of token 1 coming in
   * @param _amountIn0 The amount of token 0 to swap in
   * @return The amount of token 1 to swap out to receive the given amount in of token 0
   */
  function computeExactAmountOut(
    uint128 _reserve0,
    uint128 _reserve1,
    uint256 _amountIn1,
    uint256 _amountIn0
  ) internal pure returns (uint256) {
    (uint128 reserve0, uint128 reserve1) = _virtualBuyback(_reserve0, _reserve1, _amountIn1);
    uint256 amountOut1 = getAmountOut(_amountIn0, reserve0, reserve1);
    require(amountOut1 <= _amountIn1, "LiquidatorLib/insufficient-balance-liquidity-b");
    return amountOut1;
  }

  /**
   * @notice Adjusts the provided reserves based on the amount of token 1 coming in and performs
   *          a swap with the provided amount of token 0 in for token 1 out. Finally, scales the
   *          reserves using the provided liquidity fraction, token 1 coming in and minimum k.
   * @param _reserve0 The amount of token 0 in the reserves
   * @param _reserve1 The amount of token 1 in the reserves
   * @param _amountIn1 The amount of token 1 coming in
   * @param _amountIn0 The amount of token 0 to swap in to receive token 1 out
   * @param _swapMultiplier The multiplier to apply to the swap
   * @param _liquidityFraction The fraction relative to the amount in of token 1 to scale the
   *                           reserves to
   * @param _minK The minimum value of K to validate the scaled reserves against
   * @return reserve0 The new amount of token 0 in the reserves
   * @return reserve1 The new amount of token 1 in the reserves
   * @return amountOut1 The amount of token 1 swapped out
   */
  function swapExactAmountIn(
    uint128 _reserve0,
    uint128 _reserve1,
    uint256 _amountIn1,
    uint256 _amountIn0,
    UFixed32x4 _swapMultiplier,
    UFixed32x4 _liquidityFraction,
    uint256 _minK
  ) internal pure returns (uint128 reserve0, uint128 reserve1, uint256 amountOut1) {
    (reserve0, reserve1) = _virtualBuyback(_reserve0, _reserve1, _amountIn1);

    amountOut1 = getAmountOut(_amountIn0, reserve0, reserve1);
    require(amountOut1 <= _amountIn1, "LiquidatorLib/insufficient-balance-liquidity-c");
    reserve0 = reserve0 + uint128(_amountIn0);
    reserve1 = reserve1 - uint128(amountOut1);

    (reserve0, reserve1) = _virtualSwap(
      reserve0,
      reserve1,
      _amountIn1,
      amountOut1,
      _swapMultiplier,
      _liquidityFraction,
      _minK
    );
  }

  /**
   * @notice Adjusts the provided reserves based on the amount of token 1 coming in and performs
   *         a swap with the provided amount of token 1 out for token 0 in. Finally, scales the
   *        reserves using the provided liquidity fraction, token 1 coming in and minimum k.
   * @param _reserve0 The amount of token 0 in the reserves
   * @param _reserve1 The amount of token 1 in the reserves
   * @param _amountIn1 The amount of token 1 coming in
   * @param _amountOut1 The amount of token 1 to swap out to receive token 0 in
   * @param _swapMultiplier The multiplier to apply to the swap
   * @param _liquidityFraction The fraction relative to the amount in of token 1 to scale the
   *                          reserves to
   * @param _minK The minimum value of K to validate the scaled reserves against
   * @return reserve0 The new amount of token 0 in the reserves
   * @return reserve1 The new amount of token 1 in the reserves
   * @return amountIn0 The amount of token 0 swapped in
   */
  function swapExactAmountOut(
    uint128 _reserve0,
    uint128 _reserve1,
    uint256 _amountIn1,
    uint256 _amountOut1,
    UFixed32x4 _swapMultiplier,
    UFixed32x4 _liquidityFraction,
    uint256 _minK
  ) internal pure returns (uint128 reserve0, uint128 reserve1, uint256 amountIn0) {
    require(_amountOut1 <= _amountIn1, "LiquidatorLib/insufficient-balance-liquidity-d");
    (reserve0, reserve1) = _virtualBuyback(_reserve0, _reserve1, _amountIn1);

    // do swap
    amountIn0 = getAmountIn(_amountOut1, reserve0, reserve1);
    reserve0 = reserve0 + uint128(amountIn0);
    reserve1 = reserve1 - uint128(_amountOut1);

    (reserve0, reserve1) = _virtualSwap(
      reserve0,
      reserve1,
      _amountIn1,
      _amountOut1,
      _swapMultiplier,
      _liquidityFraction,
      _minK
    );
  }
}

File 3 of 6 : FixedMathLib.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.17;

type UFixed32x4 is uint32;

/**
 * @title FixedMathLib
 * @author PoolTogether Inc. Team
 * @notice A minimal library to do fixed point operations with 4 decimals of precision.
 */
library FixedMathLib {
  uint256 constant multiplier = 1e4;

  /**
   * @notice Multiply a uint256 by a UFixed32x4.
   * @param a The uint256 to multiply.
   * @param b The UFixed32x4 to multiply.
   * @return The product of a and b.
   */
  function mul(uint256 a, UFixed32x4 b) internal pure returns (uint256) {
    require(a <= type(uint224).max, "FixedMathLib/a-less-than-224-bits");
    return (a * UFixed32x4.unwrap(b)) / multiplier;
  }

  /**
   * @notice Divide a uint256 by a UFixed32x4.
   * @param a The uint256 to divide.
   * @param b The UFixed32x4 to divide.
   * @return The quotient of a and b.
   */
  function div(uint256 a, UFixed32x4 b) internal pure returns (uint256) {
    require(UFixed32x4.unwrap(b) > 0, "FixedMathLib/b-greater-than-zero");
    require(a <= type(uint224).max, "FixedMathLib/a-less-than-224-bits");
    return (a * multiplier) / UFixed32x4.unwrap(b);
  }
}

File 4 of 6 : ILiquidationSource.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.17;

interface ILiquidationSource {
  /**
   * @notice Get the available amount of tokens that can be swapped.
   * @param tokenOut Address of the token to get available balance for
   * @return uint256 Available amount of `token`
   */
  function liquidatableBalanceOf(address tokenOut) external view returns (uint256);

  /**
   * @notice Liquidate `amountIn` of `tokenIn` for `amountOut` of `tokenOut` and transfer to `account`.
   * @param account Address of the account that will receive `tokenOut`
   * @param tokenIn Address of the token being sold
   * @param amountIn Amount of token being sold
   * @param tokenOut Address of the token being bought
   * @param amountOut Amount of token being bought
   * @return bool Return true once the liquidation has been completed
   */
  function liquidate(
    address account,
    address tokenIn,
    uint256 amountIn,
    address tokenOut,
    uint256 amountOut
  ) external returns (bool);

  /**
   * @notice Get the address that will receive `tokenIn`.
   * @param tokenIn Address of the token to get the target address for
   * @return address Address of the target
   */
  function targetOf(address tokenIn) external view returns (address);
}

File 5 of 6 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

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

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

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

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 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) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

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

            ///////////////////////////////////////////////
            // 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.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

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

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

            // Shift in bits from prod1 into prod0.
            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 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 x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
        }
    }
}

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

Settings
{
  "remappings": [
    "@prb/test/=lib/prb-math/lib/prb-test/src/",
    "brokentoken/=lib/v5-vault/lib/brokentoken/src/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/v5-vault/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "owner-manager-contracts/=lib/v5-liquidator/lib/owner-manager-contracts/contracts/",
    "owner-manager/=lib/v5-draw-beacon/lib/owner-manager-contracts/contracts/",
    "pooltogether-rng-contracts/=lib/v5-draw-beacon/lib/pooltogether-rng-contracts/contracts/",
    "prb-math/=lib/prb-math/src/",
    "prb-test/=lib/prb-math/lib/prb-test/src/",
    "ring-buffer-lib/=lib/v5-prize-pool/lib/ring-buffer-lib/src/",
    "rng/=lib/v5-draw-beacon/lib/pooltogether-rng-contracts/contracts/",
    "script/=script/",
    "solidity-stringutils/=lib/solidity-stringutils/",
    "solmate/=lib/v5-liquidator/lib/solmate/src/",
    "src/=src/",
    "test/=test/",
    "v4-core/=lib/v5-vrgda-claimer/lib/v5-prize-pool/lib/v5-twab-controller/lib/v4-core/contracts/",
    "v5-draw-beacon/=lib/v5-draw-beacon/src/",
    "v5-liquidator-interfaces/=lib/v5-liquidator/src/interfaces/",
    "v5-liquidator-libraries/=lib/v5-liquidator/src/libraries/",
    "v5-liquidator-test/=lib/v5-vault/lib/v5-liquidator/test/",
    "v5-liquidator/=lib/v5-liquidator/src/",
    "v5-prize-pool/=lib/v5-prize-pool/src/",
    "v5-twab-controller/=lib/v5-twab-controller/src/",
    "v5-vault-mock/=lib/v5-vault/test/contracts/mock/",
    "v5-vault/=lib/v5-vault/src/",
    "v5-vrgda-claimer/=lib/v5-vrgda-claimer/src/",
    "weird-erc20/=lib/v5-vault/lib/brokentoken/lib/weird-erc20/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract ABI

[{"inputs":[{"internalType":"contract ILiquidationSource","name":"_source","type":"address"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"UFixed32x4","name":"_swapMultiplier","type":"uint32"},{"internalType":"UFixed32x4","name":"_liquidityFraction","type":"uint32"},{"internalType":"uint128","name":"_virtualReserveIn","type":"uint128"},{"internalType":"uint128","name":"_virtualReserveOut","type":"uint128"},{"internalType":"uint256","name":"_minK","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"virtualReserveIn","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"virtualReserveOut","type":"uint128"}],"name":"Swapped","type":"event"},{"inputs":[{"internalType":"uint256","name":"_amountOut","type":"uint256"}],"name":"computeExactAmountIn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"}],"name":"computeExactAmountOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityFraction","outputs":[{"internalType":"UFixed32x4","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxAmountIn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxAmountOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextLiquidationState","outputs":[{"internalType":"uint128","name":"","type":"uint128"},{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"source","outputs":[{"internalType":"contract ILiquidationSource","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_amountOutMin","type":"uint256"}],"name":"swapExactAmountIn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_amountOut","type":"uint256"},{"internalType":"uint256","name":"_amountInMax","type":"uint256"}],"name":"swapExactAmountOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapMultiplier","outputs":[{"internalType":"UFixed32x4","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"target","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenIn","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenOut","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"virtualReserveIn","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"virtualReserveOut","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"}]

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101005760003560e01c80639858b48811610097578063d0202d3b11610066578063d0202d3b14610296578063d4b83992146102bd578063d61de423146102c5578063fcbda2a4146102d857600080fd5b80639858b48814610241578063ae81df9714610268578063b8824a851461027b578063c57f19221461028357600080fd5b806366c29790116100d357806366c29790146101ac57806367e828bf146101d35780636daf390b146102125780637ed9038b1461023957600080fd5b80630aa58b21146101055780631e53a4ac1461012b5780633e0279491461015d5780634e376a9f14610199575b600080fd5b610118610113366004610fd9565b610300565b6040519081526020015b60405180910390f35b60005461014590600160801b90046001600160801b031681565b6040516001600160801b039091168152602001610122565b6101847f00000000000000000000000000000000000000000000000000000000000000c881565b60405163ffffffff9091168152602001610122565b6101186101a736600461100a565b610330565b6101187f0000000000000000000000000000000000000000000000ae4bdd0523ebf0000081565b6101fa7f000000000000000000000000ddaa05da72f50b83af888988977e71880516357981565b6040516001600160a01b039091168152602001610122565b6101fa7f000000000000000000000000c138a7c89c357d8fa5a9b7ce775e612b766153e781565b6101186104bf565b6101847f0000000000000000000000000000000000000000000000000000000000000bb881565b610118610276366004610fd9565b6104ce565b6101186104f8565b61011861029136600461100a565b610529565b6101fa7f000000000000000000000000ddaa05da72f50b83af888988977e71880516357981565b6101fa6106a4565b600054610145906001600160801b031681565b6102e0610753565b604080516001600160801b03938416815292909116602083015201610122565b6000805461032a906001600160801b0380821691600160801b900416610324610786565b85610835565b92915050565b60008061033b610786565b6000805491925090819081906103c9906001600160801b0380821691600160801b900416868a7f0000000000000000000000000000000000000000000000000000000000000bb87f00000000000000000000000000000000000000000000000000000000000000c87f0000000000000000000000000000000000000000000000ae4bdd0523ebf000006108b4565b6001600160801b03808316600160801b029084161760005591945092509050858110156104485760405162461bcd60e51b815260206004820152602260248201527f4c69717569646174696f6e506169722f6d696e2d6e6f742d67756172616e7465604482015261195960f21b60648201526084015b60405180910390fd5b610453888289610964565b60408051888152602081018390526001600160801b038086169282019290925290831660608201526001600160a01b038916907f3ef397fda41c8c79a1ead6c9e181d00d932fb117da234098e794ca71e76dceee906080015b60405180910390a2979650505050505050565b60006104c9610786565b905090565b6000805461032a906001600160801b0380821691600160801b9004166104f2610786565b85610a54565b600080546104c9906001600160801b0380821691600160801b90041661051c610786565b610524610786565b610835565b600080610534610786565b6000805491925090819081906105c2906001600160801b0380821691600160801b900416868a7f0000000000000000000000000000000000000000000000000000000000000bb87f00000000000000000000000000000000000000000000000000000000000000c87f0000000000000000000000000000000000000000000000ae4bdd0523ebf00000610acc565b6001600160801b03808316600160801b0290841617600055919450925090508581111561063c5760405162461bcd60e51b815260206004820152602260248201527f4c69717569646174696f6e506169722f6d61782d6e6f742d67756172616e7465604482015261195960f21b606482015260840161043f565b610647888883610964565b60408051828152602081018990526001600160801b038086169282019290925290831660608201526001600160a01b038916907f3ef397fda41c8c79a1ead6c9e181d00d932fb117da234098e794ca71e76dceee906080016104ac565b60405163700f04ef60e01b81526001600160a01b037f000000000000000000000000c138a7c89c357d8fa5a9b7ce775e612b766153e7811660048301526000917f000000000000000000000000ddaa05da72f50b83af888988977e7188051635799091169063700f04ef90602401602060405180830381865afa15801561072f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104c9919061103f565b60008054819061077e906001600160801b0380821691600160801b900416610779610786565b610b6a565b915091509091565b60405163587e7b1360e11b81526001600160a01b037f000000000000000000000000ddaa05da72f50b83af888988977e718805163579811660048301526000917f000000000000000000000000ddaa05da72f50b83af888988977e7188051635799091169063b0fcf62690602401602060405180830381865afa158015610811573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104c9919061105c565b60008282111561088c5760405162461bcd60e51b815260206004820152602e602482015260008051602061119583398151915260448201526d63652d6c69717569646974792d6160901b606482015260840161043f565b60008061089a878787610b6a565b915091506108a9848383610b9d565b979650505050505050565b60008060006108c48a8a8a610b6a565b90935091506108d4878484610ce0565b90508781111561092b5760405162461bcd60e51b815260206004820152602e602482015260008051602061119583398151915260448201526d63652d6c69717569646974792d6360901b606482015260840161043f565b610935878461108b565b925061094181836110b2565b915061095283838a848a8a8a610d9e565b909b909a509098509650505050505050565b60405163b947346160e01b81526001600160a01b0384811660048301527f000000000000000000000000c138a7c89c357d8fa5a9b7ce775e612b766153e781166024830152604482018390527f000000000000000000000000ddaa05da72f50b83af888988977e71880516357981166064830152608482018490527f000000000000000000000000ddaa05da72f50b83af888988977e718805163579169063b94734619060a4016020604051808303816000875af1158015610a2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a4e91906110d2565b50505050565b6000806000610a64878787610b6a565b915091506000610a75858484610ce0565b9050858111156108a95760405162461bcd60e51b815260206004820152602e602482015260008051602061119583398151915260448201526d31b296b634b8bab4b234ba3c96b160911b606482015260840161043f565b600080600087871115610b265760405162461bcd60e51b815260206004820152602e602482015260008051602061119583398151915260448201526d18d94b5b1a5c5d5a591a5d1e4b5960921b606482015260840161043f565b610b318a8a8a610b6a565b9093509150610b41878484610b9d565b9050610b4d818461108b565b9250610b5987836110b2565b915061095283838a8a8a8a8a610d9e565b6000806000610b7a848688610ce0565b9050610b8681876110b2565b9250610b92848661108b565b915050935093915050565b6000816001600160801b03168410610c0e5760405162461bcd60e51b815260206004820152602e60248201527f4c697175696461746f724c69622f696e73756666696369656e742d726573657260448201526d76652d6c69717569646974792d6360901b606482015260840161043f565b6000826001600160801b0316118015610c3057506000836001600160801b0316115b610c935760405162461bcd60e51b815260206004820152602e60248201527f4c697175696461746f724c69622f696e73756666696369656e742d726573657260448201526d1d994b5b1a5c5d5a591a5d1e4b5960921b606482015260840161043f565b6000610ca86001600160801b038516866110f4565b90506000610cbf866001600160801b03861661110b565b9050610ccb818361111e565b610cd6906001611140565b9695505050505050565b600080826001600160801b0316118015610d0357506000836001600160801b0316115b610d665760405162461bcd60e51b815260206004820152602e60248201527f4c697175696461746f724c69622f696e73756666696369656e742d726573657260448201526d76652d6c69717569646974792d6160901b606482015260840161043f565b6000610d7b6001600160801b038416866110f4565b90506000610d926001600160801b03861687611140565b9050610cd6818361111e565b6000806000610dad8787610e4f565b90506000896001600160801b0316821015610dd457610dcd828c8c610b9d565b9050610e18565b600082118015610ded575060018a6001600160801b0316115b15610e1357610dfd60018b6110b2565b6001600160801b03169150610dcd828c8c610b9d565b600091505b610e22818c61108b565b9350610e2e828b6110b2565b9250610e3d84848b8989610e9c565b909c909b509950505050505050505050565b60006001600160e01b03831115610e785760405162461bcd60e51b815260040161043f90611153565b612710610e8b63ffffffff8416856110f4565b610e95919061111e565b9392505050565b60008080610eb963ffffffff86166001600160801b0389166110f4565b612710610ecf886001600160801b038c166110f4565b610ed991906110f4565b610ee3919061111e565b90506000610ef18787610f48565b90506001600160701b038211801590610f1157506001600160701b038111155b8015610f25575084610f2383836110f4565b115b15610f3557819350809250610f3c565b8893508792505b50509550959350505050565b6000808263ffffffff1611610f9f5760405162461bcd60e51b815260206004820181905260248201527f46697865644d6174684c69622f622d677265617465722d7468616e2d7a65726f604482015260640161043f565b6001600160e01b03831115610fc65760405162461bcd60e51b815260040161043f90611153565b63ffffffff8216610e8b612710856110f4565b600060208284031215610feb57600080fd5b5035919050565b6001600160a01b038116811461100757600080fd5b50565b60008060006060848603121561101f57600080fd5b833561102a81610ff2565b95602085013595506040909401359392505050565b60006020828403121561105157600080fd5b8151610e9581610ff2565b60006020828403121561106e57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b6001600160801b038181168382160190808211156110ab576110ab611075565b5092915050565b6001600160801b038281168282160390808211156110ab576110ab611075565b6000602082840312156110e457600080fd5b81518015158114610e9557600080fd5b808202811582820484141761032a5761032a611075565b8181038181111561032a5761032a611075565b60008261113b57634e487b7160e01b600052601260045260246000fd5b500490565b8082018082111561032a5761032a611075565b60208082526021908201527f46697865644d6174684c69622f612d6c6573732d7468616e2d3232342d6269746040820152607360f81b60608201526080019056fe4c697175696461746f724c69622f696e73756666696369656e742d62616c616ea2646970667358221220ae81228bc491193dc84d6e02318a3fd8cfa2245717a0f6fecdcdf446017689e164736f6c63430008110033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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