Assistant

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "src/Assistant.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Interfaces
import {IQuoter} from "./interfaces/IQuoter.sol";
import {IVault} from "core/interfaces/IVault.sol";
import {IOracle} from "core/interfaces/IOracle.sol";
import {IUniswapV3Pool} from "v3-core/interfaces/IUniswapV3Pool.sol";

// Contracts and libraries
import {SirStructs} from "core/libraries/SirStructs.sol";
import {SystemConstants} from "core/libraries/SystemConstants.sol";
import {FullMath} from "core/libraries/FullMath.sol";
import {IWETH9, IERC20} from "core/interfaces/IWETH9.sol";
import {UniswapPoolAddress} from "core/libraries/UniswapPoolAddress.sol";
import {AddressClone} from "core/libraries/AddressClone.sol";

import "forge-std/console.sol";

/**
 * @notice Helper functions for SIR protocol
 */
contract Assistant {
    IVault public immutable VAULT;
    IOracle private immutable SIR_ORACLE;
    address private immutable UNISWAPV3_FACTORY;
    IQuoter private immutable UNISWAPV3_QUOTER;

    error VaultDoesNotExist();
    error AmountTooLow();
    error TooMuchCollateral();
    error TEAMaxSupplyExceeded();

    enum VaultStatus {
        InvalidVault,
        NoUniswapPool,
        VaultCanBeCreated,
        VaultAlreadyExists
    }

    constructor(address vault, address oracle, address uniswapV3Factory) {
        VAULT = IVault(vault);
        SIR_ORACLE = IOracle(oracle);
        UNISWAPV3_FACTORY = uniswapV3Factory;

        if (block.chainid == 1) UNISWAPV3_QUOTER = IQuoter(0x5e55C9e631FAE526cd4B0526C4818D6e0a9eF0e3);
        else if (block.chainid == 11155111) UNISWAPV3_QUOTER = IQuoter(0xe3c07ebF66b9D070b589bCCa30903891F71A92Be);
        else revert("Network not supported");
    }

    /**
     *  @notice It returns the reserves of the vaults specified in vaultIds
     */
    function getReserves(uint48[] calldata vaultIds) external view returns (SirStructs.Reserves[] memory reserves) {
        reserves = new SirStructs.Reserves[](vaultIds.length);
        SirStructs.VaultParameters memory vaultParams;
        for (uint256 i = 0; i < vaultIds.length; i++) {
            vaultParams = VAULT.paramsById(vaultIds[i]);
            reserves[i] = VAULT.getReserves(vaultParams);
        }
    }

    /**
     *  @notice It returns the balances of the user in vaults [offset + 1, offset + numVaults].
     *  @param user The address of the user.
     *  @param offset The offset of the vaults.
     *  @param numVaults The number of vaults.
     */
    function getUserBalances(
        address user,
        uint offset,
        uint numVaults
    )
        external
        view
        returns (uint256[] memory apeBalances, uint256[] memory teaBalances, uint80[] memory unclaimedSirRewards)
    {
        IERC20 ape;
        apeBalances = new uint256[](numVaults);
        teaBalances = new uint256[](numVaults);
        unclaimedSirRewards = new uint80[](numVaults);
        for (uint256 vaultId = offset + 1; vaultId <= offset + numVaults; vaultId++) {
            ape = IERC20(AddressClone.getAddress(address(VAULT), vaultId));
            apeBalances[vaultId - offset - 1] = ape.balanceOf(user);
            teaBalances[vaultId - offset - 1] = VAULT.balanceOf(user, vaultId);
            unclaimedSirRewards[vaultId - offset - 1] = VAULT.unclaimedRewards(vaultId, user);
        }
    }

    /**
     * @notice It returns the ideal price of TEA.
     * To get the price as [units of Collateral][per unit of TEA], divide num by den.
     */
    function priceOfTEA(
        SirStructs.VaultParameters calldata vaultParams
    ) external view returns (uint256 num, uint256 den) {
        // Get current reserves
        SirStructs.Reserves memory reserves = VAULT.getReserves(vaultParams);
        num = reserves.reserveLPers;

        // Get supply of TEA
        SirStructs.VaultState memory vaultState = VAULT.vaultStates(vaultParams);
        den = VAULT.totalSupply(vaultState.vaultId);
    }

    /**
     * @notice It returns the price of the APE token.
     * To get the price as [units of Collateral][per unit of APE], divide num by den.
     */
    function priceOfAPE(
        SirStructs.VaultParameters calldata vaultParams
    ) external view returns (uint256 num, uint256 den) {
        // Get current reserves
        SirStructs.Reserves memory reserves = VAULT.getReserves(vaultParams);

        // Get system parameters
        SirStructs.SystemParameters memory systemParams = VAULT.systemParams();

        // Substract fees
        num = _feeAPE(reserves.reserveApes, systemParams.baseFee.fee, vaultParams.leverageTier);

        // Get supply of APE
        SirStructs.VaultState memory vaultState = VAULT.vaultStates(vaultParams);
        den = IERC20(getAddressAPE(vaultState.vaultId)).totalSupply();
    }

    /**
     * @notice It returns the status of the vault.
     * 0: InvalidVault - returned when the ERC20 tokens are not valid.
     * 1: NoUniswapPool - returned when no Uniswap pool of the two tokens does not exist.
     * 2: VaultCanBeCreated - vault does not exist and it can be created.
     * 3: VaultAlreadyExists - vault already exists.
     */
    function getVaultStatus(SirStructs.VaultParameters calldata vaultParams) external view returns (VaultStatus) {
        // Check if the token addresses are a smart contract
        if (vaultParams.collateralToken.code.length == 0) return VaultStatus.InvalidVault;
        if (vaultParams.debtToken.code.length == 0) return VaultStatus.InvalidVault;

        // Check if the token returns total supply
        (bool success, ) = vaultParams.collateralToken.staticcall(abi.encodeWithSelector(IERC20.totalSupply.selector));
        if (!success) return VaultStatus.InvalidVault;
        (success, ) = vaultParams.debtToken.staticcall(abi.encodeWithSelector(IERC20.totalSupply.selector));
        if (!success) return VaultStatus.InvalidVault;

        // Check if the leverage tier is valid
        if (
            vaultParams.leverageTier < SystemConstants.MIN_LEVERAGE_TIER ||
            vaultParams.leverageTier > SystemConstants.MAX_LEVERAGE_TIER
        ) return VaultStatus.InvalidVault;

        // Check if a Uniswap pool exists
        if (
            !_checkFeeTierExists(vaultParams, 100) &&
            !_checkFeeTierExists(vaultParams, 500) &&
            !_checkFeeTierExists(vaultParams, 3000) &&
            !_checkFeeTierExists(vaultParams, 10000)
        ) return VaultStatus.NoUniswapPool;

        // Check if vault already exists
        SirStructs.VaultState memory vaultState = VAULT.vaultStates(vaultParams);
        if (vaultState.vaultId == 0) return VaultStatus.VaultCanBeCreated;
        return VaultStatus.VaultAlreadyExists;
    }

    function getAddressAPE(uint48 vaultId) public view returns (address) {
        return AddressClone.getAddress(address(VAULT), vaultId);
    }

    /*////////////////////////////////////////////////////////////////
                            QUOTE FUNCTIONS
    ////////////////////////////////////////////////////////////////*/

    /**
     * @notice It returns the amount of TEA/APE tokens that would be obtained by depositing collateral token.
     * @dev If quoteMint reverts, mint will revert as well; vice versa is not necessarily true.
     * @return amountTokens that would be obtained by depositing amountCollateral.
     */
    function quoteMint(
        bool isAPE,
        SirStructs.VaultParameters calldata vaultParams,
        uint144 amountCollateral
    ) public view returns (uint256 amountTokens) {
        // Get vault state
        SirStructs.VaultState memory vaultState = VAULT.vaultStates(vaultParams);
        if (vaultState.vaultId == 0) revert VaultDoesNotExist();
        if (amountCollateral == 0) revert AmountTooLow();

        // Get current reserves
        SirStructs.Reserves memory reserves = VAULT.getReserves(vaultParams);

        SirStructs.SystemParameters memory systemParams = VAULT.systemParams();
        if (isAPE) {
            // Compute how much collateral actually gets deposited
            uint256 collateralIn = _feeAPE(amountCollateral, systemParams.baseFee.fee, vaultParams.leverageTier);

            // Get supply of APE
            address ape = getAddressAPE(vaultState.vaultId);
            uint256 supplyAPE = IERC20(ape).totalSupply();

            // Calculate tokens
            amountTokens = supplyAPE == 0
                ? collateralIn + reserves.reserveApes
                : FullMath.mulDiv(supplyAPE, collateralIn, reserves.reserveApes);
        } else {
            // Get collateralIn
            uint256 collateralIn = _feeMintTEA(amountCollateral, systemParams.lpFee.fee);

            // Get supply of TEA
            uint256 supplyTEA = VAULT.totalSupply(vaultState.vaultId);

            // Calculate tokens
            amountTokens = supplyTEA == 0
                ? _amountFirstMint(vaultParams.collateralToken, amountCollateral + reserves.reserveLPers)
                : FullMath.mulDiv(supplyTEA, amountCollateral, reserves.reserveLPers);

            // Check that total supply does not overflow
            if (amountTokens > SystemConstants.TEA_MAX_SUPPLY - supplyTEA) revert TEAMaxSupplyExceeded();

            // Minter's share of TEA
            amountTokens = FullMath.mulDiv(
                amountTokens,
                collateralIn,
                supplyTEA == 0
                    ? amountCollateral + reserves.reserveLPers // In the first mint, reserveLPers contains orphaned fees from apes
                    : amountCollateral
            );
        }

        if (amountTokens == 0) revert AmountTooLow();
    }

    /**
     * @notice It returns the amount of TEA/APE tokens that would be obtained by depositing debt token
     * @dev If quoteMint reverts, mint will revert as well; vice versa is not necessarily true.
     * @return amountTokens that would be obtained.
     */
    function quoteMintWithDebtToken(
        bool isAPE,
        SirStructs.VaultParameters calldata vaultParams,
        uint256 amountDebtToken
    ) external view returns (uint256 amountTokens, uint256 amountCollateral, uint256 amountCollateralIdeal) {
        if (amountDebtToken == 0) revert AmountTooLow();

        // Get fee tier
        uint24 feeTier = SIR_ORACLE.uniswapFeeTierOf(vaultParams.debtToken, vaultParams.collateralToken);

        // Quote Uniswap v3
        (amountCollateral, , , ) = UNISWAPV3_QUOTER.quoteExactInputSingle(
            IQuoter.QuoteExactInputSingleParams({
                tokenIn: vaultParams.debtToken,
                tokenOut: vaultParams.collateralToken,
                amountIn: amountDebtToken,
                fee: feeTier,
                sqrtPriceLimitX96: 0
            })
        );

        // Check that amountCollateral does not overflow
        if (amountCollateral > type(uint144).max) revert TooMuchCollateral();

        // Calculate ideal collateral amount using instant pool price (no slippage)
        // Get Uniswap pool
        address uniswapPool = SIR_ORACLE.uniswapFeeTierAddressOf(vaultParams.debtToken, vaultParams.collateralToken);

        // Get current price
        (uint160 sqrtPriceX96, , , , , , ) = IUniswapV3Pool(uniswapPool).slot0();

        // Calculate price fraction with better precision if it doesn't overflow when multiplied by itself
        bool inverse = vaultParams.collateralToken == IUniswapV3Pool(uniswapPool).token1();
        if (sqrtPriceX96 <= type(uint128).max) {
            uint256 priceX192 = uint256(sqrtPriceX96) * sqrtPriceX96;
            amountCollateralIdeal = inverse
                ? FullMath.mulDiv(1 << 192, amountDebtToken, priceX192)
                : FullMath.mulDiv(priceX192, amountDebtToken, 1 << 192);
        } else {
            uint256 priceX128 = FullMath.mulDiv(sqrtPriceX96, sqrtPriceX96, 1 << 64);
            amountCollateralIdeal = inverse
                ? FullMath.mulDiv(1 << 128, amountDebtToken, priceX128)
                : FullMath.mulDiv(priceX128, amountDebtToken, 1 << 128);
        }

        // Given that we know how much collateral we will get from Uniswap, we can now use the quoteMint function
        amountTokens = quoteMint(isAPE, vaultParams, uint144(amountCollateral));
    }

    function quoteCollateralToDebtToken(
        address debtToken,
        address collateralToken,
        uint256 amountCollateral
    ) external view returns (uint256 amountDebtToken) {
        // Get Uniswap pool
        address uniswapPool = SIR_ORACLE.uniswapFeeTierAddressOf(debtToken, collateralToken);

        // Get current price
        (uint160 sqrtPriceX96, , , , , , ) = IUniswapV3Pool(uniswapPool).slot0();

        // Calculate price fraction with better precision if it doesn't overflow when multiplied by itself
        bool inverse = collateralToken == IUniswapV3Pool(uniswapPool).token1();
        if (sqrtPriceX96 <= type(uint128).max) {
            uint256 priceX192 = uint256(sqrtPriceX96) * sqrtPriceX96;
            return
                !inverse
                    ? FullMath.mulDiv(priceX192, amountCollateral, 1 << 192)
                    : FullMath.mulDiv(1 << 192, amountCollateral, priceX192);
        } else {
            uint256 priceX128 = FullMath.mulDiv(sqrtPriceX96, sqrtPriceX96, 1 << 64);
            return
                !inverse
                    ? FullMath.mulDiv(priceX128, amountCollateral, 1 << 128)
                    : FullMath.mulDiv(1 << 128, amountCollateral, priceX128);
        }
    }

    /**
     * @notice If quoteBurn reverts, burn in Vault.sol will revert as well; vice versa is not necessarily true.
     * @return amountCollateral that would be obtained by burning amountTokens.
     */
    function quoteBurn(
        bool isAPE,
        SirStructs.VaultParameters calldata vaultParams,
        uint256 amountTokens
    ) external view returns (uint144 amountCollateral) {
        // Get vault state
        SirStructs.VaultState memory vaultState = VAULT.vaultStates(vaultParams);
        if (vaultState.vaultId == 0) revert VaultDoesNotExist();
        if (amountTokens == 0) revert AmountTooLow();

        // Get current reserves
        SirStructs.Reserves memory reserves = VAULT.getReserves(vaultParams);

        if (isAPE) {
            // Get supply of APE
            address ape = getAddressAPE(vaultState.vaultId);
            uint256 supplyAPE = IERC20(ape).totalSupply();

            // Get collateralOut
            uint144 collateralOut = uint144(FullMath.mulDiv(reserves.reserveApes, amountTokens, supplyAPE));

            // Get system parameters
            SirStructs.SystemParameters memory systemParams = VAULT.systemParams();

            // Get collateral withdrawn
            amountCollateral = _feeAPE(collateralOut, systemParams.baseFee.fee, vaultParams.leverageTier);
        } else {
            // Get supply of TEA
            uint256 supplyTEA = VAULT.totalSupply(vaultState.vaultId);

            // Get amount of collateral that would be withdrawn
            amountCollateral = uint144(FullMath.mulDiv(reserves.reserveLPers, amountTokens, supplyTEA));
        }
    }

    /*////////////////////////////////////////////////////////////////
                            PRIVATE FUNCTIONS
    ////////////////////////////////////////////////////////////////*/

    function _feeAPE(
        uint144 collateralDepositedOrOut,
        uint16 baseFee,
        int256 leverageTier
    ) private pure returns (uint144 collateralInOrWithdrawn) {
        unchecked {
            uint256 feeNum;
            uint256 feeDen;
            if (leverageTier >= 0) {
                feeNum = 10000; // baseFee is uint16, leverageTier is int8, so feeNum does not require more than 24 bits
                feeDen = 10000 + (uint256(baseFee) << uint256(leverageTier));
            } else {
                uint256 temp = 10000 << uint256(-leverageTier);
                feeNum = temp;
                feeDen = temp + uint256(baseFee);
            }

            collateralInOrWithdrawn = uint144((uint256(collateralDepositedOrOut) * feeNum) / feeDen);
        }
    }

    function _feeMintTEA(uint144 collateralDeposited, uint16 lpFee) private pure returns (uint144 collateralIn) {
        unchecked {
            uint256 feeNum = 10000;
            uint256 feeDen = 10000 + uint256(lpFee);

            collateralIn = uint144((uint256(collateralDeposited) * feeNum) / feeDen);
        }
    }

    function _checkFeeTierExists(
        SirStructs.VaultParameters calldata vaultParams,
        uint24 feeTier
    ) private view returns (bool) {
        return
            UniswapPoolAddress
                .computeAddress(
                    UNISWAPV3_FACTORY,
                    UniswapPoolAddress.getPoolKey(vaultParams.collateralToken, vaultParams.debtToken, feeTier)
                )
                .code
                .length != 0;
    }

    function _amountFirstMint(address collateral, uint144 collateralDeposited) private view returns (uint256 amount) {
        uint256 collateralTotalSupply = IERC20(collateral).totalSupply();
        amount = collateralTotalSupply > SystemConstants.TEA_MAX_SUPPLY / 1e6
            ? FullMath.mulDiv(SystemConstants.TEA_MAX_SUPPLY, collateralDeposited, collateralTotalSupply)
            : collateralDeposited * 1e6;
    }
}
"
    },
    "src/interfaces/IQuoter.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >0.7.6;
pragma abicoder v2;

/// @title QuoterV2 Interface
/// @notice Supports quoting the calculated amounts from exact input or exact output swaps.
/// @notice For each pool also tells you the number of initialized ticks crossed and the sqrt price of the pool after the swap.
/// @dev These functions are not marked view because they rely on calling non-view functions and reverting
/// to compute the result. They are also not gas efficient and should not be called on-chain.
interface IQuoter {
    /// @notice Returns the amount out received for a given exact input swap without executing the swap
    /// @param path The path of the swap, i.e. each token pair and the pool fee
    /// @param amountIn The amount of the first token to swap
    /// @return amountOut The amount of the last token that would be received
    /// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path
    /// @return initializedTicksCrossedList List of number of initialized ticks loaded
    function quoteExactInput(
        bytes memory path,
        uint256 amountIn
    )
        external
        view
        returns (
            uint256 amountOut,
            uint160[] memory sqrtPriceX96AfterList,
            uint32[] memory initializedTicksCrossedList,
            uint256 gasEstimate
        );

    struct QuoteExactInputSingleWithPoolParams {
        address tokenIn;
        address tokenOut;
        uint256 amountIn;
        address pool;
        uint24 fee;
        uint160 sqrtPriceLimitX96;
    }

    /// @notice Returns the amount out received for a given exact input but for a swap of a single pool
    /// @param params The params for the quote, encoded as `quoteExactInputSingleWithPool`
    /// tokenIn The token being swapped in
    /// amountIn The desired input amount
    /// tokenOut The token being swapped out
    /// fee The fee of the pool to consider for the pair
    /// pool The address of the pool to consider for the pair
    /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap
    /// @return amountOut The amount of `tokenOut` that would be received
    /// @return sqrtPriceX96After The sqrt price of the pool after the swap
    /// @return initializedTicksCrossed The number of initialized ticks loaded
    function quoteExactInputSingleWithPool(
        QuoteExactInputSingleWithPoolParams memory params
    )
        external
        view
        returns (uint256 amountOut, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate);

    struct QuoteExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        uint256 amountIn;
        uint24 fee;
        uint160 sqrtPriceLimitX96;
    }

    /// @notice Returns the amount out received for a given exact input but for a swap of a single pool
    /// @param params The params for the quote, encoded as `QuoteExactInputSingleParams`
    /// tokenIn The token being swapped in
    /// amountIn The desired input amount
    /// tokenOut The token being swapped out
    /// fee The fee of the token pool to consider for the pair
    /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap
    /// @return amountOut The amount of `tokenOut` that would be received
    /// @return sqrtPriceX96After The sqrt price of the pool after the swap
    /// @return initializedTicksCrossed The number of initialized ticks loaded
    function quoteExactInputSingle(
        QuoteExactInputSingleParams memory params
    )
        external
        view
        returns (uint256 amountOut, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate);

    struct QuoteExactOutputSingleWithPoolParams {
        address tokenIn;
        address tokenOut;
        uint256 amount;
        uint24 fee;
        address pool;
        uint160 sqrtPriceLimitX96;
    }

    /// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool
    /// @param params The params for the quote, encoded as `QuoteExactOutputSingleWithPoolParams`
    /// tokenIn The token being swapped in
    /// tokenOut The token being swapped out
    /// amount The desired output amount
    /// fee The fee of the token pool to consider for the pair
    /// pool The address of the pool to consider for the pair
    /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap
    /// @return amountIn The amount required as the input for the swap in order to receive `amountOut`
    /// @return sqrtPriceX96After The sqrt price of the pool after the swap
    /// @return initializedTicksCrossed The number of initialized ticks loaded
    function quoteExactOutputSingleWithPool(
        QuoteExactOutputSingleWithPoolParams memory params
    )
        external
        view
        returns (uint256 amountIn, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate);

    struct QuoteExactOutputSingleParams {
        address tokenIn;
        address tokenOut;
        uint256 amount;
        uint24 fee;
        uint160 sqrtPriceLimitX96;
    }

    /// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool
    /// @param params The params for the quote, encoded as `QuoteExactOutputSingleParams`
    /// tokenIn The token being swapped in
    /// tokenOut The token being swapped out
    /// amountOut The desired output amount
    /// fee The fee of the token pool to consider for the pair
    /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap
    /// @return amountIn The amount required as the input for the swap in order to receive `amountOut`
    /// @return sqrtPriceX96After The sqrt price of the pool after the swap
    /// @return initializedTicksCrossed The number of initialized ticks loaded
    function quoteExactOutputSingle(
        QuoteExactOutputSingleParams memory params
    )
        external
        view
        returns (uint256 amountIn, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate);

    /// @notice Returns the amount in required for a given exact output swap without executing the swap
    /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order
    /// @param amountOut The amount of the last token to receive
    /// @return amountIn The amount of first token required to be paid
    /// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path
    /// @return initializedTicksCrossedList List of the initialized ticks that the swap crossed for each pool in the path
    function quoteExactOutput(
        bytes memory path,
        uint256 amountOut
    )
        external
        view
        returns (
            uint256 amountIn,
            uint160[] memory sqrtPriceX96AfterList,
            uint32[] memory initializedTicksCrossedList,
            uint256 gasEstimate
        );
}
"
    },
    "lib/Core/src/interfaces/IVault.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {SirStructs} from "../libraries/SirStructs.sol";

interface IVault {
    error AmountTooLow();
    error DeadlineExceeded();
    error ExcessiveDeposit();
    error InsufficientCollateralReceivedFromUniswap();
    error InsufficientDeposit();
    error LengthMismatch();
    error LeverageTierOutOfRange();
    error Locked();
    error NotAWETHVault();
    error NotAuthorized();
    error StringsInsufficientHexLength(uint256 value, uint256 length);
    error TEAMaxSupplyExceeded();
    error TransferToZeroAddress();
    error UnsafeRecipient();
    error VaultAlreadyInitialized();
    error VaultDoesNotExist();

    event ApprovalForAll(address indexed account, address indexed operator, bool approved);
    event ReservesChanged(uint48 indexed vaultId, bool isAPE, bool isMint, uint144 reserveLPers, uint144 reserveApes);
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] vaultIds,
        uint256[] amounts
    );
    event TransferSingle(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256 id,
        uint256 amount
    );
    event URI(string value, uint256 indexed id);
    event VaultInitialized(
        address indexed debtToken,
        address indexed collateralToken,
        int8 indexed leverageTier,
        uint256 vaultId,
        address ape
    );
    event VaultNewTax(uint48 indexed vault, uint8 tax, uint16 cumulativeTax);

    function APE_IMPLEMENTATION() external view returns (address);
    function ORACLE() external view returns (address);
    function SIR() external view returns (address);
    function SYSTEM_CONTROL() external view returns (address);
    function TIMESTAMP_ISSUANCE_START() external view returns (uint40);
    function balanceOf(address account, uint256 vaultId) external view returns (uint256);
    function balanceOfBatch(
        address[] memory owners,
        uint256[] memory vaultIds
    ) external view returns (uint256[] memory balances_);
    function burn(
        bool isAPE,
        SirStructs.VaultParameters memory vaultParams,
        uint256 amount,
        uint40 deadline
    ) external returns (uint144);
    function claimSIR(uint256 vaultId, address lper) external returns (uint80);
    function cumulativeSIRPerTEA(uint256 vaultId) external view returns (uint176 cumulativeSIRPerTEAx96);
    function getReserves(
        SirStructs.VaultParameters memory vaultParams
    ) external view returns (SirStructs.Reserves memory);
    function initialize(SirStructs.VaultParameters memory vaultParams) external;
    function isApprovedForAll(address, address) external view returns (bool);
    function mint(
        bool isAPE,
        SirStructs.VaultParameters memory vaultParams,
        uint256 amountToDeposit,
        uint144 collateralToDepositMin,
        uint40 deadline
    ) external payable returns (uint256 amount);
    function numberOfVaults() external view returns (uint48);
    function paramsById(uint48 vaultId) external view returns (SirStructs.VaultParameters memory);
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory vaultIds,
        uint256[] memory amounts,
        bytes memory data
    ) external;
    function safeTransferFrom(address from, address to, uint256 vaultId, uint256 amount, bytes memory data) external;
    function setApprovalForAll(address operator, bool approved) external;
    function supportsInterface(bytes4 interfaceId) external pure returns (bool);
    function systemParams() external view returns (SirStructs.SystemParameters memory systemParams_);
    function totalReserves(address collateral) external view returns (uint256);
    function totalSupply(uint256 vaultId) external view returns (uint256);
    function unclaimedRewards(uint256 vaultId, address lper) external view returns (uint80);
    function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes memory data) external;
    function updateSystemState(uint16 baseFee, uint16 lpFee, bool mintingStopped) external;
    function updateVaults(
        uint48[] memory oldVaults,
        uint48[] memory newVaults,
        uint8[] memory newTaxes,
        uint16 cumulativeTax
    ) external;
    function uri(uint256 vaultId) external view returns (string memory);
    function vaultStates(
        SirStructs.VaultParameters memory vaultParams
    ) external view returns (SirStructs.VaultState memory);
    function vaultTax(uint48 vaultId) external view returns (uint8);
    function withdrawFees(address token) external returns (uint256 totalFeesToStakers);
    function withdrawToSaveSystem(address[] memory tokens, address to) external returns (uint256[] memory amounts);
}
"
    },
    "lib/Core/src/interfaces/IOracle.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {SirStructs} from "../libraries/SirStructs.sol";

interface IOracle {
    error NoUniswapPool();
    error OracleNotInitialized();
    error UniswapFeeTierIndexOutOfBounds();

    event OracleFeeTierChanged(uint24 feeTierPrevious, uint24 feeTierSelected);
    event OracleInitialized(
        address indexed token0,
        address indexed token1,
        uint24 feeTierSelected,
        uint136 avLiquidity,
        uint40 period
    );
    event PriceUpdated(address indexed token0, address indexed token1, bool priceTruncated, int64 priceTickX42);
    event UniswapFeeTierAdded(uint24 fee);
    event UniswapOracleProbed(uint24 fee, uint136 avLiquidity, uint40 period, uint16 cardinalityToIncrease);

    function TWAP_DURATION() external view returns (uint40);
    function getPrice(address collateralToken, address debtToken) external view returns (int64);
    function getUniswapFeeTiers() external view returns (SirStructs.UniswapFeeTier[] memory uniswapFeeTiers);
    function initialize(address tokenA, address tokenB) external;
    function newUniswapFeeTier(uint24 fee) external;
    function state(address token0, address token1) external view returns (SirStructs.OracleState memory);
    function uniswapFeeTierAddressOf(address tokenA, address tokenB) external view returns (address);
    function uniswapFeeTierOf(address tokenA, address tokenB) external view returns (uint24);
    function updateOracleState(
        address collateralToken,
        address debtToken
    ) external returns (int64 tickPriceX42, address uniswapPoolAddress);
}
"
    },
    "lib/Core/lib/v3-core/contracts/interfaces/IUniswapV3Pool.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

import {IUniswapV3PoolImmutables} from './pool/IUniswapV3PoolImmutables.sol';
import {IUniswapV3PoolState} from './pool/IUniswapV3PoolState.sol';
import {IUniswapV3PoolDerivedState} from './pool/IUniswapV3PoolDerivedState.sol';
import {IUniswapV3PoolActions} from './pool/IUniswapV3PoolActions.sol';
import {IUniswapV3PoolOwnerActions} from './pool/IUniswapV3PoolOwnerActions.sol';
import {IUniswapV3PoolErrors} from './pool/IUniswapV3PoolErrors.sol';
import {IUniswapV3PoolEvents} from './pool/IUniswapV3PoolEvents.sol';

/// @title The interface for a Uniswap V3 Pool
/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform
/// to the ERC20 specification
/// @dev The pool interface is broken up into many smaller pieces
interface IUniswapV3Pool is
    IUniswapV3PoolImmutables,
    IUniswapV3PoolState,
    IUniswapV3PoolDerivedState,
    IUniswapV3PoolActions,
    IUniswapV3PoolOwnerActions,
    IUniswapV3PoolErrors,
    IUniswapV3PoolEvents
{

}
"
    },
    "lib/Core/src/libraries/SirStructs.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

library SirStructs {
    struct VaultIssuanceParams {
        uint8 tax; // (tax / type(uint8).max * 10%) of its fee revenue is directed to the Treasury.
        uint40 timestampLastUpdate; // timestamp of the last time cumulativeSIRPerTEAx96 was updated. 0 => use systemParams.timestampIssuanceStart instead
        uint176 cumulativeSIRPerTEAx96; // Q104.96, cumulative SIR minted by the vaultId per unit of TEA.
    }

    struct VaultParameters {
        address debtToken;
        address collateralToken;
        int8 leverageTier;
    }

    struct FeeStructure {
        uint16 fee; // Fee in basis points.
        uint16 feeNew; // New fee to replace fee if current time exceeds FEE_CHANGE_DELAY since timestampUpdate
        uint40 timestampUpdate; // Timestamp fee change was made. If 0, feeNew is not used.
    }

    struct SystemParameters {
        FeeStructure baseFee;
        FeeStructure lpFee;
        bool mintingStopped; // If true, no minting of TEA/APE
        /** Aggregated taxes for all vaults. Choice of uint16 type.
            For vault i, (tax_i / type(uint8).max)*10% is charged, where tax_i is of type uint8.
            They must satisfy the condition
                Σ_i (tax_i / type(uint8).max)^2 ≤ 0.1^2
            Under this constraint, cumulativeTax = Σ_i tax_i is maximized when all taxes are equal (tax_i = tax for all i) and
                tax = type(uint8).max / sqrt(Nvaults)
            Since the lowest non-zero value is tax=1, the maximum number of vaults with non-zero tax is
                Nvaults = type(uint8).max^2 < type(uint16).max
         */
        uint16 cumulativeTax;
    }

    /** Collateral owned by the apes and LPers in a vault
     */
    struct Reserves {
        uint144 reserveApes;
        uint144 reserveLPers;
        int64 tickPriceX42;
    }

    /** Data needed for recoverying the amount of collateral owned by the apes and LPers in a vault
     */
    struct VaultState {
        uint144 reserve; // reserve =  reserveApes + reserveLPers
        /** Price at the border of the power and saturation zone.
            Q21.42 - Fixed point number with 42 bits of precision after the comma.
            type(int64).max and type(int64).min are used to represent +∞ and -∞ respectively.
         */
        int64 tickPriceSatX42; // Saturation price in Q21.42 fixed point
        uint48 vaultId; // Allows the creation of approximately 281 trillion vaults
    }

    /** The sum of all amounts in Fees are equal to the amounts deposited by the user (in the case of a mint)
        or taken out by the user (in the case of a burn).
        collateralInOrWithdrawn: Amount of collateral deposited by the user (in the case of a mint) or taken out by the user (in the case of a burn).
        collateralFeeToStakers: Amount of collateral paid to the stakers.
        collateralFeeToLPers: Amount of collateral paid to the gentlemen.
        collateralFeeToProtocol: Amount of collateral paid to the protocol.
     */
    struct Fees {
        uint144 collateralInOrWithdrawn;
        uint144 collateralFeeToStakers;
        uint144 collateralFeeToLPers; // Sometimes all LPers and sometimes only protocol owned liquidity
    }

    struct StakingParams {
        uint80 stake; // Amount of staked SIR
        uint176 cumulativeHYPEPerSIRx80; // Cumulative HYPE per SIR * 2^80
    }

    struct StakerParams {
        uint80 stake; // Total amount of staked SIR by the staker
        uint176 cumulativeHYPEPerSIRx80; // Cumulative HYPE per SIR * 2^80 last time the user updated his balance of HYPE dividends
        uint80 lockedStake; // Amount of stake that was locked at time 'tsLastUpdate'
        uint40 tsLastUpdate; // Timestamp of the last time the user staked or unstaked
    }

    struct Auction {
        address bidder; // Address of the bidder
        uint96 bid; // Amount of the bid
        uint40 startTime; // Auction start time
    }

    struct OracleState {
        int64 tickPriceX42; // Last stored price. Q21.42
        uint40 timeStampPrice; // Timestamp of the last stored price
        uint8 indexFeeTier; // Uniswap v3 fee tier currently being used as oracle
        uint8 indexFeeTierProbeNext; // Uniswap v3 fee tier to probe next
        uint40 timeStampFeeTier; // Timestamp of the last probed fee tier
        bool initialized; // Whether the oracle has been initialized
        UniswapFeeTier uniswapFeeTier; // Uniswap v3 fee tier currently being used as oracle
    }

    /**
     * Parameters of a Uniswap v3 tier.
     */
    struct UniswapFeeTier {
        uint24 fee;
        int24 tickSpacing;
    }
}
"
    },
    "lib/Core/src/libraries/SystemConstants.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

library SystemConstants {
    uint8 internal constant SIR_DECIMALS = 12;

    /** SIR Token Issuance Rate
        If we want to issue 2,015,000,000 SIR per year, this implies an issuance rate of 63.9 SIR/s.
     */
    uint72 internal constant ISSUANCE = uint72(2015e6 * 10 ** SIR_DECIMALS - 1) / 365 days + 1; // [sir/s]

    /** During the first 3 years, 30%-to-33% of the emissions are diverged to contributors.
        - 10% to pre-mainnet contributors
        - 10%-13% to fundraising contributors
        - 10% to a treasury for post-mainnet stuff
     */
    uint72 internal constant LP_ISSUANCE_FIRST_3_YEARS = uint72((uint256(78024266200000000) * ISSUANCE) / 1e17);

    uint128 internal constant TEA_MAX_SUPPLY = (uint128(LP_ISSUANCE_FIRST_3_YEARS) << 96) / type(uint16).max; // Must fit in uint128

    uint40 internal constant THREE_YEARS = 3 * 365 days;

    int64 internal constant MAX_TICK_X42 = 1951133415219145403; // log_1.0001(x)*2^42 where x is the max possible Q64.64 value, i.e., 2^64 - 2^-64

    // Approximately 10 days. We did not choose 10 days precisely to avoid auctions always ending on the same day and time of the week.
    uint40 internal constant AUCTION_COOLDOWN = 247 hours; // 247h & 240h have no common factors

    // Duration of an auction
    uint40 internal constant AUCTION_DURATION = 24 hours;

    // Time it takes for a change of LP or base fee to take effect
    uint256 internal constant FEE_CHANGE_DELAY = 1 days;

    uint40 internal constant SHUTDOWN_WITHDRAWAL_DELAY = 20 days;

    int8 internal constant MAX_LEVERAGE_TIER = 2;

    int8 internal constant MIN_LEVERAGE_TIER = -4;

    uint256 internal constant HALVING_PERIOD = 30 days; // Every 30 days, half of the locked stake is unlocked
}
"
    },
    "lib/Core/src/libraries/FullMath.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
/// @dev Modified from https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol so that it can compile on Solidity 8
library FullMath {
    /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    function mulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
        // 512-bit multiply [prod1 prod0] = a * b
        // Compute the product mod 2**256 and mod 2**256 - 1
        // then use the Chinese Remainder Theorem to reconstruct
        // the 512 bit result. The result is stored in two 256
        // variables such that product = prod1 * 2**256 + prod0
        uint256 prod0; // Least significant 256 bits of the product
        uint256 prod1; // Most significant 256 bits of the product
        assembly {
            let mm := mulmod(a, b, not(0))
            prod0 := mul(a, b)
            prod1 := sub(sub(mm, prod0), lt(mm, prod0))
        }

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

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

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

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

        // Factor powers of two out of denominator
        // Compute largest power of two divisor of denominator.
        // Always >= 1.
        unchecked {
            uint256 twos = (type(uint256).max - denominator + 1) & denominator;
            // Divide denominator by power of two
            assembly {
                denominator := div(denominator, twos)
            }

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

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

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

    function tryMulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (bool success, uint256 result) {
        // 512-bit multiply [prod1 prod0] = a * b
        // Compute the product mod 2**256 and mod 2**256 - 1
        // then use the Chinese Remainder Theorem to reconstruct
        // the 512 bit result. The result is stored in two 256
        // variables such that product = prod1 * 2**256 + prod0
        uint256 prod0; // Least significant 256 bits of the product
        uint256 prod1; // Most significant 256 bits of the product
        assembly {
            let mm := mulmod(a, b, not(0))
            prod0 := mul(a, b)
            prod1 := sub(sub(mm, prod0), lt(mm, prod0))
        }

        // Handle non-overflow cases, 256 by 256 division
        if (prod1 == 0) {
            if (denominator == 0) return (false, 0);
            assembly {
                result := div(prod0, denominator)
            }
            return (true, result);
        }

        // Make sure the result is less than 2**256.
        // Also prevents denominator == 0
        if (denominator <= prod1) return (false, 0);

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

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

        // Factor powers of two out of denominator
        // Compute largest power of two divisor of denominator.
        // Always >= 1.
        unchecked {
            uint256 twos = (type(uint256).max - denominator + 1) & denominator;
            // Divide denominator by power of two
            assembly {
                denominator := div(denominator, twos)
            }

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

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

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

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

    function tryMulDivRoundingUp(
        uint256 a,
        uint256 b,
        uint256 denominator
    ) internal pure returns (bool success, uint256 result) {
        (success, result) = tryMulDiv(a, b, denominator);
        if (success && mulmod(a, b, denominator) > 0) {
            if (result == type(uint256).max) return (false, 0);
            result++;
        }
    }
}
"
    },
    "lib/Core/src/interfaces/IWETH9.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

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

/// @title Interface for WETH9
interface IWETH9 is IERC20 {
    /// @notice Deposit ether to get wrapped ether
    function deposit() external payable;

    /// @notice Withdraw wrapped ether to get ether
    function withdraw(uint256) external;
}
"
    },
    "lib/Core/src/libraries/UniswapPoolAddress.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Provides functions for deriving a pool address from the factory, tokens, and the fee
/// @notice Modified from https://github.com/Uniswap/v3-periphery/blob/main/contracts/libraries/PoolAddress.sol
library UniswapPoolAddress {
    bytes32 internal constant POOL_INIT_CODE_HASH = 0xe3572921be1688dba92df30c6781b8770499ff274d20ae9b325f4242634774fb;

    /// @notice The identifying key of the pool
    struct PoolKey {
        address token0;
        address token1;
        uint24 fee;
    }

    /// @notice Returns PoolKey: the ordered tokens with the matched fee levels
    /// @param tokenA The first token of a pool, unsorted
    /// @param tokenB The second token of a pool, unsorted
    /// @param fee The fee level of the pool
    /// @return Poolkey The pool details with ordered token0 and token1 assignments
    function getPoolKey(address tokenA, address tokenB, uint24 fee) internal pure returns (PoolKey memory) {
        if (tokenA > tokenB) (tokenA, tokenB) = (tokenB, tokenA);
        return PoolKey({token0: tokenA, token1: tokenB, fee: fee});
    }

    /// @notice Deterministically computes the pool address given the factory and PoolKey
    /// @param factory The Uniswap V3 factory contract address
    /// @param key The PoolKey
    /// @return pool The contract address of the V3 pool
    function computeAddress(address factory, PoolKey memory key) internal pure returns (address pool) {
        require(key.token0 < key.token1);
        pool = address(
            uint160(
                uint256(
                    keccak256(
                        abi.encodePacked(
                            hex"ff",
                            factory,
                            keccak256(abi.encode(key.token0, key.token1, key.fee)),
                            POOL_INIT_CODE_HASH
                        )
                    )
                )
            )
        );
    }
}
"
    },
    "lib/Core/src/libraries/AddressClone.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

library AddressClone {
    /// @dev Hash of the `_CREATE3_PROXY_BYTECODE`.
    /// Equivalent to `keccak256(abi.encodePacked(hex"67363d3d37363d34f03d5260086018f3"))`.
    bytes32 private constant _CREATE3_PROXY_BYTECODE_HASH =
        0x21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f;

    function getAddress(address deployer, uint256 vaultId) internal pure returns (address clone) {
        /// @solidity memory-safe-assembly
        // solhint-disable-next-line no-inline-assembly
        assembly {
            // Cache the free memory pointer.
            let m := mload(0x40)
            // Store `address(this)`.
            mstore(0x00, deployer)
            // Store the prefix.
            mstore8(0x0b, 0xff)
            // Store the salt.
            mstore(0x20, vaultId)
            // Store the bytecode hash.
            mstore(0x40, _CREATE3_PROXY_BYTECODE_HASH)

            // Store the proxy's address.
            mstore(0x14, keccak256(0x0b, 0x55))
            // Restore the free memory pointer.
            mstore(0x40, m)
            // 0xd6 = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x01).
            // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex).
            mstore(0x00, 0xd694)
            // Nonce of the proxy contract (1).
            mstore8(0x34, 0x01)

            clone := and(keccak256(0x1e, 0x17), 0xffffffffffffffffffffffffffffffffffffffff)
        }
    }
}
"
    },
    "lib/forge-std/src/console.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

library console {
    address constant CONSOLE_ADDRESS =
        0x000000000000000000636F6e736F6c652e6c6f67;

    function _sendLogPayloadImplementation(bytes memory payload) internal view {
        address consoleAddress = CONSOLE_ADDRESS;
        /// @solidity memory-safe-assembly
        assembly {
            pop(
                staticcall(
                    gas(),
                    consoleAddress,
                    add(payload, 32),
                    mload(payload),
                    0,
                    0
                )
            )
        }
    }

    function _castToPure(
      function(bytes memory) internal view fnIn
    ) internal pure returns (function(bytes memory) pure fnOut) {
        assembly {
            fnOut := fnIn
        }
    }

    function _sendLogPayload(bytes memory payload) internal pure {
        _castToPure(_sendLogPayloadImplementation)(payload);
    }

    function log() internal pure {
        _sendLogPayload(abi.encodeWithSignature("log()"));
    }

    function logInt(int256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(int256)", p0));
    }

    function logUint(uint256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
    }

    function logString(string memory p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
    }

    function logBool(bool p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
    }

    function logAddress(address p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
    }

    function logBytes(bytes memory p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
    }

    function logBytes1(bytes1 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
    }

    function logBytes2(bytes2 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
    }

    function logBytes3(bytes3 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
    }

    function logBytes4(bytes4 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
    }

    function logBytes5(bytes5 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
    }

    function logBytes6(bytes6 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
    }

    function logBytes7(bytes7 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
    }

    function logBytes8(bytes8 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
    }

    function logBytes9(bytes9 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
    }

    function logBytes10(bytes10 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
    }

    function logBytes11(bytes11 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
    }

    function logBytes12(bytes12 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
    }

    function logBytes13(bytes13 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
    }

    function logBytes14(bytes14 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
    }

    function logBytes15(bytes15 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
    }

    function logBytes16(bytes16 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
    }

    function logBytes17(bytes17 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
    }

    function logBytes18(bytes18 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
    }

    function logBytes19(bytes19 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
    }

    function logBytes20(bytes20 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
    }

    function logBytes21(bytes21 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
    }

    function logBytes22(bytes22 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
    }

    function logBytes23(bytes23 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
    }

    function logBytes24(bytes24 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
    }

    function logBytes25(bytes25 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
    }

    function logBytes26(bytes26 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
    }

    function logBytes27(bytes27 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
    }

    function logBytes28(bytes28 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
    }

    function logBytes29(bytes29 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
    }

    function logBytes30(bytes30 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
    }

    function logBytes31(bytes31 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
    }

    function logBytes32(bytes32 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
    }

    function log(uint256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
    }

    function log(int256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(int256)", p0));
    }

    function log(string memory p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
    }

    function log(bool p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
    }

    function log(address p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
    }

    function log(uint256 p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1));
    }

    function log(uint256 p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1));
    }

    function log(uint256 p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1));
    }

    function log(uint256 p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1));
    }

    function log(string memory p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1));
    }

    function log(string memory p0, int256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,int256)", p0, p1));
    }

    function log(string memory p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
    }

    function log(string memory p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
    }

    function log(string memory p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
    }

    function log(bool p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1));
    }

    function log(bool p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
    }

    function log(bool p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
    }

    function log(bool p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
    }

    function log(address p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1));
    }

    function log(address p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
    }

    function log(address p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
    }

    function log(address p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
    }

    function log(uint256 p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2));
    }

    function log(uint256 p0, boo

Tags:
ERC20, ERC1155, ERC165, Multisig, Mintable, Burnable, Non-Fungible, Swap, Liquidity, Staking, Upgradeable, Multi-Signature, Factory, Oracle|addr:0x2068b30a10a9d4d48c82180a627f011e5129b74f|verified:true|block:23489243|tx:0x39dae225c8d92c2558b8ddb4197dce7cecd2782e717a4f00dda22121e7ef1182|first_check:1759401522

Submitted on: 2025-10-02 12:38:42

Comments

Log in to comment.

No comments yet.