ETH Price: $3,403.23 (+6.76%)
Gas: 18 Gwei

Contract

0xFf73827eaA3A11255c19AdbA10b8f906bc54FA32
 

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

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
184725192023-10-31 20:34:11257 days ago1698784451  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
VaultFacet

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
shanghai EvmVersion
File 1 of 10 : VaultFacet.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.21;

import {U256} from "contracts/libraries/PRBMathHelper.sol";

import {IAsset as IERC20} from "interfaces/IAsset.sol";

import {Modifiers} from "contracts/libraries/AppStorage.sol";
import {Errors} from "contracts/libraries/Errors.sol";
import {STypes} from "contracts/libraries/DataTypes.sol";
import {Vault} from "contracts/libraries/Constants.sol";

// import {console} from "contracts/libraries/console.sol";

/**
 * @title VaultFacet
 *
 * @notice Contract that owns all of the ETH and ERC20 tokens for the entire network
 */

contract VaultFacet is Modifiers {
    using U256 for uint256;

    address private immutable dethOne;

    constructor(address _deth) {
        dethOne = _deth;
    }

    /**
     * @notice Deposit DETH token into market system
     * @dev No event needed. Use the transfer event emitted in burnFrom
     * @param amount Deposit amount
     */
    function depositDETH(address deth, uint88 amount) external nonReentrant {
        if (amount == 0) revert Errors.PriceOrAmountIs0();

        uint256 vault;
        if (deth == dethOne) {
            vault = Vault.ONE;
        } else {
            if (s.dethVault[deth] == 0) revert Errors.InvalidDeth();
            vault = s.dethVault[deth];
        }
        IERC20(deth).burnFrom(msg.sender, amount);
        s.vaultUser[vault][msg.sender].ethEscrowed += amount;
    }

    /**
     * @notice Deposit ERC20 token into market system
     * @dev If frozen, prevent asset deposit
     * No event needed. Use the transfer event emitted in burnFrom
     * @param asset Asset address
     * @param amount Deposit amount
     */
    function depositAsset(address asset, uint104 amount)
        external
        onlyValidAsset(asset)
        isNotFrozen(asset)
        nonReentrant
    {
        if (amount == 0) revert Errors.PriceOrAmountIs0();

        IERC20(asset).burnFrom(msg.sender, amount);
        s.assetUser[asset][msg.sender].ercEscrowed += amount;
    }

    /**
     * @notice Withdraw DETH from market system
     *
     * @param amount Withdrawal amount
     */
    function withdrawDETH(address deth, uint88 amount) external nonReentrant {
        if (amount == 0) revert Errors.PriceOrAmountIs0();

        uint256 vault;
        if (deth == dethOne) {
            vault = Vault.ONE;
        } else {
            if (s.dethVault[deth] == 0) revert Errors.InvalidDeth();
            vault = s.dethVault[deth];
        }

        STypes.VaultUser storage VaultUser = s.vaultUser[vault][msg.sender];
        if (amount > VaultUser.ethEscrowed) revert Errors.InsufficientETHEscrowed();

        VaultUser.ethEscrowed -= amount;
        IERC20(deth).mint(msg.sender, amount);
    }

    /**
     * @notice Withdraw ERC20 token from market system
     *
     * @param asset Asset address
     * @param amount Withdrawal amount
     */
    function withdrawAsset(address asset, uint104 amount)
        external
        onlyValidAsset(asset)
        nonReentrant
    {
        if (amount == 0) revert Errors.PriceOrAmountIs0();

        STypes.AssetUser storage AssetUser = s.assetUser[asset][msg.sender];
        if (amount > AssetUser.ercEscrowed) revert Errors.InsufficientERCEscrowed();

        AssetUser.ercEscrowed -= amount;
        IERC20(asset).mint(msg.sender, amount);
    }
}

File 2 of 10 : PRBMathHelper.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.21;

import {mulDiv as _mulDiv, mulDiv18, UNIT} from "@prb/math/src/Common.sol";
import {Errors} from "contracts/libraries/Errors.sol";

library U256 {
    function mul(uint256 x, uint256 y) internal pure returns (uint256 result) {
        result = mulDiv18(x, y);
    }

    function div(uint256 x, uint256 y) internal pure returns (uint256 result) {
        result = _mulDiv(x, UNIT, y);
    }

    function mulDiv(uint256 x, uint256 y, uint256 denominator)
        internal
        pure
        returns (uint256 result)
    {
        return _mulDiv(x, y, denominator);
    }

    function inv(uint256 x) internal pure returns (uint256 result) {
        unchecked {
            // 1e36 is UNIT * UNIT.
            result = 1e36 / x;
        }
    }

    function divU80(uint256 x, uint256 y) internal pure returns (uint80 result) {
        uint256 _result = _mulDiv(x, UNIT, y);
        if (_result > type(uint80).max) revert Errors.InvalidAmount(); // assume amount?
        result = uint80(_result);
    }

    function divU64(uint256 x, uint256 y) internal pure returns (uint64 result) {
        uint256 _result = _mulDiv(x, UNIT, y);
        if (_result > type(uint64).max) revert Errors.InvalidAmount(); // assume amount?
        result = uint64(_result);
    }

    // test
    function divU88(uint256 x, uint256 y) internal pure returns (uint88 result) {
        uint256 _result = _mulDiv(x, UNIT, y);
        if (_result > type(uint88).max) revert Errors.InvalidAmount(); // assume amount?
        result = uint88(_result);
    }
}

// uint128
library Math128 {
    // just passing the result of casting the first param to 256
    function mul(uint128 x, uint256 y) internal pure returns (uint256 result) {
        result = mulDiv18(x, y);
    }

    function div(uint128 x, uint256 y) internal pure returns (uint256 result) {
        result = _mulDiv(x, UNIT, y);
    }
}

// uint104
library Math104 {
    // just passing the result of casting the first param to 256
    function mul(uint104 x, uint256 y) internal pure returns (uint256 result) {
        result = mulDiv18(x, y);
    }

    function div(uint104 x, uint256 y) internal pure returns (uint256 result) {
        result = _mulDiv(x, UNIT, y);
    }
}

// uint96
library U96 {
    // just passing the result of casting the first param to 256
    function mul(uint96 x, uint256 y) internal pure returns (uint256 result) {
        result = mulDiv18(x, y);
    }

    function div(uint96 x, uint256 y) internal pure returns (uint256 result) {
        result = _mulDiv(x, UNIT, y);
    }

    function divU64(uint96 x, uint256 y) internal pure returns (uint64 result) {
        uint256 _result = _mulDiv(x, UNIT, y);
        if (_result > type(uint64).max) revert Errors.InvalidAmount(); // assume amount?
        result = uint64(_result);
    }
}

// uint88
library U88 {
    // just passing the result of casting the first param to 256
    function mul(uint88 x, uint256 y) internal pure returns (uint256 result) {
        result = mulDiv18(x, y);
    }

    function mulU88(uint88 x, uint256 y) internal pure returns (uint88 result) {
        uint256 _result = mulDiv18(x, y);
        if (_result > type(uint88).max) revert Errors.InvalidAmount(); // assume amount?
        result = uint88(_result);
    }

    function div(uint88 x, uint256 y) internal pure returns (uint256 result) {
        result = _mulDiv(x, UNIT, y);
    }

    function divU88(uint88 x, uint256 y) internal pure returns (uint88 result) {
        uint256 _result = _mulDiv(x, UNIT, y);
        if (_result > type(uint88).max) revert Errors.InvalidAmount(); // assume amount?
        result = uint88(_result);
    }

    function divU80(uint88 x, uint256 y) internal pure returns (uint80 result) {
        uint256 _result = _mulDiv(x, UNIT, y);
        if (_result > type(uint80).max) revert Errors.InvalidAmount(); // assume amount?
        result = uint80(_result);
    }
}

// uint80
library U80 {
    // just passing the result of casting the first param to 256
    function mul(uint80 x, uint256 y) internal pure returns (uint256 result) {
        result = mulDiv18(x, y);
    }

    function mulU80(uint80 x, uint256 y) internal pure returns (uint80 result) {
        uint256 _result = mulDiv18(x, y);
        if (_result > type(uint80).max) revert Errors.InvalidPrice(); // assume price?
        result = uint80(_result);
    }

    function mulU88(uint80 x, uint256 y) internal pure returns (uint88 result) {
        uint256 _result = mulDiv18(x, y);
        if (_result > type(uint80).max) revert Errors.InvalidPrice(); // assume price?
        result = uint88(_result);
    }

    function div(uint80 x, uint256 y) internal pure returns (uint256 result) {
        result = _mulDiv(x, UNIT, y);
    }

    // test
    function inv(uint80 x) internal pure returns (uint256 result) {
        unchecked {
            // 1e36 is UNIT * UNIT.
            result = 1e36 / x;
        }
    }
}

File 3 of 10 : IAsset.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.21;



interface IAsset {

  // functions from node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol
  function name() external view returns (string memory);
  function symbol() external view returns (string memory);
  function decimals() external view returns (uint8);
  function totalSupply() external view returns (uint256);
  function balanceOf(address account) external view returns (uint256);
  function transfer(address to, uint256 amount) external returns (bool);
  function allowance(address owner, address spender) external view returns (uint256);
  function approve(address spender, uint256 amount) external returns (bool);
  function transferFrom(address from, address to, uint256 amount) external returns (bool);
  function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
  function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);

  // functions from node_modules/@openzeppelin/contracts/utils/cryptography/EIP712.sol
  function eip712Domain() external view returns (bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions);

  // functions from node_modules/@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol
  function permit(
        address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;
  function nonces(address owner) external view returns (uint256);
  function DOMAIN_SEPARATOR() external view returns (bytes32);

  // functions from contracts/tokens/Asset.sol
  function mint(address to, uint256 amount) external;
  function burnFrom(address account, uint256 amount) external;
}

File 4 of 10 : AppStorage.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.21;

import {STypes, F, SR} from "contracts/libraries/DataTypes.sol";
import {LibDiamond} from "contracts/libraries/LibDiamond.sol";
import {Errors} from "contracts/libraries/Errors.sol";
import {Constants} from "contracts/libraries/Constants.sol";

// import {console} from "contracts/libraries/console.sol";

struct AppStorage {
    address admin;
    address ownerCandidate;
    address baseOracle;
    uint24 flaggerIdCounter;
    uint40 tokenIdCounter; //NFT - As of 2023, Ethereum had ~2B total tx. Uint40 max value is 1T, which is more than enough for NFTs
    uint8 reentrantStatus;
    // DETH
    mapping(address deth => uint256 vault) dethVault;
    // Bridge
    mapping(address bridge => STypes.Bridge) bridge;
    // Vault
    mapping(uint256 vault => STypes.Vault) vault;
    mapping(uint256 vault => address[]) vaultBridges;
    mapping(uint256 vault => mapping(address account => STypes.VaultUser)) vaultUser;
    // Assets
    mapping(address asset => STypes.Asset) asset;
    mapping(address asset => mapping(address account => STypes.AssetUser)) assetUser;
    // Assets - Orderbook
    mapping(address asset => mapping(uint16 id => STypes.Order)) bids;
    mapping(address asset => mapping(uint16 id => STypes.Order)) asks;
    mapping(address asset => mapping(uint16 id => STypes.Order)) shorts;
    mapping(
        address asset
            => mapping(address account => mapping(uint8 id => STypes.ShortRecord))
        ) shortRecords;
    mapping(uint24 flaggerId => address flagger) flagMapping;
    // ERC721
    mapping(uint256 tokenId => STypes.NFT) nftMapping;
    mapping(uint256 tokenId => address) getApproved;
    mapping(address owner => mapping(address operator => bool)) isApprovedForAll;
    // ERC721 - Assets
    address[] assets;
    mapping(uint256 assetId => address) assetMapping;
    // ERC721 - METADATA STORAGE/LOGIC
    string name;
    string symbol;
}

function appStorage() pure returns (AppStorage storage s) {
    // solhint-disable-next-line no-inline-assembly
    assembly {
        s.slot := 0
    }
}

contract Modifiers {
    AppStorage internal s;

    modifier onlyDAO() {
        LibDiamond.enforceIsContractOwner();
        _;
    }

    modifier onlyAdminOrDAO() {
        if (msg.sender != LibDiamond.contractOwner() && msg.sender != s.admin) {
            revert Errors.NotOwnerOrAdmin();
        }
        _;
    }

    modifier onlyDiamond() {
        if (msg.sender != address(this)) revert Errors.NotDiamond();
        _;
    }

    modifier onlyValidAsset(address asset) {
        if (s.asset[asset].vault == 0) revert Errors.InvalidAsset();
        _;
    }

    modifier isNotFrozen(address asset) {
        if (s.asset[asset].frozen != F.Unfrozen) revert Errors.AssetIsFrozen();
        _;
    }

    modifier isPermanentlyFrozen(address asset) {
        if (s.asset[asset].frozen != F.Permanent) {
            revert Errors.AssetIsNotPermanentlyFrozen();
        }
        _;
    }

    function _onlyValidShortRecord(address asset, address shorter, uint8 id)
        internal
        view
    {
        uint8 maxId = s.assetUser[asset][shorter].shortRecordIdCounter;
        if (id >= maxId) revert Errors.InvalidShortId();
        if (id < Constants.SHORT_STARTING_ID) revert Errors.InvalidShortId();
        if (s.shortRecords[asset][shorter][id].status == SR.Closed) {
            revert Errors.InvalidShortId();
        }
    }

    modifier onlyValidShortRecord(address asset, address shorter, uint8 id) {
        _onlyValidShortRecord(asset, shorter, id);
        _;
    }

    modifier nonReentrant() {
        if (s.reentrantStatus == Constants.ENTERED) revert Errors.ReentrantCall();
        s.reentrantStatus = Constants.ENTERED;
        _;
        s.reentrantStatus = Constants.NOT_ENTERED;
    }

    modifier nonReentrantView() {
        if (s.reentrantStatus == Constants.ENTERED) revert Errors.ReentrantCallView();
        _;
    }

    modifier onlyValidBridge(address bridge) {
        if (s.bridge[bridge].vault == 0) revert Errors.InvalidBridge();
        _;
    }
}

File 5 of 10 : Errors.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.21;

library Errors {
    error AlreadyMinted();
    error AssetIsFrozen();
    error AssetIsNotPermanentlyFrozen();
    error BadHintIdArray();
    error BadShortHint();
    error BridgeAlreadyCreated();
    error CannotCancelMoreThan1000Orders();
    error CannotExitPartialFillSR();
    error CannotFlagSelf();
    error CannotLeaveDustAmount();
    error CannotLiquidateSelf();
    error CannotMintAnymoreNFTs();
    error CannotMintLastShortRecord();
    error CannotSocializeDebt();
    error CannotTransferFlaggableShort();
    error CannotTransferFlaggedShort();
    error CollateralHigherThanMax();
    error CRLowerThanMin();
    error DifferentVaults();
    error ExitShortPriceTooLow();
    error FirstShortDeleted();
    error FirstShortMustBeNFT();
    error FunctionNotFound(bytes4 _functionSelector);
    error AlreadyLiquidatable();
    error InvalidAmount();
    error InvalidAsset();
    error InvalidBridge();
    error InvalidBuyback();
    error InvalidFlaggerHint();
    error InvalidInitialCR();
    error InvalidMsgValue();
    error InvalidPrice();
    error InvalidShortId();
    error InvalidTithe();
    error InvalidTokenId();
    error InvalidTwapPrice();
    error InvalidTWAPSecondsAgo();
    error InvalidVault();
    error InvalidDeth();
    error InsufficientWalletBalance();
    error InsufficientCollateral();
    error InsufficientERCEscrowed();
    error InsufficientETHEscrowed();
    error InsufficientEthInLiquidityPool();
    error InsufficientNumberOfShorts();
    error IsNotNFT();
    error LiquidationAlreadyFlagged();
    error LiquidationIneligibleWindow();
    error SecondaryLiquidationNoValidShorts();
    error MarketAlreadyCreated();
    error NoDittoReward();
    error NoSells();
    error NoShares();
    error NotActiveOrder();
    error NotBridgeForBaseCollateral();
    error NotDiamond();
    error NotLastOrder();
    error NotMinted();
    error NotOwner();
    error NotOwnerOrAdmin();
    error NotOwnerCandidate();
    error NoYield();
    error OrderIdCountTooLow();
    error OrderUnderMinimumSize();
    error OriginalShortRecordCancelled();
    error ParameterIsZero();
    error PostExitCRLtPreExitCR();
    error PriceOrAmountIs0();
    error ReceiverExceededShortRecordLimit();
    error ReentrantCall();
    error ReentrantCallView();
    error ShortNotFlagged();
    error ShortRecordIdOverflow();
    error ShortRecordIdsNotSorted();
    error SufficientCollateral();
    error TooManyHints();
    error UnderMinimum();
    error UnderMinimumDeposit();
    error VaultAlreadyCreated();

    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
     * Used in balance queries.
     * @param owner Address of the current owner of a token.
     */
    error ERC721InvalidOwner(address owner);
    /**
     * @dev Indicates a `tokenId` whose `owner` is the zero address.
     * @param tokenId Identifier number of a token.
     */
    error ERC721NonexistentToken(uint256 tokenId);
    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC721InvalidOperator(address operator);
    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param tokenId Identifier number of a token.
     */
    error ERC721InsufficientApproval(address operator, uint256 tokenId);
    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC721InvalidApprover(address approver);
    /**
     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param tokenId Identifier number of a token.
     * @param owner Address of the current owner of a token.
     */
    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC721InvalidReceiver(address receiver);
}

File 6 of 10 : DataTypes.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.21;

// import {console} from "contracts/libraries/console.sol";

//@dev leave room for others frozen types
//@dev Asset frozen status
enum F {
    Unfrozen,
    Permanent
}

// @dev if this is changed, modify orderTypetoString in libraries/console.sol
// @dev Order types
enum O {
    Uninitialized,
    LimitBid,
    LimitAsk,
    MarketBid,
    MarketAsk,
    LimitShort,
    Cancelled,
    Matched
}

// @dev ShortRecord status
enum SR {
    PartialFill,
    FullyFilled,
    Closed
}

// @dev oracle frequency
enum OF {
    OneHour,
    FifteenMinutes
}

// 2**n-1 with 18 decimals (prices, amount)
// uint64 = 18.45
// uint72 = 4.722k
// uint80 = 1.2m
// uint88 = 300m
// uint96 = 79B
// uint104 = 1.2t

// DataTypes used in storage
library STypes {
    // 2 slots
    struct Order {
        // SLOT 1: 88 + 80 + 16 + 16 + 16 + 8 + 8 + 16 + 8 = 256
        uint88 ercAmount; // max 300m erc
        uint80 price; // max 1.2m eth
        // max orders 65k, with id re-use
        uint16 prevId;
        uint16 id;
        uint16 nextId;
        O orderType;
        // @dev diff against contract creation timestamp to prevent overflow in 2106
        uint32 creationTime; // seconds
        // SLOT 2: 160 + 32 = 192 (64 unused)
        address addr; // 160
        O prevOrderType;
        // @dev storing as 170 with 2 decimals -> 1.70 ether
        uint16 initialCR; // @dev only used for LimitShort
        uint8 shortRecordId; // @dev only used for LimitShort
        uint64 filler;
    }

    // 2 slots
    // @dev dethYieldRate should match Vault
    struct ShortRecord {
        // SLOT 1: 88 + 88 + 80 = 256
        uint88 collateral; // price * ercAmount * initialCR
        uint88 ercDebt; // same as Order.ercAmount
        uint80 dethYieldRate;
        // SLOT 2: 64 + 40 + 32 + 24 + 8 + 8 + 8 + 8 = 184 (64 remaining)
        SR status;
        uint8 prevId;
        uint8 id;
        uint8 nextId;
        uint64 ercDebtRate; // socialized penalty rate
        uint32 updatedAt; // seconds
        uint32 flaggedAt; // seconds
        uint24 flaggerId;
        uint40 tokenId; // As of 2023, Ethereum had ~2B total tx. Uint40 max value is 1T, which is more than enough
    }

    struct NFT {
        // SLOT 1: 160 + 8 + 8 = 176 (80 unused)
        address owner;
        uint8 assetId;
        uint8 shortRecordId;
    }

    // uint8:  [0-255]
    // uint16: [0-65_535]
    // @dev see testMultiAssetSettings()
    struct Asset {
        // SLOT 1: 104 + 88 + 16 + 16 + 16 + 8 + 8 = 256 (0 unused)
        uint104 ercDebt; // max 20.2T
        uint88 dethCollateral;
        uint16 startingShortId;
        uint16 orderIdCounter; // max is uint16 but need to throw/handle that?
        uint16 initialCR; // 5 ether -> [1-10, 2 decimals]
        F frozen; // 0 or 1
        uint8 vault;
        // SLOT 2 (Liquidation Parameters)
        // 64 + 16*3 + 8*10 = 192 (64 unused)
        uint8 minBidEth; // 10 -> (1 * 10**18 / 10**2) = 0.1 ether
        uint8 minAskEth; // 10 -> (1 * 10**18 / 10**2) = 0.1 ether
        uint16 minShortErc; // 2000 -> (2000 * 10**18) -> 2000 ether
        uint8 minimumCR; // 1.1 ether -> [1-2, 2 decimals]
        uint8 tappFeePct; // 0.025 ether -> [0-2.5%, 3 decimals]
        uint8 callerFeePct; // 0.005 ether -> [0-2.5%, 3 decimals]
        uint8 forcedBidPriceBuffer; // 1.1 ether -> [1-2, 2 decimals]
        uint8 assetId;
        uint64 ercDebtRate; // max 18x, socialized penalty rate
        uint16 primaryLiquidationCR; // 1.5 ether -> [1-5, 2 decimals]
        uint16 secondaryLiquidationCR; // 1.4 ether -> [1-5, 2 decimals]
        uint8 resetLiquidationTime; // 12 hours -> [1-48 hours, 0 decimals]
        uint8 secondLiquidationTime; // 8 hours -> [1-48 hours, 0 decimals]
        uint8 firstLiquidationTime; // 6 hours -> [1-48 hours, 0 decimals]
        uint64 filler; // keep slots distinct
        // SLOT 3 (Chainlink)
        address oracle; // for non-usd asset
    }

    // 3 slots
    // @dev dethYieldRate should match ShortRecord
    struct Vault {
        // SLOT 1: 88 + 88 + 80 = 256 (0 unused)
        uint88 dethCollateral; // max 309m, 18 decimals
        uint88 dethTotal; // max 309m, 18 decimals
        uint80 dethYieldRate; // onlyUp
        // SLOT 2: 88 + 16 + 16 = 136 (128 unused)
        // tracked for shorter ditto rewards
        uint88 dethCollateralReward; // onlyUp
        uint16 dethTithePercent; // [0-100, 2 decimals]
        uint16 dittoShorterRate; // per unit of dethCollateral
        uint128 filler2;
        // SLOT 3: 128 + 96 + 16 + 16 = 256
        uint128 dittoMatchedShares;
        uint96 dittoMatchedReward; // max 79B, 18 decimals
        uint16 dittoMatchedRate;
        uint16 dittoMatchedTime; // last claim (in days) from STARTING_TIME
    }

    // 1 slots
    struct AssetUser {
        // SLOT 1: 104 + 24 + 32 + 8 = 168 (88 unused)
        uint104 ercEscrowed;
        uint24 g_flaggerId;
        uint32 g_flaggedAt; // represents the most recent flag - in hours
        uint8 shortRecordIdCounter;
        uint96 filler;
    }

    // 1 slots
    struct VaultUser {
        // SLOT 1: 88 + 88 + 80 = 256 (0 unused)
        uint88 ethEscrowed;
        uint88 dittoMatchedShares;
        uint80 dittoReward; // max 1.2m, 18 decimals
    }

    struct Bridge {
        // SLOT 1: 16 + 8 + 8 = 32 (224 unused)
        uint8 vault;
        uint16 withdrawalFee;
        uint8 unstakeFee;
    }
}

// @dev DataTypes only used in memory
library MTypes {
    struct OrderHint {
        uint16 hintId;
        uint256 creationTime;
    }

    struct BatchLiquidation {
        address shorter;
        uint8 shortId;
    }

    struct Match {
        uint88 fillEth;
        uint88 fillErc;
        uint88 colUsed;
        uint88 dittoMatchedShares;
        // Below used only for bids
        uint88 shortFillEth; // Includes colUsed + fillEth from shorts
        uint96 askFillErc; // Subset of fillErc
        bool ratesQueried; // Save gas when matching shorts
        uint80 dethYieldRate;
        uint64 ercDebtRate;
    }

    struct ExitShort {
        address asset;
        uint256 ercDebt;
        uint88 collateral;
        uint88 ethFilled;
        uint88 ercAmountLeft;
        uint88 ercFilled;
        uint256 beforeExitCR;
    }

    struct CombineShorts {
        bool shortFlagExists;
        uint32 shortUpdatedAt;
    }

    struct PrimaryLiquidation {
        address asset;
        uint256 vault;
        STypes.ShortRecord short;
        address shorter;
        uint256 cRatio;
        uint80 oraclePrice;
        uint256 forcedBidPriceBuffer;
        uint256 ethDebt;
        uint88 ethFilled;
        uint88 ercDebtMatched;
        bool loseCollateral;
        uint256 tappFeePct;
        uint256 callerFeePct;
        uint88 gasFee;
        uint88 totalFee; // gasFee + tappFee + callerFee
        uint256 minimumCR;
    }

    struct SecondaryLiquidation {
        address asset;
        uint256 vault;
        STypes.ShortRecord short;
        address shorter;
        uint256 cRatio;
        uint256 minimumCR;
        uint88 liquidatorCollateral;
        uint256 oraclePrice;
    }

    struct BidMatchAlgo {
        uint16 askId;
        uint16 shortHintId;
        uint16 shortId;
        uint16 prevShortId;
        uint16 firstShortIdBelowOracle;
        uint16 matchedAskId;
        uint16 matchedShortId;
        bool isMovingBack;
        bool isMovingFwd;
        uint256 oraclePrice;
        uint16 dustAskId;
        uint16 dustShortId;
    }

    struct CreateVaultParams {
        uint16 dethTithePercent;
        uint16 dittoMatchedRate;
        uint16 dittoShorterRate;
    }

    struct CreateLimitShortParam {
        address asset;
        uint256 eth;
        uint256 minShortErc;
        uint256 minAskEth;
        uint16 startingId;
        uint256 oraclePrice;
    }
}

File 7 of 10 : Constants.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.21;

library Constants {
    // @dev mark start of orders mapping
    uint8 internal constant HEAD = 1;
    // @dev only used as an alias since it's the same id
    uint8 internal constant TAIL = 1;
    // for all order types, starting point of orders
    uint8 internal constant STARTING_ID = 100;
    uint8 internal constant SHORT_MAX_ID = 254; // max uint8
    uint8 internal constant SHORT_STARTING_ID = 2;

    uint256 internal constant DUST_FACTOR = 0.5 ether;
    uint256 internal constant MIN_DURATION = 14 days;
    uint256 internal constant CRATIO_MAX = 15 ether;
    uint256 internal constant YIELD_DELAY_SECONDS = 60; // just need enough to prevent flash loan
    uint256 internal constant BRIDGE_YIELD_UPDATE_THRESHOLD = 1000 ether;
    uint256 internal constant BRIDGE_YIELD_PERCENT_THRESHOLD = 0.01 ether; // 1%

    // Bridge
    // @dev Matching RocketPool min deposit for now, Lido is 100 wei
    uint88 internal constant MIN_DEPOSIT = 0.01 ether;

    // re-entrancy
    uint8 internal constant NOT_ENTERED = 1;
    uint8 internal constant ENTERED = 2;
    uint256 internal constant ONE_DECIMAL_PLACES = 10;
    uint256 internal constant TWO_DECIMAL_PLACES = 100;
    uint256 internal constant THREE_DECIMAL_PLACES = 1000;
    uint256 internal constant FOUR_DECIMAL_PLACES = 10000;
    uint256 internal constant FIVE_DECIMAL_PLACES = 100000;
    uint256 internal constant SIX_DECIMAL_PLACES = 1000000;

    // set this to a datetime closer to deployment
    // @dev changing this will likely break the end to end fork test
    uint256 internal constant STARTING_TIME = 1660353637;

    int256 internal constant PREV = -1;
    int256 internal constant EXACT = 0;
    int256 internal constant NEXT = 1;

    bool internal constant MARKET_ORDER = true;
    bool internal constant LIMIT_ORDER = false;

    // Oracle
    // Base Oracle needs to be adjust 10**10 to have full 18 precision
    int256 internal constant BASE_ORACLE_DECIMALS = 10 ** 10;

    // Mainnet TWAP
    address internal constant USDC_WETH =
        address(0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640);
    address internal constant USDC = address(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
    address internal constant WETH = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
    uint128 internal constant UNISWAP_WETH_BASE_AMT = 1 ether;
    uint256 internal constant DECIMAL_USDC = 10 ** 6; //USDC's ERC contract sets to 6 decimals
}

library Vault {
    // ONE is the default vault
    uint256 internal constant ONE = 1;
}

File 8 of 10 : Common.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

// Common.sol
//
// Common mathematical functions needed by both SD59x18 and UD60x18. Note that these global functions do not
// always operate with SD59x18 and UD60x18 numbers.

/*//////////////////////////////////////////////////////////////////////////
                                CUSTOM ERRORS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Thrown when the resultant value in {mulDiv} overflows uint256.
error PRBMath_MulDiv_Overflow(uint256 x, uint256 y, uint256 denominator);

/// @notice Thrown when the resultant value in {mulDiv18} overflows uint256.
error PRBMath_MulDiv18_Overflow(uint256 x, uint256 y);

/// @notice Thrown when one of the inputs passed to {mulDivSigned} is `type(int256).min`.
error PRBMath_MulDivSigned_InputTooSmall();

/// @notice Thrown when the resultant value in {mulDivSigned} overflows int256.
error PRBMath_MulDivSigned_Overflow(int256 x, int256 y);

/*//////////////////////////////////////////////////////////////////////////
                                    CONSTANTS
//////////////////////////////////////////////////////////////////////////*/

/// @dev The maximum value a uint128 number can have.
uint128 constant MAX_UINT128 = type(uint128).max;

/// @dev The maximum value a uint40 number can have.
uint40 constant MAX_UINT40 = type(uint40).max;

/// @dev The unit number, which the decimal precision of the fixed-point types.
uint256 constant UNIT = 1e18;

/// @dev The unit number inverted mod 2^256.
uint256 constant UNIT_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281;

/// @dev The the largest power of two that divides the decimal value of `UNIT`. The logarithm of this value is the least significant
/// bit in the binary representation of `UNIT`.
uint256 constant UNIT_LPOTD = 262144;

/*//////////////////////////////////////////////////////////////////////////
                                    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.
/// @custom:smtchecker abstract-function-nondet
function exp2(uint256 x) pure returns (uint256 result) {
    unchecked {
        // Start from 0.5 in the 192.64-bit fixed-point format.
        result = 0x800000000000000000000000000000000000000000000000;

        // The following logic multiplies the result by $\sqrt{2^{-i}}$ when the bit at position i is 1. Key points:
        //
        // 1. Intermediate results will not overflow, as the starting point is 2^191 and all magic factors are under 2^65.
        // 2. The rationale for organizing the if statements into groups of 8 is gas savings. If the result of performing
        // a bitwise AND operation between x and any value in the array [0x80; 0x40; 0x20; 0x10; 0x08; 0x04; 0x02; 0x01] is 1,
        // we know that `x & 0xFF` is also 1.
        if (x & 0xFF00000000000000 > 0) {
            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 & 0xFF000000000000 > 0) {
            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 & 0xFF0000000000 > 0) {
            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 & 0xFF00000000 > 0) {
            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 & 0xFF000000 > 0) {
            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 & 0xFF0000 > 0) {
            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 & 0xFF00 > 0) {
            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 & 0xFF > 0) {
            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;
            }
        }

        // In the code snippet below, two operations are executed simultaneously:
        //
        // 1. The result is multiplied by $(2^n + 1)$, where $2^n$ represents the integer part, and the additional 1
        // accounts for the initial guess of 0.5. This is achieved by subtracting from 191 instead of 192.
        // 2. The result is then converted to an unsigned 60.18-decimal fixed-point format.
        //
        // The underlying logic is based on the relationship $2^{191-ip} = 2^{ip} / 2^{191}$, where $ip$ denotes the,
        // integer part, $2^n$.
        result *= UNIT;
        result >>= (191 - (x >> 64));
    }
}

/// @notice Finds the zero-based index of the first 1 in the binary representation of x.
///
/// @dev See the note on "msb" in this Wikipedia article: https://en.wikipedia.org/wiki/Find_first_set
///
/// Each step in this implementation is equivalent to this high-level code:
///
/// ```solidity
/// if (x >= 2 ** 128) {
///     x >>= 128;
///     result += 128;
/// }
/// ```
///
/// Where 128 is replaced with each respective power of two factor. See the full high-level implementation here:
/// https://gist.github.com/PaulRBerg/f932f8693f2733e30c4d479e8e980948
///
/// The Yul instructions used below are:
///
/// - "gt" is "greater than"
/// - "or" is the OR bitwise operator
/// - "shl" is "shift left"
/// - "shr" is "shift right"
///
/// @param x The uint256 number for which to find the index of the most significant bit.
/// @return result The index of the most significant bit as a uint256.
/// @custom:smtchecker abstract-function-nondet
function msb(uint256 x) pure returns (uint256 result) {
    // 2^128
    assembly ("memory-safe") {
        let factor := shl(7, gt(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^64
    assembly ("memory-safe") {
        let factor := shl(6, gt(x, 0xFFFFFFFFFFFFFFFF))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^32
    assembly ("memory-safe") {
        let factor := shl(5, gt(x, 0xFFFFFFFF))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^16
    assembly ("memory-safe") {
        let factor := shl(4, gt(x, 0xFFFF))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^8
    assembly ("memory-safe") {
        let factor := shl(3, gt(x, 0xFF))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^4
    assembly ("memory-safe") {
        let factor := shl(2, gt(x, 0xF))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^2
    assembly ("memory-safe") {
        let factor := shl(1, gt(x, 0x3))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^1
    // No need to shift x any more.
    assembly ("memory-safe") {
        let factor := gt(x, 0x1)
        result := or(result, factor)
    }
}

/// @notice Calculates x*y÷denominator with 512-bit precision.
///
/// @dev Credits to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.
///
/// Notes:
/// - The result is rounded toward zero.
///
/// Requirements:
/// - The denominator must not be zero.
/// - The result must fit in uint256.
///
/// @param x The multiplicand as a uint256.
/// @param y The multiplier as a uint256.
/// @param denominator The divisor as a uint256.
/// @return result The result as a uint256.
/// @custom:smtchecker abstract-function-nondet
function mulDiv(uint256 x, uint256 y, uint256 denominator) 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 ("memory-safe") {
        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 {
            return prod0 / denominator;
        }
    }

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

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

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

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

    unchecked {
        // Calculate the largest power of two divisor of the denominator using the unary operator ~. This operation cannot overflow
        // because the denominator cannot be zero at this point in the function execution. The result is always >= 1.
        // For more detail, see https://cs.stackexchange.com/q/138556/92363.
        uint256 lpotdod = denominator & (~denominator + 1);
        uint256 flippedLpotdod;

        assembly ("memory-safe") {
            // Factor powers of two out of denominator.
            denominator := div(denominator, lpotdod)

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

            // Get the flipped value `2^256 / lpotdod`. If the `lpotdod` is zero, the flipped value is one.
            // `sub(0, lpotdod)` produces the two's complement version of `lpotdod`, which is equivalent to flipping all the bits.
            // However, `div` interprets this value as an unsigned value: https://ethereum.stackexchange.com/q/147168/24693
            flippedLpotdod := add(div(sub(0, lpotdod), lpotdod), 1)
        }

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

        // 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;
    }
}

/// @notice Calculates x*y÷1e18 with 512-bit precision.
///
/// @dev A variant of {mulDiv} with constant folding, i.e. in which the denominator is hard coded to 1e18.
///
/// Notes:
/// - The body is purposely left uncommented; to understand how this works, see the documentation in {mulDiv}.
/// - The result is rounded toward zero.
/// - We take as an axiom that the result cannot be `MAX_UINT256` when x and y solve the following system of equations:
///
/// $$
/// \begin{cases}
///     x * y = MAX\_UINT256 * UNIT \\
///     (x * y) \% UNIT \geq \frac{UNIT}{2}
/// \end{cases}
/// $$
///
/// Requirements:
/// - Refer to the requirements in {mulDiv}.
/// - The result must fit in uint256.
///
/// @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.
/// @custom:smtchecker abstract-function-nondet
function mulDiv18(uint256 x, uint256 y) pure returns (uint256 result) {
    uint256 prod0;
    uint256 prod1;
    assembly ("memory-safe") {
        let mm := mulmod(x, y, not(0))
        prod0 := mul(x, y)
        prod1 := sub(sub(mm, prod0), lt(mm, prod0))
    }

    if (prod1 == 0) {
        unchecked {
            return prod0 / UNIT;
        }
    }

    if (prod1 >= UNIT) {
        revert PRBMath_MulDiv18_Overflow(x, y);
    }

    uint256 remainder;
    assembly ("memory-safe") {
        remainder := mulmod(x, y, UNIT)
        result :=
            mul(
                or(
                    div(sub(prod0, remainder), UNIT_LPOTD),
                    mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, UNIT_LPOTD), UNIT_LPOTD), 1))
                ),
                UNIT_INVERSE
            )
    }
}

/// @notice Calculates x*y÷denominator with 512-bit precision.
///
/// @dev This is an extension of {mulDiv} for signed numbers, which works by computing the signs and the absolute values separately.
///
/// Notes:
/// - The result is rounded toward zero.
///
/// Requirements:
/// - Refer to the requirements in {mulDiv}.
/// - None of the inputs can be `type(int256).min`.
/// - The result must fit in 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.
/// @custom:smtchecker abstract-function-nondet
function mulDivSigned(int256 x, int256 y, int256 denominator) pure returns (int256 result) {
    if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {
        revert PRBMath_MulDivSigned_InputTooSmall();
    }

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

    // Compute the absolute value of x*y÷denominator. The result must fit in int256.
    uint256 resultAbs = mulDiv(xAbs, yAbs, dAbs);
    if (resultAbs > uint256(type(int256).max)) {
        revert PRBMath_MulDivSigned_Overflow(x, y);
    }

    // Get the signs of x, y and the denominator.
    uint256 sx;
    uint256 sy;
    uint256 sd;
    assembly ("memory-safe") {
        // "sgt" is the "signed greater than" assembly instruction and "sub(0,1)" is -1 in two's complement.
        sx := sgt(x, sub(0, 1))
        sy := sgt(y, sub(0, 1))
        sd := sgt(denominator, sub(0, 1))
    }

    // XOR over sx, sy and sd. What this does is to check whether there are 1 or 3 negative signs in the inputs.
    // If there are, the result should be negative. Otherwise, it should be positive.
    unchecked {
        result = sx ^ sy ^ sd == 0 ? -int256(resultAbs) : int256(resultAbs);
    }
}

/// @notice Calculates the square root of x using the Babylonian method.
///
/// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
///
/// Notes:
/// - If x is not a perfect square, the result is rounded down.
/// - Credits to OpenZeppelin for the explanations in comments below.
///
/// @param x The uint256 number for which to calculate the square root.
/// @return result The result as a uint256.
/// @custom:smtchecker abstract-function-nondet
function sqrt(uint256 x) pure returns (uint256 result) {
    if (x == 0) {
        return 0;
    }

    // For our first guess, we calculate the biggest power of 2 which is smaller than the square root of x.
    //
    // We know that the "msb" (most significant bit) of x is a power of 2 such that we have:
    //
    // $$
    // msb(x) <= x <= 2*msb(x)$
    // $$
    //
    // We write $msb(x)$ as $2^k$, and we get:
    //
    // $$
    // k = log_2(x)
    // $$
    //
    // Thus, we can write the initial inequality as:
    //
    // $$
    // 2^{log_2(x)} <= x <= 2*2^{log_2(x)+1} \\
    // sqrt(2^k) <= sqrt(x) < sqrt(2^{k+1}) \\
    // 2^{k/2} <= sqrt(x) < 2^{(k+1)/2} <= 2^{(k/2)+1}
    // $$
    //
    // Consequently, $2^{log_2(x) /2} is a good first approximation of sqrt(x) with at least one correct bit.
    uint256 xAux = uint256(x);
    result = 1;
    if (xAux >= 2 ** 128) {
        xAux >>= 128;
        result <<= 64;
    }
    if (xAux >= 2 ** 64) {
        xAux >>= 64;
        result <<= 32;
    }
    if (xAux >= 2 ** 32) {
        xAux >>= 32;
        result <<= 16;
    }
    if (xAux >= 2 ** 16) {
        xAux >>= 16;
        result <<= 8;
    }
    if (xAux >= 2 ** 8) {
        xAux >>= 8;
        result <<= 4;
    }
    if (xAux >= 2 ** 4) {
        xAux >>= 4;
        result <<= 2;
    }
    if (xAux >= 2 ** 2) {
        result <<= 1;
    }

    // At this point, `result` is an estimation with at least one bit of precision. We know the true value has at
    // most 128 bits, 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 + 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;

        // If x is not a perfect square, round the result toward zero.
        uint256 roundedResult = x / result;
        if (result >= roundedResult) {
            result = roundedResult;
        }
    }
}

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

/**
 * \
 * Author: Nick Mudge
 *
 * Implementation of Diamond facet.
 * Uses the diamond-2 version 1.3.4 implementation:
 * https://github.com/mudgen/diamond-2
 *
 * This is gas optimized by reducing storage reads and storage writes.
 * This code is as complex as it is to reduce gas costs.
 * /*****************************************************************************
 */

import {IDiamondCut} from "contracts/interfaces/IDiamondCut.sol";

/* solhint-disable */
library LibDiamond {
    bytes32 constant DIAMOND_STORAGE_POSITION =
        keccak256("diamond.standard.diamond.storage");

    struct DiamondStorage {
        // maps function selectors to the facets that execute the functions.
        // and maps the selectors to their position in the selectorSlots array.
        // func selector => address facet, selector position
        mapping(bytes4 => bytes32) facets;
        // array of slots of function selectors.
        // each slot holds 8 function selectors.
        mapping(uint256 => bytes32) selectorSlots;
        // owner of the contract
        // Used to query if a contract implements an interface.
        // Used to implement ERC-165.
        mapping(bytes4 => bool) supportedInterfaces;
        // The number of function selectors in selectorSlots
        uint16 selectorCount;
        // owner of the contract
        address contractOwner;
    }

    function diamondStorage() internal pure returns (DiamondStorage storage ds) {
        bytes32 position = DIAMOND_STORAGE_POSITION;
        assembly {
            ds.slot := position
        }
    }

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

    function setContractOwner(address _newOwner) internal {
        DiamondStorage storage ds = diamondStorage();
        address previousOwner = ds.contractOwner;
        ds.contractOwner = _newOwner;
        emit OwnershipTransferred(previousOwner, _newOwner);
    }

    function contractOwner() internal view returns (address contractOwner_) {
        contractOwner_ = diamondStorage().contractOwner;
    }

    function enforceIsContractOwner() internal view {
        require(
            msg.sender == diamondStorage().contractOwner,
            "LibDiamond: Must be contract owner"
        );
    }

    event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);

    bytes32 constant CLEAR_ADDRESS_MASK = bytes32(uint256(0xffffffffffffffffffffffff));
    bytes32 constant CLEAR_SELECTOR_MASK = bytes32(uint256(0xffffffff << 224));

    // Internal function version of diamondCut
    // This code is almost the same as the external diamondCut,
    // except it is using 'Facet[] memory _diamondCut' instead of
    // 'Facet[] calldata _diamondCut'.
    // The code is duplicated to prevent copying calldata to memory which
    // causes an error for a two dimensional array.
    function diamondCut(
        IDiamondCut.FacetCut[] memory _diamondCut,
        address _init,
        bytes memory _calldata
    ) internal {
        DiamondStorage storage ds = diamondStorage();
        uint256 originalSelectorCount = ds.selectorCount;
        uint256 selectorCount = originalSelectorCount;
        bytes32 selectorSlot;
        // Check if last selector slot is not full
        if (selectorCount % 8 > 0) {
            // get last selectorSlot
            selectorSlot = ds.selectorSlots[selectorCount / 8];
        }
        // loop through diamond cut
        for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
            (selectorCount, selectorSlot) = addReplaceRemoveFacetSelectors(
                selectorCount,
                selectorSlot,
                _diamondCut[facetIndex].facetAddress,
                _diamondCut[facetIndex].action,
                _diamondCut[facetIndex].functionSelectors
            );
        }
        if (selectorCount != originalSelectorCount) {
            ds.selectorCount = uint16(selectorCount);
        }
        // If last selector slot is not full
        if (selectorCount % 8 > 0) {
            ds.selectorSlots[selectorCount / 8] = selectorSlot;
        }
        emit DiamondCut(_diamondCut, _init, _calldata);
        initializeDiamondCut(_init, _calldata);
    }

    function addReplaceRemoveFacetSelectors(
        uint256 _selectorCount,
        bytes32 _selectorSlot,
        address _newFacetAddress,
        IDiamondCut.FacetCutAction _action,
        bytes4[] memory _selectors
    ) internal returns (uint256, bytes32) {
        DiamondStorage storage ds = diamondStorage();
        require(_selectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
        if (_action == IDiamondCut.FacetCutAction.Add) {
            require(
                _newFacetAddress != address(0),
                "LibDiamondCut: Add facet can't be address(0)"
            );
            enforceHasContractCode(
                _newFacetAddress, "LibDiamondCut: Add facet has no code"
            );
            for (
                uint256 selectorIndex; selectorIndex < _selectors.length; selectorIndex++
            ) {
                bytes4 selector = _selectors[selectorIndex];
                bytes32 oldFacet = ds.facets[selector];
                require(
                    address(bytes20(oldFacet)) == address(0),
                    "LibDiamondCut: Can't add function that already exists"
                );
                // add facet for selector
                ds.facets[selector] = bytes20(_newFacetAddress) | bytes32(_selectorCount);
                uint256 selectorInSlotPosition = (_selectorCount % 8) * 32;
                // clear selector position in slot and add selector
                _selectorSlot = (
                    _selectorSlot & ~(CLEAR_SELECTOR_MASK >> selectorInSlotPosition)
                ) | (bytes32(selector) >> selectorInSlotPosition);
                // if slot is full then write it to storage
                if (selectorInSlotPosition == 224) {
                    ds.selectorSlots[_selectorCount / 8] = _selectorSlot;
                    _selectorSlot = 0;
                }
                _selectorCount++;
            }
        } else if (_action == IDiamondCut.FacetCutAction.Replace) {
            require(
                _newFacetAddress != address(0),
                "LibDiamondCut: Replace facet can't be address(0)"
            );
            enforceHasContractCode(
                _newFacetAddress, "LibDiamondCut: Replace facet has no code"
            );
            for (
                uint256 selectorIndex; selectorIndex < _selectors.length; selectorIndex++
            ) {
                bytes4 selector = _selectors[selectorIndex];
                bytes32 oldFacet = ds.facets[selector];
                address oldFacetAddress = address(bytes20(oldFacet));
                // only useful if immutable functions exist
                require(
                    oldFacetAddress != address(this),
                    "LibDiamondCut: Can't replace immutable function"
                );
                require(
                    oldFacetAddress != _newFacetAddress,
                    "LibDiamondCut: Can't replace function with same function"
                );
                require(
                    oldFacetAddress != address(0),
                    "LibDiamondCut: Can't replace function that doesn't exist"
                );
                // replace old facet address
                ds.facets[selector] =
                    (oldFacet & CLEAR_ADDRESS_MASK) | bytes20(_newFacetAddress);
            }
        } else if (_action == IDiamondCut.FacetCutAction.Remove) {
            require(
                _newFacetAddress == address(0),
                "LibDiamondCut: Remove facet address must be address(0)"
            );
            uint256 selectorSlotCount = _selectorCount / 8;
            uint256 selectorInSlotIndex = (_selectorCount % 8) - 1;
            for (
                uint256 selectorIndex; selectorIndex < _selectors.length; selectorIndex++
            ) {
                if (_selectorSlot == 0) {
                    // get last selectorSlot
                    selectorSlotCount--;
                    _selectorSlot = ds.selectorSlots[selectorSlotCount];
                    selectorInSlotIndex = 7;
                }
                bytes4 lastSelector;
                uint256 oldSelectorsSlotCount;
                uint256 oldSelectorInSlotPosition;
                // adding a block here prevents stack too deep error
                {
                    bytes4 selector = _selectors[selectorIndex];
                    bytes32 oldFacet = ds.facets[selector];
                    require(
                        address(bytes20(oldFacet)) != address(0),
                        "LibDiamondCut: Can't remove function that doesn't exist"
                    );
                    // only useful if immutable functions exist
                    require(
                        address(bytes20(oldFacet)) != address(this),
                        "LibDiamondCut: Can't remove immutable function"
                    );
                    // replace selector with last selector in ds.facets
                    // gets the last selector
                    lastSelector = bytes4(_selectorSlot << (selectorInSlotIndex * 32));
                    if (lastSelector != selector) {
                        // update last selector slot position info
                        ds.facets[lastSelector] = (oldFacet & CLEAR_ADDRESS_MASK)
                            | bytes20(ds.facets[lastSelector]);
                    }
                    delete ds.facets[selector];
                    uint256 oldSelectorCount = uint16(uint256(oldFacet));
                    oldSelectorsSlotCount = oldSelectorCount / 8;
                    oldSelectorInSlotPosition = (oldSelectorCount % 8) * 32;
                }
                if (oldSelectorsSlotCount != selectorSlotCount) {
                    bytes32 oldSelectorSlot = ds.selectorSlots[oldSelectorsSlotCount];
                    // clears the selector being deleted and puts the last selector in its place.
                    oldSelectorSlot = (
                        oldSelectorSlot
                            & ~(CLEAR_SELECTOR_MASK >> oldSelectorInSlotPosition)
                    ) | (bytes32(lastSelector) >> oldSelectorInSlotPosition);
                    // update storage with the modified slot
                    ds.selectorSlots[oldSelectorsSlotCount] = oldSelectorSlot;
                } else {
                    // clears the selector being deleted and puts the last selector in its place.
                    _selectorSlot = (
                        _selectorSlot
                            & ~(CLEAR_SELECTOR_MASK >> oldSelectorInSlotPosition)
                    ) | (bytes32(lastSelector) >> oldSelectorInSlotPosition);
                }
                if (selectorInSlotIndex == 0) {
                    delete ds.selectorSlots[selectorSlotCount];
                    _selectorSlot = 0;
                }
                selectorInSlotIndex--;
            }
            _selectorCount = selectorSlotCount * 8 + selectorInSlotIndex + 1;
        } else {
            revert("LibDiamondCut: Incorrect FacetCutAction");
        }
        return (_selectorCount, _selectorSlot);
    }

    function initializeDiamondCut(address _init, bytes memory _calldata) internal {
        if (_init == address(0)) {
            require(
                _calldata.length == 0,
                "LibDiamondCut: _init is address(0) but_calldata is not empty"
            );
        } else {
            require(
                _calldata.length > 0,
                "LibDiamondCut: _calldata is empty but _init is not address(0)"
            );
            if (_init != address(this)) {
                enforceHasContractCode(_init, "LibDiamondCut: _init address has no code");
            }
            (bool success, bytes memory error) = _init.delegatecall(_calldata);
            if (success == false) {
                if (error.length > 0) {
                    // bubble up the error
                    revert(string(error));
                } else {
                    revert("LibDiamondCut: _init function reverted");
                }
            }
        }
    }

    function enforceHasContractCode(address _contract, string memory _errorMessage)
        internal
        view
    {
        uint256 contractSize;
        assembly {
            contractSize := extcodesize(_contract)
        }
        require(contractSize > 0, _errorMessage);
    }
}

File 10 of 10 : IDiamondCut.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
/*
 * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
 */

interface IDiamondCut {
    enum FacetCutAction {
        Add,
        Replace,
        Remove
    }

    struct FacetCut {
        address facetAddress;
        FacetCutAction action;
        bytes4[] functionSelectors;
    }

    /// @notice Add/replace/remove any number of functions and optionally execute
    ///         a function with delegatecall
    /// @param _diamondCut Contains the facet addresses and function selectors
    /// @param _init The address of the contract or facet to execute _calldata
    /// @param _calldata A function call, including function selector and arguments
    ///                  _calldata is executed with delegatecall on _init
    function diamondCut(
        FacetCut[] calldata _diamondCut,
        address _init,
        bytes calldata _calldata
    ) external;

    event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
}

Settings
{
  "remappings": [
    "forge-std/=lib/forge-std/src/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "interfaces/=interfaces/",
    "contracts/=contracts/",
    "test/=test/",
    "test-gas/=test-gas/",
    "deploy/=deploy/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "@chainlink/=node_modules/@chainlink/",
    "@eth-optimism/=node_modules/@eth-optimism/",
    "@prb/=node_modules/@prb/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "shanghai",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_deth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AssetIsFrozen","type":"error"},{"inputs":[],"name":"InsufficientERCEscrowed","type":"error"},{"inputs":[],"name":"InsufficientETHEscrowed","type":"error"},{"inputs":[],"name":"InvalidAsset","type":"error"},{"inputs":[],"name":"InvalidDeth","type":"error"},{"inputs":[],"name":"PriceOrAmountIs0","type":"error"},{"inputs":[],"name":"ReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint104","name":"amount","type":"uint104"}],"name":"depositAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"deth","type":"address"},{"internalType":"uint88","name":"amount","type":"uint88"}],"name":"depositDETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint104","name":"amount","type":"uint104"}],"name":"withdrawAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"deth","type":"address"},{"internalType":"uint88","name":"amount","type":"uint88"}],"name":"withdrawDETH","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a060405234801561000f575f80fd5b50604051610fb0380380610fb083398101604081905261002e9161003f565b6001600160a01b031660805261006c565b5f6020828403121561004f575f80fd5b81516001600160a01b0381168114610065575f80fd5b9392505050565b608051610f2561008b5f395f81816101ab01526107c40152610f255ff3fe608060405234801561000f575f80fd5b506004361061004a575f3560e01c806316a707851461004e5780633adc16fc14610063578063a59adf9c14610076578063fc8b8d6b14610089575b5f80fd5b61006161005c366004610d7b565b61009c565b005b610061610071366004610dbf565b610401565b610061610084366004610d7b565b6106b5565b610061610097366004610dbf565b6109d8565b6002547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c010000000000000000000000000000000000000000000000000000000090910460ff160161011b576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c02000000000000000000000000000000000000000000000000000000001790556affffffffffffffffffffff81165f036101a8576040517fe5c30f3900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361020457506001610288565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600360205260408120549003610261576040517f992e8e8000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff82165f908152600360205260409020545b5f818152600760209081526040808320338452909152902080546affffffffffffffffffffff90811690841611156102ec576040517f7d243a2c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054839082905f9061030c9084906affffffffffffffffffffff16610e27565b82546101009290920a6affffffffffffffffffffff8181021990931691831602179091556040517f40c10f19000000000000000000000000000000000000000000000000000000008152336004820152908516602482015273ffffffffffffffffffffffffffffffffffffffff861691506340c10f19906044015b5f604051808303815f87803b15801561039e575f80fd5b505af11580156103b0573d5f803e3d5ffd5b5050600280547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c0100000000000000000000000000000000000000000000000000000000179055505050505050565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526008602052604081205483917f010000000000000000000000000000000000000000000000000000000000000090910460ff169003610487576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c010000000000000000000000000000000000000000000000000000000090910460ff1601610506576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c02000000000000000000000000000000000000000000000000000000001790556cffffffffffffffffffffffffff82165f03610595576040517fe5c30f3900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83165f908152600960209081526040808320338452909152902080546cffffffffffffffffffffffffff9081169084161115610612576040517f4bf8161700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054839082905f906106349084906cffffffffffffffffffffffffff16610e52565b82546101009290920a6cffffffffffffffffffffffffff8181021990931691831602179091556040517f40c10f19000000000000000000000000000000000000000000000000000000008152336004820152908516602482015273ffffffffffffffffffffffffffffffffffffffff861691506340c10f1990604401610387565b6002547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c010000000000000000000000000000000000000000000000000000000090910460ff1601610734576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c02000000000000000000000000000000000000000000000000000000001790556affffffffffffffffffffff81165f036107c1576040517fe5c30f3900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361081d575060016108a1565b73ffffffffffffffffffffffffffffffffffffffff83165f90815260036020526040812054900361087a576040517f992e8e8000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff82165f908152600360205260409020545b6040517f79cc67900000000000000000000000000000000000000000000000000000000081523360048201526affffffffffffffffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff8416906379cc6790906044015f604051808303815f87803b158015610918575f80fd5b505af115801561092a573d5f803e3d5ffd5b5050505f828152600760209081526040808320338452909152812080548593509091906109659084906affffffffffffffffffffff16610e78565b82546affffffffffffffffffffff9182166101009390930a92830291909202199091161790555050600280547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c01000000000000000000000000000000000000000000000000000000001790555050565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526008602052604081205483917f010000000000000000000000000000000000000000000000000000000000000090910460ff169003610a5e576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825f73ffffffffffffffffffffffffffffffffffffffff82165f908152600860205260409020547e01000000000000000000000000000000000000000000000000000000000000900460ff166001811115610abb57610abb610e9c565b14610af2576040517f0e27a3f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c010000000000000000000000000000000000000000000000000000000090910460ff1601610b71576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c02000000000000000000000000000000000000000000000000000000001790556cffffffffffffffffffffffffff83165f03610c00576040517fe5c30f3900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f79cc67900000000000000000000000000000000000000000000000000000000081523360048201526cffffffffffffffffffffffffff8416602482015273ffffffffffffffffffffffffffffffffffffffff8516906379cc6790906044015f604051808303815f87803b158015610c79575f80fd5b505af1158015610c8b573d5f803e3d5ffd5b5050505073ffffffffffffffffffffffffffffffffffffffff84165f90815260096020908152604080832033845290915281208054859290610cdd9084906cffffffffffffffffffffffffff16610ec9565b82546cffffffffffffffffffffffffff9182166101009390930a92830291909202199091161790555050600280547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c0100000000000000000000000000000000000000000000000000000000179055505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610d76575f80fd5b919050565b5f8060408385031215610d8c575f80fd5b610d9583610d53565b915060208301356affffffffffffffffffffff81168114610db4575f80fd5b809150509250929050565b5f8060408385031215610dd0575f80fd5b610dd983610d53565b915060208301356cffffffffffffffffffffffffff81168114610db4575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b6affffffffffffffffffffff828116828216039080821115610e4b57610e4b610dfa565b5092915050565b6cffffffffffffffffffffffffff828116828216039080821115610e4b57610e4b610dfa565b6affffffffffffffffffffff818116838216019080821115610e4b57610e4b610dfa565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6cffffffffffffffffffffffffff818116838216019080821115610e4b57610e4b610dfa56fea264697066735822122072f50d6e676291302d496d2d71b9ff4cd936dd227e1712505188ed74565593c964736f6c63430008150033000000000000000000000000d1770004661852cbc0b317c7775f4fa22e6bc60a

Deployed Bytecode

0x608060405234801561000f575f80fd5b506004361061004a575f3560e01c806316a707851461004e5780633adc16fc14610063578063a59adf9c14610076578063fc8b8d6b14610089575b5f80fd5b61006161005c366004610d7b565b61009c565b005b610061610071366004610dbf565b610401565b610061610084366004610d7b565b6106b5565b610061610097366004610dbf565b6109d8565b6002547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c010000000000000000000000000000000000000000000000000000000090910460ff160161011b576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c02000000000000000000000000000000000000000000000000000000001790556affffffffffffffffffffff81165f036101a8576040517fe5c30f3900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f7f000000000000000000000000d1770004661852cbc0b317c7775f4fa22e6bc60a73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361020457506001610288565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600360205260408120549003610261576040517f992e8e8000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff82165f908152600360205260409020545b5f818152600760209081526040808320338452909152902080546affffffffffffffffffffff90811690841611156102ec576040517f7d243a2c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054839082905f9061030c9084906affffffffffffffffffffff16610e27565b82546101009290920a6affffffffffffffffffffff8181021990931691831602179091556040517f40c10f19000000000000000000000000000000000000000000000000000000008152336004820152908516602482015273ffffffffffffffffffffffffffffffffffffffff861691506340c10f19906044015b5f604051808303815f87803b15801561039e575f80fd5b505af11580156103b0573d5f803e3d5ffd5b5050600280547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c0100000000000000000000000000000000000000000000000000000000179055505050505050565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526008602052604081205483917f010000000000000000000000000000000000000000000000000000000000000090910460ff169003610487576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c010000000000000000000000000000000000000000000000000000000090910460ff1601610506576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c02000000000000000000000000000000000000000000000000000000001790556cffffffffffffffffffffffffff82165f03610595576040517fe5c30f3900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83165f908152600960209081526040808320338452909152902080546cffffffffffffffffffffffffff9081169084161115610612576040517f4bf8161700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054839082905f906106349084906cffffffffffffffffffffffffff16610e52565b82546101009290920a6cffffffffffffffffffffffffff8181021990931691831602179091556040517f40c10f19000000000000000000000000000000000000000000000000000000008152336004820152908516602482015273ffffffffffffffffffffffffffffffffffffffff861691506340c10f1990604401610387565b6002547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c010000000000000000000000000000000000000000000000000000000090910460ff1601610734576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c02000000000000000000000000000000000000000000000000000000001790556affffffffffffffffffffff81165f036107c1576040517fe5c30f3900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f7f000000000000000000000000d1770004661852cbc0b317c7775f4fa22e6bc60a73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361081d575060016108a1565b73ffffffffffffffffffffffffffffffffffffffff83165f90815260036020526040812054900361087a576040517f992e8e8000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff82165f908152600360205260409020545b6040517f79cc67900000000000000000000000000000000000000000000000000000000081523360048201526affffffffffffffffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff8416906379cc6790906044015f604051808303815f87803b158015610918575f80fd5b505af115801561092a573d5f803e3d5ffd5b5050505f828152600760209081526040808320338452909152812080548593509091906109659084906affffffffffffffffffffff16610e78565b82546affffffffffffffffffffff9182166101009390930a92830291909202199091161790555050600280547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c01000000000000000000000000000000000000000000000000000000001790555050565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526008602052604081205483917f010000000000000000000000000000000000000000000000000000000000000090910460ff169003610a5e576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825f73ffffffffffffffffffffffffffffffffffffffff82165f908152600860205260409020547e01000000000000000000000000000000000000000000000000000000000000900460ff166001811115610abb57610abb610e9c565b14610af2576040517f0e27a3f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c010000000000000000000000000000000000000000000000000000000090910460ff1601610b71576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c02000000000000000000000000000000000000000000000000000000001790556cffffffffffffffffffffffffff83165f03610c00576040517fe5c30f3900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f79cc67900000000000000000000000000000000000000000000000000000000081523360048201526cffffffffffffffffffffffffff8416602482015273ffffffffffffffffffffffffffffffffffffffff8516906379cc6790906044015f604051808303815f87803b158015610c79575f80fd5b505af1158015610c8b573d5f803e3d5ffd5b5050505073ffffffffffffffffffffffffffffffffffffffff84165f90815260096020908152604080832033845290915281208054859290610cdd9084906cffffffffffffffffffffffffff16610ec9565b82546cffffffffffffffffffffffffff9182166101009390930a92830291909202199091161790555050600280547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c0100000000000000000000000000000000000000000000000000000000179055505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610d76575f80fd5b919050565b5f8060408385031215610d8c575f80fd5b610d9583610d53565b915060208301356affffffffffffffffffffff81168114610db4575f80fd5b809150509250929050565b5f8060408385031215610dd0575f80fd5b610dd983610d53565b915060208301356cffffffffffffffffffffffffff81168114610db4575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b6affffffffffffffffffffff828116828216039080821115610e4b57610e4b610dfa565b5092915050565b6cffffffffffffffffffffffffff828116828216039080821115610e4b57610e4b610dfa565b6affffffffffffffffffffff818116838216019080821115610e4b57610e4b610dfa565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6cffffffffffffffffffffffffff818116838216019080821115610e4b57610e4b610dfa56fea264697066735822122072f50d6e676291302d496d2d71b9ff4cd936dd227e1712505188ed74565593c964736f6c63430008150033

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

000000000000000000000000d1770004661852cbc0b317c7775f4fa22e6bc60a

-----Decoded View---------------
Arg [0] : _deth (address): 0xd1770004661852cbC0B317c7775f4fA22E6bC60A

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000d1770004661852cbc0b317c7775f4fa22e6bc60a


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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.