TermMaxVaultFactoryV2

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": {
    "contracts/v2/factory/TermMaxVaultFactoryV2.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
import {ITermMaxVaultV2} from "../vault/ITermMaxVaultV2.sol";
import {FactoryEventsV2} from "../events/FactoryEventsV2.sol";
import {ITermMaxVaultFactoryV2} from "./ITermMaxVaultFactoryV2.sol";
import {VaultInitialParamsV2} from "../storage/TermMaxStorageV2.sol";
import {VersionV2} from "../VersionV2.sol";

/**
 * @title The TermMax vault factory v2
 * @author Term Structure Labs
 */
contract TermMaxVaultFactoryV2 is ITermMaxVaultFactoryV2, VersionV2 {
    /**
     * @notice The implementation of TermMax Vault contract v2
     */
    address public immutable TERMMAX_VAULT_IMPLEMENTATION;

    constructor(address TERMMAX_VAULT_IMPLEMENTATION_) {
        TERMMAX_VAULT_IMPLEMENTATION = TERMMAX_VAULT_IMPLEMENTATION_;
    }

    /**
     * @inheritdoc ITermMaxVaultFactoryV2
     */
    function predictVaultAddress(
        address deployer,
        address asset,
        string memory name,
        string memory symbol,
        uint256 salt
    ) external view returns (address vault) {
        return Clones.predictDeterministicAddress(
            TERMMAX_VAULT_IMPLEMENTATION, keccak256(abi.encode(deployer, asset, name, symbol, salt))
        );
    }

    /**
     * @inheritdoc ITermMaxVaultFactoryV2
     */
    function createVault(VaultInitialParamsV2 memory initialParams, uint256 salt) public returns (address vault) {
        vault = Clones.cloneDeterministic(
            TERMMAX_VAULT_IMPLEMENTATION,
            keccak256(abi.encode(msg.sender, initialParams.asset, initialParams.name, initialParams.symbol, salt))
        );
        ITermMaxVaultV2(vault).initialize(initialParams);
        emit FactoryEventsV2.VaultCreated(vault, msg.sender, initialParams);
    }
}
"
    },
    "dependencies/@openzeppelin-contracts-5.2.0/proxy/Clones.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (proxy/Clones.sol)

pragma solidity ^0.8.20;

import {Create2} from "../utils/Create2.sol";
import {Errors} from "../utils/Errors.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[ERC-1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 */
library Clones {
    error CloneArgumentsTooLong();

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address implementation) internal returns (address instance) {
        return clone(implementation, 0);
    }

    /**
     * @dev Same as {xref-Clones-clone-address-}[clone], but with a `value` parameter to send native currency
     * to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function clone(address implementation, uint256 value) internal returns (address instance) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        assembly ("memory-safe") {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create(value, 0x09, 0x37)
        }
        if (instance == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `implementation` and `salt` multiple times will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
        return cloneDeterministic(implementation, salt, 0);
    }

    /**
     * @dev Same as {xref-Clones-cloneDeterministic-address-bytes32-}[cloneDeterministic], but with
     * a `value` parameter to send native currency to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function cloneDeterministic(
        address implementation,
        bytes32 salt,
        uint256 value
    ) internal returns (address instance) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        assembly ("memory-safe") {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create2(value, 0x09, 0x37, salt)
        }
        if (instance == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            mstore(add(ptr, 0x38), deployer)
            mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
            mstore(add(ptr, 0x14), implementation)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
            mstore(add(ptr, 0x58), salt)
            mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
            predicted := and(keccak256(add(ptr, 0x43), 0x55), 0xffffffffffffffffffffffffffffffffffffffff)
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt
    ) internal view returns (address predicted) {
        return predictDeterministicAddress(implementation, salt, address(this));
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom
     * immutable arguments. These are provided through `args` and cannot be changed after deployment. To
     * access the arguments within the implementation, use {fetchCloneArgs}.
     *
     * This function uses the create opcode, which should never revert.
     */
    function cloneWithImmutableArgs(address implementation, bytes memory args) internal returns (address instance) {
        return cloneWithImmutableArgs(implementation, args, 0);
    }

    /**
     * @dev Same as {xref-Clones-cloneWithImmutableArgs-address-bytes-}[cloneWithImmutableArgs], but with a `value`
     * parameter to send native currency to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function cloneWithImmutableArgs(
        address implementation,
        bytes memory args,
        uint256 value
    ) internal returns (address instance) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
        assembly ("memory-safe") {
            instance := create(value, add(bytecode, 0x20), mload(bytecode))
        }
        if (instance == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation` with custom
     * immutable arguments. These are provided through `args` and cannot be changed after deployment. To
     * access the arguments within the implementation, use {fetchCloneArgs}.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy the clone. Using the same
     * `implementation`, `args` and `salt` multiple times will revert, since the clones cannot be deployed twice
     * at the same address.
     */
    function cloneDeterministicWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt
    ) internal returns (address instance) {
        return cloneDeterministicWithImmutableArgs(implementation, args, salt, 0);
    }

    /**
     * @dev Same as {xref-Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-}[cloneDeterministicWithImmutableArgs],
     * but with a `value` parameter to send native currency to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function cloneDeterministicWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt,
        uint256 value
    ) internal returns (address instance) {
        bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
        return Create2.deploy(value, salt, bytecode);
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.
     */
    function predictDeterministicAddressWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
        return Create2.computeAddress(salt, keccak256(bytecode), deployer);
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.
     */
    function predictDeterministicAddressWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt
    ) internal view returns (address predicted) {
        return predictDeterministicAddressWithImmutableArgs(implementation, args, salt, address(this));
    }

    /**
     * @dev Get the immutable args attached to a clone.
     *
     * - If `instance` is a clone that was deployed using `clone` or `cloneDeterministic`, this
     *   function will return an empty array.
     * - If `instance` is a clone that was deployed using `cloneWithImmutableArgs` or
     *   `cloneDeterministicWithImmutableArgs`, this function will return the args array used at
     *   creation.
     * - If `instance` is NOT a clone deployed using this library, the behavior is undefined. This
     *   function should only be used to check addresses that are known to be clones.
     */
    function fetchCloneArgs(address instance) internal view returns (bytes memory) {
        bytes memory result = new bytes(instance.code.length - 45); // revert if length is too short
        assembly ("memory-safe") {
            extcodecopy(instance, add(result, 32), 45, mload(result))
        }
        return result;
    }

    /**
     * @dev Helper that prepares the initcode of the proxy with immutable args.
     *
     * An assembly variant of this function requires copying the `args` array, which can be efficiently done using
     * `mcopy`. Unfortunately, that opcode is not available before cancun. A pure solidity implementation using
     * abi.encodePacked is more expensive but also more portable and easier to review.
     *
     * NOTE: https://eips.ethereum.org/EIPS/eip-170[EIP-170] limits the length of the contract code to 24576 bytes.
     * With the proxy code taking 45 bytes, that limits the length of the immutable args to 24531 bytes.
     */
    function _cloneCodeWithImmutableArgs(
        address implementation,
        bytes memory args
    ) private pure returns (bytes memory) {
        if (args.length > 24531) revert CloneArgumentsTooLong();
        return
            abi.encodePacked(
                hex"61",
                uint16(args.length + 45),
                hex"3d81600a3d39f3363d3d373d3d3d363d73",
                implementation,
                hex"5af43d82803e903d91602b57fd5bf3",
                args
            );
    }
}
"
    },
    "contracts/v2/vault/ITermMaxVaultV2.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {PendingAddress, PendingUint192} from "../../v1/lib/PendingLib.sol";
import {VaultInitialParamsV2} from "../storage/TermMaxStorageV2.sol";
import {CurveCuts} from "../../v1/storage/TermMaxStorage.sol";
import {OrderV2ConfigurationParams} from "./VaultStorageV2.sol";
import {ITermMaxMarketV2} from "../ITermMaxMarketV2.sol";
import {ITermMaxOrderV2} from "../ITermMaxOrderV2.sol";

/**
 * @title ITermMaxVaultV2
 * @notice Interface for TermMax Vault V2 contract
 * @dev This interface defines the core functionality for vault operations including:
 *      - Vault initialization and configuration
 *      - APY and idle fund rate management with timelock mechanism
 *      - Pool whitelist management with pending approval system
 *      - Order creation and management (curves, configuration, liquidity)
 *      - Integration with ERC4626 pools and TermMax markets
 *
 *      The vault implements a timelock mechanism for critical parameter changes
 *      to ensure security and allow for community review of proposed changes.
 */
interface ITermMaxVaultV2 {
    // ============================================
    // INITIALIZATION
    // ============================================

    /**
     * @notice Initializes the vault with the provided parameters
     * @dev This function should only be called once during contract deployment.
     *      Sets up initial vault configuration including APY parameters, access controls,
     *      and initial pool configurations.
     * @param params The initial configuration parameters for the vault including:
     *               - minApy: minimum guaranteed APY
     *               - minIdleFundRate: minimum rate for idle funds
     *               - governance and admin addresses
     *               - initial pool configurations
     */
    function initialize(VaultInitialParamsV2 memory params) external;

    // ============================================
    // APY AND RATE QUERIES
    // ============================================

    /**
     * @notice Returns the current annual percentage yield based on accreting principal
     * @dev APY is calculated based on the vault's current performance and accruing interest.
     *      This is a dynamic value that reflects real-time vault performance.
     * @return The current APY as a uint256 value (e.g., 5% APY = 0.05e8)
     */
    function apy() external view returns (uint256);

    /**
     * @notice Returns the minimum guaranteed APY for the vault
     * @dev This represents the floor APY that the vault aims to maintain.
     *      Changes to this value require timelock approval for security.
     * @return The minimum APY as a uint64 value (e.g., 5% APY = 0.05e8)
     */
    function minApy() external view returns (uint64);

    // ============================================
    // PENDING PARAMETER QUERIES
    // ============================================

    /**
     * @notice Returns the pending minimum APY update details
     * @dev Contains the proposed new value and timing information for the pending change.
     *      Used to track timelock status and proposed changes.
     * @return PendingUint192 struct with pending minimum APY data, structure includes:
     *         - newValue: the proposed new minimum APY
     *         - validAt: the timestamp when the change becomes valid
     *         - isActive: whether there's an active pending change
     */
    function pendingMinApy() external view returns (PendingUint192 memory);

    /**
     * @notice Returns the pending pool value
     * @dev Contains the proposed new value and timing information for the pending change.
     *      Used to track timelock status and proposed changes.
     * @return PendingAddress struct with pending pool data, structure includes:
     *         - newValue: the proposed new pool address
     *         - validAt: the timestamp when the change becomes valid
     */
    function pendingPool() external view returns (PendingAddress memory);

    // ============================================
    // PARAMETER SUBMISSION (TIMELOCK INITIATION)
    // ============================================

    /**
     * @notice Submits a new minimum APY for pending approval
     * @dev Initiates a timelock period before the new minimum APY can be applied.
     *      Only authorized governance can call this function.
     * @param newMinApy The proposed new minimum APY value (e.g., 5% APY = 0.05e8)
     */
    function submitPendingMinApy(uint64 newMinApy) external;

    /**
     * @notice Submits a new pool for pending approval
     * @dev Initiates a timelock period before the new pool can be used for earning yield.
     * @param pool The address of the ERC4626 pool
     */
    function submitPendingPool(address pool) external;

    // ============================================
    // PARAMETER ACCEPTANCE (TIMELOCK COMPLETION)
    // ============================================

    /**
     * @notice Accepts and applies the pending minimum APY change
     * @dev Can only be called after the timelock period has elapsed.
     *      Finalizes the APY change and updates the active minimum APY.
     */
    function acceptPendingMinApy() external;

    /**
     * @notice
     */
    function acceptPool() external;

    /**
     *
     */
    function pool() external view returns (IERC4626);

    // ============================================
    // PARAMETER REVOCATION (TIMELOCK CANCELLATION)
    // ============================================

    /**
     * @notice Revokes the pending minimum APY change
     * @dev Cancels the pending change and resets the pending state.
     *      Allows governance to cancel proposed changes before they take effect.
     */
    function revokePendingMinApy() external;

    /**
     * @notice Revokes a pending pool change
     * @dev Cancels the pending change and resets the pending state.
     *      Allows governance to abort pool changes before they take effect.
     */
    function revokePendingPool() external;

    // ============================================
    // ORDER MANAGEMENT
    // ============================================

    /**
     * @notice Update the configuration for multiple orders
     * @param orders The list of order addresses to update
     * @param orderConfigs The new configuration parameters for each order, containing:
     *                    - virtualXtReserve: The new virtual XT reserve for the order
     *                    - maxXtReserve: The new maximum XT reserve for the order
     *                    - removingLiquidity: The amount of liquidity to remove from the order
     *                    - curveCuts: The new curve cuts for the order
     */
    function updateOrdersConfiguration(address[] memory orders, OrderV2ConfigurationParams[] memory orderConfigs)
        external;

    /**
     * @notice Remove the liquidity from multiple orders
     * @param orders The list of order addresses to update
     * @param removedLiquidities The amount of liquidity to remove from each order
     */
    function removeLiquidityFromOrders(address[] memory orders, uint256[] memory removedLiquidities) external;

    /**
     * @notice Creates a new order with the specified parameters
     * @dev Deploys a new TermMax order contract with the given configuration.
     *      The order will be associated with the specified market and pool.
     * @param market The TermMax market address that the order will operate in
     * @param params The configuration parameters for the new order
     * @return order The address of the newly created TermMax order contract
     */
    function createOrder(ITermMaxMarketV2 market, OrderV2ConfigurationParams memory params)
        external
        returns (ITermMaxOrderV2 order);
}
"
    },
    "contracts/v2/events/FactoryEventsV2.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {MarketInitialParams} from "../../v1/storage/TermMaxStorage.sol";
import {VaultInitialParamsV2} from "../storage/TermMaxStorageV2.sol";

/**
 * @title Factory Events Interface V2
 * @notice Events emitted by the TermMax factory contracts
 */
interface FactoryEventsV2 {
    /**
     * @notice Emitted when a new market is created
     * @param market The address of the newly created market
     * @param collateral The address of the collateral token
     * @param debtToken The debt token interface
     * @param params The initial parameters for the market
     */
    event MarketCreated(
        address indexed market, address indexed collateral, IERC20 indexed debtToken, MarketInitialParams params
    );

    /**
     * @notice Emitted when a new vault is created
     * @param vault The address of the newly created vault
     * @param creator The address of the vault creator
     * @param initialParams The initial parameters used to configure the vault
     */
    event VaultCreated(address indexed vault, address indexed creator, VaultInitialParamsV2 initialParams);

    /**
     * @notice Emitted when a new price feed is created
     * @param priceFeed The address of the newly created price feed contract
     */
    event PriceFeedCreated(address indexed priceFeed);

    // Events from TermMax4626Factory
    /**
     * @notice Emitted when TermMax4626Factory is initialized
     * @param aavePool The Aave pool address
     * @param aaveReferralCode The Aave referral code
     * @param stableERC4626For4626Implementation The stable ERC4626For4626 implementation address
     * @param stableERC4626ForAaveImplementation The stable ERC4626ForAave implementation address
     * @param variableERC4626ForAaveImplementation The variable ERC4626ForAave implementation address
     */
    event TermMax4626FactoryInitialized(
        address indexed aavePool,
        uint16 aaveReferralCode,
        address stableERC4626For4626Implementation,
        address stableERC4626ForAaveImplementation,
        address variableERC4626ForAaveImplementation
    );

    /**
     * @notice Emitted when a new StableERC4626For4626 is created
     * @param caller The address that called the creation function
     * @param stableERC4626For4626 The address of the created StableERC4626For4626
     */
    event StableERC4626For4626Created(address indexed caller, address indexed stableERC4626For4626);

    /**
     * @notice Emitted when a new StableERC4626ForAave is created
     * @param caller The address that called the creation function
     * @param stableERC4626ForAave The address of the created StableERC4626ForAave
     */
    event StableERC4626ForAaveCreated(address indexed caller, address indexed stableERC4626ForAave);

    /**
     * @notice Emitted when a new VariableERC4626ForAave is created
     * @param caller The address that called the creation function
     * @param variableERC4626ForAave The address of the created VariableERC4626ForAave
     */
    event VariableERC4626ForAaveCreated(address indexed caller, address indexed variableERC4626ForAave);
}
"
    },
    "contracts/v2/factory/ITermMaxVaultFactoryV2.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {VaultInitialParamsV2} from "../storage/TermMaxStorageV2.sol";

/**
 * @title TermMax Vault Factory Interface v2
 * @author Term Structure Labs
 * @notice Interface for creating new TermMax vaults
 */
interface ITermMaxVaultFactoryV2 {
    /**
     * @notice The implementation of TermMax Vault contract
     */
    function TERMMAX_VAULT_IMPLEMENTATION() external view returns (address);

    /**
     * @notice Predict the address of a new TermMax vault
     * @param deployer The address of the vault deployer
     * @param asset The address of the asset
     * @param name The name of the vault
     * @param symbol The symbol of the vault
     * @param salt The salt used to create the vault
     * @return vault The predicted address of the vault
     */
    function predictVaultAddress(
        address deployer,
        address asset,
        string memory name,
        string memory symbol,
        uint256 salt
    ) external view returns (address vault);

    /**
     * @notice Creates a new TermMax vault with the specified parameters
     * @param initialParams Initial parameters for vault configuration
     * @param salt The salt used to create the vault
     * @return address The address of the newly created vault
     */
    function createVault(VaultInitialParamsV2 memory initialParams, uint256 salt) external returns (address);
}
"
    },
    "contracts/v2/storage/TermMaxStorageV2.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {IGearingToken} from "../../v1/tokens/IGearingToken.sol";
import {OrderConfig} from "../../v1/storage/TermMaxStorage.sol";

struct VaultInitialParamsV2 {
    address admin;
    address curator;
    address guardian;
    uint256 timelock;
    IERC20 asset;
    /// @notice The third-party pool to earn floating interest by idle funds
    IERC4626 pool;
    uint256 maxCapacity;
    string name;
    string symbol;
    /// @notice The performance fee rate in base units, e.g. 20% = 0.2e8
    uint64 performanceFeeRate;
    /// @notice The minimum APY in base units, e.g. 2% = 0.02e8
    uint64 minApy;
}

struct OrderInitialParams {
    address maker;
    IERC20 ft;
    IERC20 xt;
    IERC20 debtToken;
    IGearingToken gt;
    uint256 virtualXtReserve;
    IERC4626 pool;
    uint64 maturity;
    OrderConfig orderConfig;
}
"
    },
    "contracts/v2/VersionV2.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

abstract contract VersionV2 {
    // Function to get the version number
    function getVersion() public pure virtual returns (string memory) {
        return "2.0.0";
    }
}
"
    },
    "dependencies/@openzeppelin-contracts-5.2.0/utils/Create2.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Create2.sol)

pragma solidity ^0.8.20;

import {Errors} from "./Errors.sol";

/**
 * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
 * `CREATE2` can be used to compute in advance the address where a smart
 * contract will be deployed, which allows for interesting new mechanisms known
 * as 'counterfactual interactions'.
 *
 * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
 * information.
 */
library Create2 {
    /**
     * @dev There's no code to deploy.
     */
    error Create2EmptyBytecode();

    /**
     * @dev Deploys a contract using `CREATE2`. The address where the contract
     * will be deployed can be known in advance via {computeAddress}.
     *
     * The bytecode for a contract can be obtained from Solidity with
     * `type(contractName).creationCode`.
     *
     * Requirements:
     *
     * - `bytecode` must not be empty.
     * - `salt` must have not been used for `bytecode` already.
     * - the factory must have a balance of at least `amount`.
     * - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
     */
    function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
        if (address(this).balance < amount) {
            revert Errors.InsufficientBalance(address(this).balance, amount);
        }
        if (bytecode.length == 0) {
            revert Create2EmptyBytecode();
        }
        assembly ("memory-safe") {
            addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
            // if no address was created, and returndata is not empty, bubble revert
            if and(iszero(addr), not(iszero(returndatasize()))) {
                let p := mload(0x40)
                returndatacopy(p, 0, returndatasize())
                revert(p, returndatasize())
            }
        }
        if (addr == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
     * `bytecodeHash` or `salt` will result in a new destination address.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
        return computeAddress(salt, bytecodeHash, address(this));
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
     * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
        assembly ("memory-safe") {
            let ptr := mload(0x40) // Get free memory pointer

            // |                   | ↓ ptr ...  ↓ ptr + 0x0B (start) ...  ↓ ptr + 0x20 ...  ↓ ptr + 0x40 ...   |
            // |-------------------|---------------------------------------------------------------------------|
            // | bytecodeHash      |                                                        CCCCCCCCCCCCC...CC |
            // | salt              |                                      BBBBBBBBBBBBB...BB                   |
            // | deployer          | 000000...0000AAAAAAAAAAAAAAAAAAA...AA                                     |
            // | 0xFF              |            FF                                                             |
            // |-------------------|---------------------------------------------------------------------------|
            // | memory            | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
            // | keccak(start, 85) |            ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |

            mstore(add(ptr, 0x40), bytecodeHash)
            mstore(add(ptr, 0x20), salt)
            mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
            let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
            mstore8(start, 0xff)
            addr := and(keccak256(start, 85), 0xffffffffffffffffffffffffffffffffffffffff)
        }
    }
}
"
    },
    "dependencies/@openzeppelin-contracts-5.2.0/utils/Errors.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of common custom errors used in multiple contracts
 *
 * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
 * It is recommended to avoid relying on the error API for critical functionality.
 *
 * _Available since v5.1._
 */
library Errors {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error InsufficientBalance(uint256 balance, uint256 needed);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedCall();

    /**
     * @dev The deployment failed.
     */
    error FailedDeployment();

    /**
     * @dev A necessary precompile is missing.
     */
    error MissingPrecompile(address);
}
"
    },
    "dependencies/@openzeppelin-contracts-5.2.0/interfaces/IERC4626.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC4626.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../token/ERC20/IERC20.sol";
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";

/**
 * @dev Interface of the ERC-4626 "Tokenized Vault Standard", as defined in
 * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
 */
interface IERC4626 is IERC20, IERC20Metadata {
    event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);

    event Withdraw(
        address indexed sender,
        address indexed receiver,
        address indexed owner,
        uint256 assets,
        uint256 shares
    );

    /**
     * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
     *
     * - MUST be an ERC-20 token contract.
     * - MUST NOT revert.
     */
    function asset() external view returns (address assetTokenAddress);

    /**
     * @dev Returns the total amount of the underlying asset that is “managed” by Vault.
     *
     * - SHOULD include any compounding that occurs from yield.
     * - MUST be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT revert.
     */
    function totalAssets() external view returns (uint256 totalManagedAssets);

    /**
     * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
     * scenario where all the conditions are met.
     *
     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT show any variations depending on the caller.
     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
     * - MUST NOT revert.
     *
     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
     * from.
     */
    function convertToShares(uint256 assets) external view returns (uint256 shares);

    /**
     * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
     * scenario where all the conditions are met.
     *
     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT show any variations depending on the caller.
     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
     * - MUST NOT revert.
     *
     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
     * from.
     */
    function convertToAssets(uint256 shares) external view returns (uint256 assets);

    /**
     * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
     * through a deposit call.
     *
     * - MUST return a limited value if receiver is subject to some deposit limit.
     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
     * - MUST NOT revert.
     */
    function maxDeposit(address receiver) external view returns (uint256 maxAssets);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
     * current on-chain conditions.
     *
     * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
     *   call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
     *   in the same transaction.
     * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
     *   deposit would be accepted, regardless if the user has enough tokens approved, etc.
     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by depositing.
     */
    function previewDeposit(uint256 assets) external view returns (uint256 shares);

    /**
     * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
     *
     * - MUST emit the Deposit event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
     *   deposit execution, and are accounted for during deposit.
     * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
     *   approving enough underlying tokens to the Vault contract, etc).
     *
     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
     */
    function deposit(uint256 assets, address receiver) external returns (uint256 shares);

    /**
     * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
     * - MUST return a limited value if receiver is subject to some mint limit.
     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
     * - MUST NOT revert.
     */
    function maxMint(address receiver) external view returns (uint256 maxShares);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
     * current on-chain conditions.
     *
     * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
     *   in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
     *   same transaction.
     * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
     *   would be accepted, regardless if the user has enough tokens approved, etc.
     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by minting.
     */
    function previewMint(uint256 shares) external view returns (uint256 assets);

    /**
     * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
     *
     * - MUST emit the Deposit event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
     *   execution, and are accounted for during mint.
     * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
     *   approving enough underlying tokens to the Vault contract, etc).
     *
     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
     */
    function mint(uint256 shares, address receiver) external returns (uint256 assets);

    /**
     * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
     * Vault, through a withdraw call.
     *
     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
     * - MUST NOT revert.
     */
    function maxWithdraw(address owner) external view returns (uint256 maxAssets);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
     * given current on-chain conditions.
     *
     * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
     *   call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
     *   called
     *   in the same transaction.
     * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
     *   the withdrawal would be accepted, regardless if the user has enough shares, etc.
     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by depositing.
     */
    function previewWithdraw(uint256 assets) external view returns (uint256 shares);

    /**
     * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
     *
     * - MUST emit the Withdraw event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
     *   withdraw execution, and are accounted for during withdraw.
     * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
     *   not having enough shares, etc).
     *
     * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
     * Those methods should be performed separately.
     */
    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);

    /**
     * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
     * through a redeem call.
     *
     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
     * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
     * - MUST NOT revert.
     */
    function maxRedeem(address owner) external view returns (uint256 maxShares);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
     * given current on-chain conditions.
     *
     * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
     *   in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
     *   same transaction.
     * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
     *   redemption would be accepted, regardless if the user has enough shares, etc.
     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by redeeming.
     */
    function previewRedeem(uint256 shares) external view returns (uint256 assets);

    /**
     * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
     *
     * - MUST emit the Withdraw event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
     *   redeem execution, and are accounted for during redeem.
     * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
     *   not having enough shares, etc).
     *
     * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
     * Those methods should be performed separately.
     */
    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}
"
    },
    "contracts/v1/lib/PendingLib.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

struct PendingUint192 {
    /// @notice The pending value to set.
    uint192 value;
    /// @notice The timestamp at which the pending value becomes valid.
    uint64 validAt;
}

struct PendingAddress {
    /// @notice The pending value to set.
    address value;
    /// @notice The timestamp at which the pending value becomes valid.
    uint64 validAt;
}

/// @title PendingLib
/// @author Morpho Labs
/// @custom:contact security@morpho.org
/// @notice Library to manage pending values and their validity timestamp.
library PendingLib {
    /// @dev Updates `pending`'s value to `newValue` and its corresponding `validAt` timestamp.
    /// @dev Assumes `timelock` <= `MAX_TIMELOCK`.
    function update(PendingUint192 storage pending, uint184 newValue, uint256 timelock) internal {
        pending.value = newValue;
        // Safe "unchecked" cast because timelock <= MAX_TIMELOCK.
        pending.validAt = uint64(block.timestamp + timelock);
    }

    /// @dev Updates `pending`'s value to `newValue` and its corresponding `validAt` timestamp.
    /// @dev Assumes `timelock` <= `MAX_TIMELOCK`.
    function update(PendingAddress storage pending, address newValue, uint256 timelock) internal {
        pending.value = newValue;
        // Safe "unchecked" cast because timelock <= MAX_TIMELOCK.
        pending.validAt = uint64(block.timestamp + timelock);
    }
}
"
    },
    "contracts/v1/storage/TermMaxStorage.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IOracle} from "../oracle/IOracle.sol";
import {ISwapCallback} from "../ISwapCallback.sol";

/**
 * @title The data struct of token pair
 * @author Term Structure Labs
 */
struct CurveCut {
    uint256 xtReserve;
    uint256 liqSquare;
    int256 offset;
}

struct FeeConfig {
    /// @notice The lending fee ratio taker
    ///         i.e. 0.01e8 means 1%
    uint32 lendTakerFeeRatio;
    /// @notice The lending fee ratio for maker
    ///         i.e. 0.01e8 means 1%
    uint32 lendMakerFeeRatio;
    /// @notice The borrowing fee ratio for taker
    ///         i.e. 0.01e8 means 1%
    uint32 borrowTakerFeeRatio;
    /// @notice The borrowing fee ratio for maker
    ///         i.e. 0.01e8 means 1%
    uint32 borrowMakerFeeRatio;
    /// @notice The fee ratio when minting GT tokens by collateral
    ///         i.e. 0.01e8 means 1%
    uint32 mintGtFeeRatio;
    /// @notice The fee ref when minting GT tokens by collateral
    ///         i.e. 0.01e8 means 1%
    uint32 mintGtFeeRef;
}

struct CurveCuts {
    /// @notice The curve cuts of the market to lend
    CurveCut[] lendCurveCuts;
    /// @notice The curve cuts of the market to borrow
    CurveCut[] borrowCurveCuts;
}

struct MarketConfig {
    /// @notice The treasurer's address, which will receive protocol fee
    address treasurer;
    /// @notice The unix time of maturity date
    uint64 maturity;
    /// @notice The fee ratio when tradings with the market and orders
    FeeConfig feeConfig;
}

struct LoanConfig {
    /// @notice The oracle aggregator
    IOracle oracle;
    /// @notice The debt liquidation threshold
    ///         If the loan to collateral is greater than or equal to this value,
    ///         it will be liquidated
    ///         i.e. 0.9e8 means debt value is the 90% of collateral value
    uint32 liquidationLtv;
    /// @notice Maximum loan to collateral when borrowing
    ///         i.e. 0.85e8 means debt value is the 85% of collateral value
    uint32 maxLtv;
    /// @notice The flag to indicate debt is liquidatable or not
    /// @dev    If liquidatable is false, the collateral can only be delivered after maturity
    bool liquidatable;
}

/// @notice Data of Gearing Token's configuturation
struct GtConfig {
    /// @notice The address of collateral token
    address collateral;
    /// @notice The debtToken(debt) token
    IERC20Metadata debtToken;
    /// @notice The bond token
    IERC20 ft;
    /// @notice The treasurer's address, which will receive protocol reward while liquidation
    address treasurer;
    /// @notice The unix time of maturity date
    uint64 maturity;
    /// @notice The configuration of oracle, ltv and liquidation
    LoanConfig loanConfig;
}

struct OrderConfig {
    CurveCuts curveCuts;
    uint256 gtId;
    uint256 maxXtReserve;
    ISwapCallback swapTrigger;
    FeeConfig feeConfig;
}

struct MarketInitialParams {
    /// @notice The address of collateral token
    address collateral;
    /// @notice The debtToken(debt) token
    IERC20Metadata debtToken;
    /// @notice The admin address
    address admin;
    /// @notice The implementation of TermMax Gearing Token contract
    address gtImplementation;
    /// @notice The configuration of market
    MarketConfig marketConfig;
    /// @notice The configuration of loan
    LoanConfig loanConfig;
    /// @notice The encoded parameters to initialize GT implementation contract
    bytes gtInitalParams;
    string tokenName;
    string tokenSymbol;
}

struct VaultInitialParams {
    address admin;
    address curator;
    uint256 timelock;
    IERC20 asset;
    uint256 maxCapacity;
    string name;
    string symbol;
    uint64 performanceFeeRate;
}
"
    },
    "contracts/v2/vault/VaultStorageV2.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {PendingAddress, PendingUint192} from "../../v1/lib/PendingLib.sol";
import {CurveCuts} from "../../v1/storage/TermMaxStorage.sol";

struct OrderV2ConfigurationParams {
    uint256 originalVirtualXtReserve;
    uint256 virtualXtReserve;
    uint256 maxXtReserve;
    CurveCuts curveCuts;
}

contract VaultStorageV2 {
    // State variables
    address internal _guardian;
    address internal _curator;

    mapping(address => bool) internal _marketWhitelist;
    mapping(address => PendingUint192) internal _pendingMarkets;

    PendingUint192 internal _pendingTimelock;
    PendingUint192 internal _pendingPerformanceFeeRate;
    PendingAddress internal _pendingGuardian;
    PendingUint192 internal _pendingMinApy;
    PendingAddress internal _pendingPool;

    uint256 internal _timelock;
    uint256 internal _maxCapacity;

    /// @dev The total ft in the vault
    uint256 internal _totalFt;
    /// @notice The locked ft = accretingPrincipal + performanceFee;
    uint256 internal _accretingPrincipal;
    /// @notice The performance fee is paid to the curators
    uint256 internal _performanceFee;
    /// @notice Annualize the interest income
    uint256 internal _annualizedInterest;
    /// @notice The third-party pool to earn floating interest by idle funds
    IERC4626 internal _pool;

    /// @notice A mapping from collateral address to bad debt
    mapping(address => uint256) internal _badDebtMapping;

    /// @notice A mapping from order address to its maturity
    mapping(address => uint256) internal _orderMaturityMapping;

    /// @notice A one-way linked list presented using a mapping structure, recorded in order according to matiruty
    /// @notice The key is the maturity, and the value is the next maturity
    /// Etc. day 0 => day 1 => day 2 => day 3 => ...
    mapping(uint64 => uint64) internal _maturityMapping;
    /// @notice A mapping from maturity to its annualized interest
    mapping(uint64 => uint256) internal _maturityToInterest;

    /// @notice The performance fee rate, in basis points (1e8 = 100%)
    uint64 internal _performanceFeeRate;

    /// @notice The last time the interest was accurately calculated
    uint64 internal _lastUpdateTime;

    /// @notice The minimum APY for the vault to be active
    uint64 internal _minApy;
}
"
    },
    "contracts/v2/ITermMaxMarketV2.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {OrderConfig} from "../v1/storage/TermMaxStorage.sol";
import {ITermMaxOrder} from "../v1/ITermMaxOrder.sol";
import {OrderInitialParams} from "./storage/TermMaxStorageV2.sol";

/**
 * @title TermMax Market V2 interface
 * @author Term Structure Labs
 * @notice Interface for TermMax V2 markets with enhanced functionality over V1
 * @dev Extends the base market functionality with additional features for better user experience
 */
interface ITermMaxMarketV2 {
    /**
     * @notice Returns the human-readable name of the market
     * @dev Used for identification and display purposes in V2 markets
     * @return The name string of the market (e.g., "Termmax Market:USDC-24-Dec")
     */
    function name() external view returns (string memory);

    /**
     * @notice Burns FT and XT tokens on behalf of an owner to redeem underlying tokens
     * @dev V2 enhancement allowing third-party burning with proper authorization
     * @param owner The address that owns the tokens to be burned
     * @param recipient The address that will receive the redeemed underlying tokens
     * @param debtTokenAmt The amount of debt tokens (FT/XT pairs) to burn
     */
    function burn(address owner, address recipient, uint256 debtTokenAmt) external;

    /**
     * @notice Creates a leveraged position using XT tokens from a specified owner
     * @dev V2 enhancement allowing leverage creation on behalf of another address
     * @param xtOwner The address that owns the XT tokens to be used for leverage
     * @param recipient The address that will receive the generated GT (Gearing Token)
     * @param xtAmt The amount of XT tokens to use for creating the leveraged position
     * @param callbackData Encoded data passed to the flash loan callback for collateral handling
     * @return gtId The ID of the newly minted Gearing Token representing the leveraged position
     */
    function leverageByXt(address xtOwner, address recipient, uint128 xtAmt, bytes calldata callbackData)
        external
        returns (uint256 gtId);

    /**
     * @notice Redeems FT tokens on behalf of an owner after market maturity
     * @dev V2 enhancement allowing third-party redemption with proper authorization
     * @param ftOwner The address that owns the FT tokens to be redeemed
     * @param recipient The address that will receive the redeemed assets
     * @param ftAmount The amount of FT tokens to redeem
     * @return debtTokenAmt The amount of underlying debt tokens received
     * @return deliveryData Encoded data containing collateral delivery information
     */
    function redeem(address ftOwner, address recipient, uint256 ftAmount) external returns (uint256, bytes memory);

    /**
     * @notice Creates a new TermMax order with default parameters
     * @dev Uses CREATE to deploy the order contract at a non-deterministic address
     */
    function createOrder(OrderInitialParams memory params) external returns (ITermMaxOrder order);

    /**
     * @notice Creates a new TermMax order with a unique salt for address uniqueness
     * @dev Uses CREATE2 to deploy the order contract at a deterministic address based on the salt
     */
    function createOrder(OrderInitialParams memory params, uint256 salt) external returns (ITermMaxOrder order);

    /**
     * @notice Predict the address of a TermMax order that would be created with given parameters and salt
     * @dev Computes the address using CREATE2 without actually deploying the contract
     */
    function predictOrderAddress(OrderInitialParams memory params, uint256 salt)
        external
        view
        returns (address orderAddress);
}
"
    },
    "contracts/v2/ITermMaxOrderV2.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IERC20} from "../v1/tokens/IMintableERC20.sol";
import {OrderInitialParams} from "./storage/TermMaxStorageV2.sol";
import {ISwapCallback} from "../v1/ISwapCallback.sol";
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {CurveCuts} from "../v1/storage/TermMaxStorage.sol";

/**
 * @title TermMax Order interface v2
 * @author Term Structure Labs
 * @notice The V2 Order use vitual xt reserve to present the current price,
 *        which is different from V1 Order that uses real xt reserve.
 *        You have to set the virtual xt reserve to set an initialize price.
 */
interface ITermMaxOrderV2 {
    /// @notice Initialize the token and configuration of the order (V2 version)
    function initialize(OrderInitialParams memory params) external;

    // =============================================================================
    // V2-SPECIFIC VIEW FUNCTIONS
    // =============================================================================

    /// @notice Get the pool address set for the order
    function pool() external view returns (IERC4626);

    /// @notice Get the virtual XT reserve, which is used to present the current price
    function virtualXtReserve() external view returns (uint256);

    /// @notice Get real reserves including assets in pool
    function getRealReserves() external view returns (uint256 ftReserve, uint256 xtReserve);

    // =============================================================================
    // V2-SPECIFIC ADMIN FUNCTIONS
    // =============================================================================

    /// @notice Set curve and price configuration
    /// @param originalVirtualXtReserve The original virtual reserve of XT token, which is used to prevent price manipulation
    /// @param virtualXtReserve The virtual reserve of XT token, which presents the current price
    /// @param maxXtReserve The maximum reserve of XT token
    /// @param newCurveCuts The new curve configuration parameters
    function setCurveAndPrice(
        uint256 originalVirtualXtReserve,
        uint256 virtualXtReserve,
        uint256 maxXtReserve,
        CurveCuts memory newCurveCuts
    ) external;

    /// @notice Set general configuration parameters
    /// @param gtId The ID of the Gearing Token, which is used to borrow tokens
    /// @param swapTrigger The callback contract to trigger swaps
    function setGeneralConfig(uint256 gtId, ISwapCallback swapTrigger) external;

    /// @notice Set the staking pool
    /// @param newPool The new staking pool to be set, the address(0) can be used to unset the pool
    function setPool(IERC4626 newPool) external;

    // =============================================================================
    // V2-SPECIFIC LIQUIDITY MANAGEMENT FUNCTIONS
    // =============================================================================

    /// @notice Add liquidity to the order
    /// @notice If you want to add liquidity by ft or xt, please transfer them to the order directly.
    /// @param asset The asset to be added as liquidity, debt token or pool shares
    /// @param amount The amount of the asset to be added
    function addLiquidity(IERC20 asset, uint256 amount) external;

    /// @notice Remove liquidity from the order
    /// @param asset The asset to be removed as liquidity, debt token or pool shares
    /// @param amount The amount of the asset to be removed
    /// @param recipient The address to receive the removed liquidity
    function removeLiquidity(IERC20 asset, uint256 amount, address recipient) external;

    /// @notice Redeem all assets and close the order, must be called after the maturity + liquidation period
    /// @param recipient The address to receive the redeemed assets
    /// @return badDebt The amount of bad debt incurred during the redemption
    /// @return deliveryData Additional data returned from the redemption process
    /// @dev You have to withdraw the delivery collateral manually if the asset is a pool share.
    /// @dev This function will close the order and transfer all assets to the recipient.
    function redeemAll(address recipient) external returns (uint256 badDebt, bytes memory deliveryData);

    /// @notice Withdraw all assets before maturity, only callable by the owner
    /// @param recipient The address to receive the withdrawn assets
    /// @return debtTokenAmount The amount of debt tokens withdrawn
    /// @return ftAmount The amount of FT tokens withdrawn
    /// @return xtAmount The amount of XT tokens withdrawn
    function withdrawAllAssetsBeforeMaturity(address recipient)
        external
        returns (uint256 debtTokenAmount, uint256 ftAmount, uint256 xtAmount);

    /// @notice Borrow tokens from the order
    /// @param recipient The address to receive the borrowed tokens
    /// @param amount The amount of tokens to be borrowed
    function borrowToken(address recipient, uint256 amount) external;
}
"
    },
    "dependencies/@openzeppelin-contracts-5.2.0/token/ERC20/IERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

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

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

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

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

    /**
     * @dev Moves a `value` 

Tags:
ERC20, ERC721, ERC165, Multisig, Mintable, Burnable, Pausable, Non-Fungible, Swap, Liquidity, Staking, Yield, Voting, Timelock, Upgradeable, Multi-Signature, Factory, Oracle|addr:0xb4314cbe0f5bc5be6e247892ac4543dba223a13d|verified:true|block:23479701|tx:0x5c795b09509da54e21e4cfac547dc1354ad8acec146861fc621e3d0c17b2964e|first_check:1759318525

Submitted on: 2025-10-01 13:35:25

Comments

Log in to comment.

No comments yet.