AccessManagerV2

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

import "../../v1/access/AccessManager.sol";
import {IOracleV2} from "../oracle/IOracleV2.sol";
import {ITermMaxVaultV2, OrderV2ConfigurationParams, CurveCuts} from "../vault/ITermMaxVaultV2.sol";
import {IWhitelistManager} from "./IWhitelistManager.sol";
import {VersionV2} from "../VersionV2.sol";

/**
 * @title TermMax Access Manager V2
 * @author Term Structure Labs
 * @notice Extended access manager for TermMax V2 protocol with additional oracle and batch operations
 * @dev Inherits from AccessManager V1 and adds V2-specific functionality for managing oracles and batch operations
 */
contract AccessManagerV2 is AccessManager, VersionV2 {
    error CannotRenounceRole();

    /// @notice Role to manage whitelist
    bytes32 public constant WHITELIST_ROLE = keccak256("WHITELIST_ROLE");

    /// @notice Role to upgrade contracts
    bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");

    function upgradeSubContract(UUPSUpgradeable proxy, address newImplementation, bytes memory data)
        external
        override
        onlyRole(UPGRADER_ROLE)
    {
        proxy.upgradeToAndCall(newImplementation, data);
    }

    function batchSetWhitelist(
        IWhitelistManager whitelistManager,
        address[] calldata contractAddresses,
        IWhitelistManager.ContractModule module,
        bool approved
    ) external onlyRole(WHITELIST_ROLE) {
        whitelistManager.batchSetWhitelist(contractAddresses, module, approved);
    }

    /**
     * @notice Batch pause/unpause multiple entities in a single transaction
     * @dev Allows efficient management of multiple pausable contracts simultaneously
     * @param entities Array of IPausable contracts to pause/unpause
     * @param state True to unpause entities, false to pause them
     * @custom:access Requires PAUSER_ROLE
     * @custom:gas-optimization Uses a simple loop for batch operations
     */
    function batchSetSwitch(IPausable[] calldata entities, bool state) external onlyRole(PAUSER_ROLE) {
        if (state) {
            for (uint256 i = 0; i < entities.length; ++i) {
                entities[i].unpause();
            }
        } else {
            for (uint256 i = 0; i < entities.length; ++i) {
                entities[i].pause();
            }
        }
    }

    /**
     * @notice Submit a pending oracle configuration for a specific asset
     * @dev Allows oracle managers to propose new oracle configurations that can be activated later
     * @param aggregator The oracle aggregator contract to submit the pending oracle to
     * @param asset The asset address for which the oracle is being configured
     * @param oracle The oracle configuration structure containing price feed details
     * @custom:access Requires ORACLE_ROLE
     * @custom:security Oracle updates go through a pending mechanism for security
     */
    function submitPendingOracle(IOracleV2 aggregator, address asset, IOracleV2.Oracle memory oracle)
        external
        onlyRole(ORACLE_ROLE)
    {
        aggregator.submitPendingOracle(asset, oracle);
    }

    /**
     * @notice Revoke a pending oracle configuration for a specific asset
     * @dev Allows oracle managers to cancel pending oracle updates before they are activated
     * @param aggregator The oracle aggregator contract to revoke the pending oracle from
     * @param asset The asset address for which the pending oracle should be revoked
     * @custom:access Requires ORACLE_ROLE
     * @custom:security Provides a way to cancel erroneous oracle submissions
     */
    function revokePendingOracle(IOracleV2 aggregator, address asset) external onlyRole(ORACLE_ROLE) {
        aggregator.revokePendingOracle(asset);
    }

    /**
     * @notice Revoke a pending minimum APY change for the vault
     * @param vault The TermMax vault contract to update
     * @custom:access Requires VAULT_ROLE
     * @custom:security Allows governance to cancel proposed changes before they take effect
     */
    function revokePendingMinApy(ITermMaxVaultV2 vault) external onlyRole(VAULT_ROLE) {
        vault.revokePendingMinApy();
    }

    /**
     * @notice Revoke a pending pool change for the vault
     * @param vault The TermMax vault contract to update
     * @custom:access Requires VAULT_ROLE
     * @custom:security Allows governance to abort pool changes before they take effect
     */
    function revokePendingPool(ITermMaxVaultV2 vault) external onlyRole(VAULT_ROLE) {
        vault.revokePendingPool();
    }

    /// @notice Forbid renouncing roles
    function renounceRole(bytes32 role, address callerConfirmation) public override {
        revert CannotRenounceRole();
    }
}
"
    },
    "contracts/v1/access/AccessManager.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {ITermMaxMarket} from "../ITermMaxMarket.sol";
import {ITermMaxFactory} from "../factory/ITermMaxFactory.sol";
import {ITermMaxRouter} from "../router/ITermMaxRouter.sol";
import {ITermMaxOrder} from "../ITermMaxOrder.sol";
import {IOracle} from "../oracle/IOracle.sol";
import {ITermMaxVault} from "../vault/ITermMaxVault.sol";
import {MarketConfig, FeeConfig, MarketInitialParams} from "../storage/TermMaxStorage.sol";

interface IOwnable {
    function transferOwnership(address newOwner) external;

    function acceptOwnership() external;
}

interface IPausable {
    function pause() external;

    function unpause() external;
}

/**
 * @title TermMax Access Manager
 * @author Term Structure Labs
 */
contract AccessManager is AccessControlUpgradeable, UUPSUpgradeable {
    error CannotRevokeDefaultAdminRole();

    /// @notice Role to manage switch
    bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
    /// @notice Role to manage configuration items
    bytes32 public constant CONFIGURATOR_ROLE = keccak256("CONFIGURATOR_ROLE");
    /// @notice Role to manage vault
    bytes32 public constant VAULT_ROLE = keccak256("VAULT_ROLE");
    /// @notice Role to manage oracle
    bytes32 public constant ORACLE_ROLE = keccak256("ORACLE_ROLE");
    /// @notice Role to manage market
    bytes32 public constant MARKET_ROLE = keccak256("MARKET_ROLE");

    function initialize(address admin) public initializer {
        __UUPSUpgradeable_init();
        __AccessControl_init();
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
    }

    /// @notice Set GT implementation to the factory
    function setGtImplement(ITermMaxFactory factory, string memory gtImplementName, address gtImplement)
        external
        onlyRole(MARKET_ROLE)
    {
        factory.setGtImplement(gtImplementName, gtImplement);
    }

    /// @notice Deploy a new market
    function createMarket(
        ITermMaxFactory factory,
        bytes32 gtKey,
        MarketInitialParams calldata deployParams,
        uint256 salt
    ) external onlyRole(MARKET_ROLE) returns (address market) {
        market = factory.createMarket(gtKey, deployParams, salt);
    }

    /// @notice Transfer ownable contract's ownership
    function transferOwnership(IOwnable entity, address to) external onlyRole(DEFAULT_ADMIN_ROLE) {
        entity.transferOwnership(to);
    }

    function acceptOwnership(IOwnable entity) external onlyRole(DEFAULT_ADMIN_ROLE) {
        entity.acceptOwnership();
    }

    /// @notice Upgrade the target contract using UUPS
    function upgradeSubContract(UUPSUpgradeable proxy, address newImplementation, bytes memory data)
        external
        virtual
        onlyRole(DEFAULT_ADMIN_ROLE)
    {
        proxy.upgradeToAndCall(newImplementation, data);
    }

    /// @notice Set the adapter whitelist for router
    function setAdapterWhitelist(ITermMaxRouter router, address adapter, bool isWhitelist)
        external
        onlyRole(MARKET_ROLE)
    {
        router.setAdapterWhitelist(adapter, isWhitelist);
    }

    function submitPendingOracle(IOracle aggregator, address asset, IOracle.Oracle memory oracle)
        external
        onlyRole(ORACLE_ROLE)
    {
        aggregator.submitPendingOracle(asset, oracle);
    }

    function acceptPendingOracle(IOracle aggregator, address asset) external onlyRole(ORACLE_ROLE) {
        aggregator.acceptPendingOracle(asset);
    }

    /// @notice Update the market configuration
    function updateMarketConfig(ITermMaxMarket market, MarketConfig calldata newConfig)
        external
        onlyRole(CONFIGURATOR_ROLE)
    {
        market.updateMarketConfig(newConfig);
    }

    /// @notice Set the configuration of Gearing Token
    function updateGtConfig(ITermMaxMarket market, bytes memory configData) external onlyRole(CONFIGURATOR_ROLE) {
        market.updateGtConfig(configData);
    }

    /// @notice Set the fee rate of an order
    function updateOrderFeeRate(ITermMaxMarket market, ITermMaxOrder order, FeeConfig memory feeConfig)
        external
        onlyRole(CONFIGURATOR_ROLE)
    {
        market.updateOrderFeeRate(order, feeConfig);
    }

    /// @notice Set the switch of an entity
    function setSwitch(IPausable entity, bool state) external onlyRole(PAUSER_ROLE) {
        if (state) {
            entity.unpause();
        } else {
            entity.pause();
        }
    }

    function submitVaultGuardian(ITermMaxVault vault, address newGuardian) external onlyRole(VAULT_ROLE) {
        vault.submitGuardian(newGuardian);
    }

    /// @notice Revoke a pending guardian for the vault
    function revokeVaultPendingGuardian(ITermMaxVault vault) external onlyRole(VAULT_ROLE) {
        vault.revokePendingGuardian();
    }

    /// @notice Revoke a pending timelock for the vault
    function revokeVaultPendingTimelock(ITermMaxVault vault) external onlyRole(VAULT_ROLE) {
        vault.revokePendingTimelock();
    }

    /// @notice Revoke a pending market for the vault
    function revokeVaultPendingMarket(ITermMaxVault vault, address market) external onlyRole(VAULT_ROLE) {
        vault.revokePendingMarket(market);
    }

    /// @notice Set the curator for the vault, only admin role
    function setCuratorForVault(ITermMaxVault vault, address newCurator) external onlyRole(VAULT_ROLE) {
        vault.setCurator(newCurator);
    }

    /// @notice Set the allocator for the vault
    function setIsAllocatorForVault(ITermMaxVault vault, address allocator, bool isAllocator)
        external
        onlyRole(VAULT_ROLE)
    {
        vault.setIsAllocator(allocator, isAllocator);
    }

    /// @notice Revoke role
    /// @dev Can't revoke your own role
    function revokeRole(bytes32 role, address account) public override onlyRole(getRoleAdmin(role)) {
        if (msg.sender == account) {
            revert AccessControlBadConfirmation();
        }

        _revokeRole(role, account);
    }

    /// @notice Revoke role
    /// @dev Can't revoke default admin role
    function renounceRole(bytes32 role, address callerConfirmation) public virtual override {
        if (role == DEFAULT_ADMIN_ROLE) {
            revert CannotRevokeDefaultAdminRole();
        }
        _revokeRole(role, callerConfirmation);
    }

    function _authorizeUpgrade(address newImplementation) internal virtual override onlyRole(DEFAULT_ADMIN_ROLE) {}
}
"
    },
    "contracts/v2/oracle/IOracleV2.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

/**
 * @title IOracleV2
 * @author Term Structure Labs
 * @notice Enhanced oracle interface for TermMax V2 protocol with improved price feed management
 * @dev Extends the V1 oracle interface with additional features including price caps, separate backup heartbeats,
 * and oracle revocation capabilities for enhanced security and flexibility
 */
interface IOracleV2 {
    /**
     * @notice Oracle configuration structure for price feed management
     * @dev Contains primary and backup aggregators with independent heartbeat configurations
     * @param aggregator Primary price feed aggregator (required)
     * @param backupAggregator Secondary price feed aggregator for fallback (optional)
     * @param maxPrice Maximum allowed price value for this asset (0 = no limit)
     * @param minPrice Minimum allowed price value for this asset (0 = no limit)
     * @param heartbeat Maximum allowed staleness for primary aggregator in seconds (0 = no staleness check)
     * @param backupHeartbeat Maximum allowed staleness for backup aggregator in seconds (0 = no staleness check)
     */
    struct Oracle {
        AggregatorV3Interface aggregator;
        AggregatorV3Interface backupAggregator;
        int256 maxPrice;
        int256 minPrice;
        uint32 heartbeat;
        uint32 backupHeartbeat;
    }

    /**
     * @notice Error thrown when the oracle system cannot provide a reliable price
     * @dev Occurs when both primary and backup oracles are stale, returning invalid data, or when no oracle is configured
     * @param asset The address of the asset for which the oracle is not working
     */
    error OracleIsNotWorking(address asset);

    /**
     * @notice Retrieves the current price of an asset in USD from the oracle system
     * @dev Uses primary oracle first, falls back to backup if primary is stale or invalid
     * Applies maxPrice cap if configured. Returns price with the aggregator's native decimals
     * @param asset The address of the asset to get the price for
     * @return price The current price of the asset (may be capped by maxPrice)
     * @return decimals The number of decimal places in the returned price
     * @custom:reverts OracleIsNotWorking if no valid price can be obtained
     */
    function getPrice(address asset) external view returns (uint256 price, uint8 decimals);

    /**
     * @notice Submits a new oracle configuration for an asset with timelock protection
     * @dev Creates a pending oracle update that must wait for the timelock period before activation
     * Used for adding new oracles or updating existing ones with enhanced security
     * @param asset The address of the asset to configure the oracle for
     * @param oracle The oracle configuration structure with primary/backup feeds and settings
     * @custom:access Typically restricted to oracle managers or governance
     * @custom:security Subject to timelock delay for security
     */
    function submitPendingOracle(address asset, Oracle memory oracle) external;

    /**
     * @notice Activates a previously submitted pending oracle configuration
     * @dev Can only be called after the timelock period has elapsed since submission
     * Replaces the current oracle configuration with the pending one
     * @param asset The address of the asset to accept the pending oracle for
     * @custom:access Usually callable by anyone after timelock expires
     * @custom:validation Requires valid pending oracle and elapsed timelock
     */
    function acceptPendingOracle(address asset) external;

    /**
     * @notice Cancels a pending oracle configuration before it can be accepted
     * @dev Allows oracle managers to revoke pending updates if errors are discovered
     * Can only revoke pending oracles that haven't been accepted yet
     * @param asset The address of the asset to revoke the pending oracle for
     * @custom:access Typically restricted to oracle managers or governance
     * @custom:security Provides emergency mechanism to cancel erroneous oracle updates
     */
    function revokePendingOracle(address asset) external;
}
"
    },
    "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/access/IWhitelistManager.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title IWhitelistManager
 * @author Term Structure Labs
 * @notice Interface for managing whitelists for different contract modules
 */
interface IWhitelistManager {
    event WhitelistUpdated(address[] contractAddress, ContractModule module, bool approved);

    enum ContractModule {
        ADAPTER,
        ORDER_CALLBACK,
        MARKET,
        ORACLE,
        POOL
    }

    /**
     * @notice Set the whitelist status for contract addresses and module
     * @param contractAddresses Array of addresses to set the whitelist status for
     * @param module The contract module type
     * @param approved Whether the addresses should be approved or not
     */
    function batchSetWhitelist(address[] memory contractAddresses, ContractModule module, bool approved) external;

    /**
     * @notice Check if a contract address is whitelisted for a specific module
     * @param contractAddress The address to check
     * @param module The contract module type
     * @return bool True if the address is whitelisted for the module, false otherwise
     */
    function isWhitelisted(address contractAddress, ContractModule module) external view returns (bool);
}
"
    },
    "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-upgradeable-5.2.0/access/AccessControlUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {
    struct RoleData {
        mapping(address account => bool) hasRole;
        bytes32 adminRole;
    }

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;


    /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
    struct AccessControlStorage {
        mapping(bytes32 role => RoleData) _roles;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;

    function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
        assembly {
            $.slot := AccessControlStorageLocation
        }
    }

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with an {AccessControlUnauthorizedAccount} error including the required role.
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    function __AccessControl_init() internal onlyInitializing {
    }

    function __AccessControl_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        return $._roles[role].hasRole[account];
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
     * is missing `role`.
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AccessControlUnauthorizedAccount(account, role);
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        return $._roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address callerConfirmation) public virtual {
        if (callerConfirmation != _msgSender()) {
            revert AccessControlBadConfirmation();
        }

        _revokeRole(role, callerConfirmation);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        AccessControlStorage storage $ = _getAccessControlStorage();
        bytes32 previousAdminRole = getRoleAdmin(role);
        $._roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        if (!hasRole(role, account)) {
            $._roles[role].hasRole[account] = true;
            emit RoleGranted(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        if (hasRole(role, account)) {
            $._roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}
"
    },
    "dependencies/@openzeppelin-contracts-upgradeable-5.2.0/proxy/utils/UUPSUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (proxy/utils/UUPSUpgradeable.sol)

pragma solidity ^0.8.22;

import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
import {Initializable} from "./Initializable.sol";

/**
 * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
 * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
 *
 * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
 * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
 * `UUPSUpgradeable` with a custom implementation of upgrades.
 *
 * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
 */
abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
    address private immutable __self = address(this);

    /**
     * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
     * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
     * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
     * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
     * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
     * during an upgrade.
     */
    string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";

    /**
     * @dev The call is from an unauthorized context.
     */
    error UUPSUnauthorizedCallContext();

    /**
     * @dev The storage `slot` is unsupported as a UUID.
     */
    error UUPSUnsupportedProxiableUUID(bytes32 slot);

    /**
     * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
     * a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case
     * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
     * function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
     * fail.
     */
    modifier onlyProxy() {
        _checkProxy();
        _;
    }

    /**
     * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
     * callable on the implementing contract but not through proxies.
     */
    modifier notDelegated() {
        _checkNotDelegated();
        _;
    }

    function __UUPSUpgradeable_init() internal onlyInitializing {
    }

    function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the
     * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
     */
    function proxiableUUID() external view virtual notDelegated returns (bytes32) {
        return ERC1967Utils.IMPLEMENTATION_SLOT;
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
     * encoded in `data`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     *
     * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, data);
    }

    /**
     * @dev Reverts if the execution is not performed via delegatecall or the execution
     * context is not of a proxy with an ERC-1967 compliant implementation pointing to self.
     * See {_onlyProxy}.
     */
    function _checkProxy() internal view virtual {
        if (
            address(this) == __self || // Must be called through delegatecall
            ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
        ) {
            revert UUPSUnauthorizedCallContext();
        }
    }

    /**
     * @dev Reverts if the execution is performed via delegatecall.
     * See {notDelegated}.
     */
    function _checkNotDelegated() internal view virtual {
        if (address(this) != __self) {
            // Must not be called through delegatecall
            revert UUPSUnauthorizedCallContext();
        }
    }

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

    /**
     * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
     *
     * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
     * is expected to be the implementation slot in ERC-1967.
     *
     * Emits an {IERC1967-Upgraded} event.
     */
    function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
        try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
            if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
                revert UUPSUnsupportedProxiableUUID(slot);
            }
            ERC1967Utils.upgradeToAndCall(newImplementation, data);
        } catch {
            // The implementation is not UUPS
            revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
        }
    }
}
"
    },
    "contracts/v1/ITermMaxMarket.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IMintableERC20, IERC20} from "./tokens/IMintableERC20.sol";
import {IGearingToken} from "./tokens/IGearingToken.sol";
import {ITermMaxOrder} from "./ITermMaxOrder.sol";
import {MarketConfig, MarketInitialParams, CurveCuts, FeeConfig} from "./storage/TermMaxStorage.sol";
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
import {ISwapCallback} from "./ISwapCallback.sol";

/**
 * @title TermMax Market interface
 * @author Term Structure Labs
 */
interface ITermMaxMarket {
    /// @notice Initialize the token and configuration of the market
    function initialize(MarketInitialParams memory params) external;

    /// @notice Return the configuration
    function config() external view returns (MarketConfig memory);

    /// @notice Set the market configuration
    function updateMarketConfig(MarketConfig calldata newConfig) external;

    /// @notice Return the tokens in TermMax Market
    /// @return ft Fixed-rate Token(bond token). Earning Fixed Income with High Certainty
    /// @return xt Intermediary Token for Collateralization and Leveragin
    /// @return gt Gearing Token
    /// @return collateral Collateral token
    /// @return underlying Underlying Token(debt)
    function tokens()
        external
        view
        returns (IMintableERC20 ft, IMintableERC20 xt, IGearingToken gt, address collateral, IERC20 underlying);

    /// @notice Mint FT and XT tokens by underlying token.
    ///         No price slippage or handling fees.
    /// @param debtTokenAmt Amount of underlying token want to lock
    function mint(address recipient, uint256 debtTokenAmt) external;

    /// @notice Burn FT and XT to get underlying token.
    ///         No price slippage or handling fees.
    /// @param debtTokenAmt Amount of underlying token want to get
    function burn(address recipient, uint256 debtTokenAmt) external;

    /// @notice Using collateral to issue FT tokens.
    ///         Caller will get FT(bond) tokens equal to the debt amount subtract issue fee
    /// @param debt The amount of debt, unit by underlying token
    /// @param collateralData The encoded data of collateral
    /// @return gtId The id of Gearing Token
    ///
    function issueFt(address recipient, uint128 debt, bytes calldata collateralData)
        external
        returns (uint256 gtId, uint128 ftOutAmt);

    /// @notice Return the issue fee ratio
    function mintGtFeeRatio() external view returns (uint256);

    /// @notice Using collateral to issue FT tokens.
    ///         Caller will get FT(bond) tokens equal to the debt amount subtract issue fee
    /// @param recipient Who will receive Gearing Token
    /// @param debt The amount of debt, unit by underlying token
    /// @param gtId The id of Gearing Token
    /// @return ftOutAmt The amount of FT issued
    ///
    function issueFtByExistedGt(address recipient, uint128 debt, uint256 gtId) external returns (uint128 ftOutAmt);

    /// @notice Flash loan underlying token for leverage
    /// @param recipient Who will receive Gearing Token
    /// @param xtAmt The amount of XT token.
    ///              The caller will receive an equal amount of underlying token by flash loan.
    /// @param callbackData The data of flash loan callback
    /// @return gtId The id of Gearing Token
    function leverageByXt(address recipient, uint128 xtAmt, bytes calldata callbackData)
        external
        returns (uint256 gtId);

    /// @notice Preview the redeem amount and delivery data
    /// @param ftAmount The amount of FT want to redeem
    /// @return debtTokenAmt The amount of debt token
    /// @return deliveryData The delivery data
    function previewRedeem(uint256 ftAmount) external view returns (uint256 debtTokenAmt, bytes memory deliveryData);

    /// @notice Redeem underlying tokens after maturity
    /// @param ftAmount The amount of FT want to redeem
    /// @param recipient Who will receive the underlying tokens
    /// @return debtTokenAmt The amount of debt token
    /// @return deliveryData The delivery data
    function redeem(uint256 ftAmount, address recipient)
        external
        returns (uint256 debtTokenAmt, bytes memory deliveryData);

    /// @notice Set the configuration of Gearing Token
    function updateGtConfig(bytes memory configData) external;

    /// @notice Set the fee rate of order
    function updateOrderFeeRate(ITermMaxOrder order, FeeConfig memory newFeeConfig) external;

    /// @notice Create a new order
    function createOrder(address maker, uint256 maxXtReserve, ISwapCallback swapTrigger, CurveCuts memory curveCuts)
        external
        returns (ITermMaxOrder order);
}
"
    },
    "contracts/v1/factory/ITermMaxFactory.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {MarketInitialParams} from "../storage/TermMaxStorage.sol";

/**
 * @title The TermMax factory interface
 * @author Term Structure Labs
 */
interface ITermMaxFactory {
    function TERMMAX_MARKET_IMPLEMENTATION() external view returns (address);

    function gtImplements(bytes32 gtKey) external view returns (address gtImplement);

    /// @notice Set the implementations of TermMax Gearing Token contract
    function setGtImplement(string memory gtImplementName, address gtImplement) external;

    /// @notice Predict the address of token pair
    function predictMarketAddress(
        address deployer,
        address collateral,
        address debtToken,
        uint64 maturity,
        uint256 salt
    ) external view returns (address market);

    /// @notice Deploy a new market
    function createMarket(bytes32 gtKey, MarketInitialParams memory params, uint256 salt)
        external
        returns (address market);
}
"
    },
    "contracts/v1/router/ITermMaxRouter.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ITermMaxMarket} from "../ITermMaxMarket.sol";
import {ITermMaxOrder} from "../ITermMaxOrder.sol";
import {SwapUnit} from "./ISwapAdapter.sol";
import {CurveCuts} from "../storage/TermMaxStorage.sol";
import {ISwapCallback} from "../ISwapCallback.sol";

/**
 * @title TermMax Router interface
 * @author Term Structure Labs
 * @notice Interface for the main router contract that handles all user interactions with TermMax protocol
 * @dev This interface defines all external functions for swapping, leveraging, and managing positions
 */
interface ITermMaxRouter {
    /**
     * @notice Pauses all protocol operations
     * @dev Can only be called by authorized addresses
     */
    function pause() external;

    /**
     * @notice Unpauses protocol operations
     * @dev Can only be called by authorized addresses
     */
    function unpause() external;

    /**
     * @notice View the adapter whitelist status
     * @dev Used for controlling which swap adapters can be used
     * @param adapter The adapter's address to check whitelist status for
     * @return True if whitelisted, false otherwise
     */
    function adapterWhitelist(address adapter) external view returns (bool);

    /**
     * @notice Set the adapter whitelist status
     * @dev Used for controlling which swap adapters can be used
     * @param adapter The adapter's address to set whitelist status for
     * @param isWhitelist True to whitelist, false to remove from whitelist
     */
    function setAdapterWhitelist(address adapter, bool isWhitelist) external;

    /**
     * @notice Retrieves all assets owned by an address in a specific market
     * @dev Returns both ERC20 tokens and GT (Governance Token) positions
     * @param market The market to query assets from
     * @param owner The address to check assets for
     * @return tokens Array of ERC20 token addresses
     * @return balances Corresponding balances for each token
     * @return gt The GT token contract address
     * @return gtIds Array of GT token IDs owned by the address
     */
    function assetsWithERC20Collateral(ITermMaxMarket market, address owner)
        external
        view
        returns (IERC20[4] memory tokens, uint256[4] memory balances, address gt, uint256[] memory gtIds);

    /**
     * @notice Swaps an exact amount of input token for output token
     * @dev Uses specified orders for the swap path
     * @param tokenIn Input token to swap from
     * @param tokenOut Output token to swap to
     * @param recipient Address to receive the output tokens
     * @param orders Array of orders to use for the swap path
     * @param tradingAmts Array of amounts to trade for each order
     * @param minTokenOut Minimum amount of output tokens to receive
     * @param deadline The deadline timestamp for the transaction
     * @return netTokenOut Actual amount of output tokens received
     */
    function swapExactTokenToToken(
        IERC20 tokenIn,
        IERC20 tokenOut,
        address recipient,
        ITermMaxOrder[] memory orders,
        uint128[] memory tradingAmts,
        uint128 minTokenOut,
        uint256 deadline
    ) external returns (uint256 netTokenOut);

    /**
     * @notice Swaps tokens to receive an exact amount of output token
     * @dev Uses specified orders for the swap path
     * @param tokenIn Input token to swap from
     * @param tokenOut Output token to swap to
     * @param recipient Address to receive the output tokens
     * @param orders Array of orders to use for the swap path
     * @param tradingAmts Array of amounts to trade for each order
     * @param maxTokenIn Maximum amount of input tokens to spend
     * @param deadline The deadline timestamp for the transaction
     * @return netTokenIn Actual amount of input tokens spent
     */
    function swapTokenToExactToken(
        IERC20 tokenIn,
        IERC20 tokenOut,
        address recipient,
        ITermMaxOrder[] memory orders,
        uint128[] memory tradingAmts,
        uint128 maxTokenIn,
        uint256 deadline
    ) external returns (uint256 netTokenIn);

    /**
     * @notice Sells FT and XT tokens for underlying tokens
     * @dev Executes multiple orders to sell tokens
     * @param recipient Address to receive the output tokens
     * @param market The market to sell tokens in
     * @param ftInAmt Amount of FT tokens to sell
     * @param xtInAmt Amount of XT tokens to sell
     * @param orders Array of orders to execute
     * @param amtsToSellTokens Array of amounts to sell for each order
     * @param minTokenOut Minimum amount of output tokens to receive
     * @param deadline The deadline timestamp for the transaction
     * @return netTokenOut Actual amount of output tokens received
     */
    function sellTokens(
        address recipient,
        ITermMaxMarket market,
        uint128 ftInAmt,
        uint128 xtInAmt,
        ITermMaxOrder[] memory orders,
        uint128[] memory amtsToSellTokens,
        uint128 minTokenOut,
        uint256 deadline
    ) external returns (uint256 netTokenOut);

    /**
     * @notice Creates a leveraged position from input tokens
     * @dev Swaps tokens for XT and creates a leveraged position
     * @param recipient Address to receive the position
     * @param market The market to create position in
     * @param orders Array of orders to execute
     * @param amtsToBuyXt Array of amounts of XT to buy for each order
     * @param minXtOut Minimum amount of XT to establish the position
     * @param tokenToSwap Amount of tokens to swap
     * @param maxLtv Maximum loan-to-value ratio
     * @param units Array of swap units defining the swap path
     * @param deadline The deadline timestamp for the transaction
     * @return gtId ID of the generated GT token
     * @return netXtOut Amount of XT tokens received
     */
    function leverageFromToken(
        address recipient,
        ITermMaxMarket market,
        ITermMaxOrder[] memory orders,
        uint128[] memory amtsToBuyXt,
        uint128 minXtOut,
        uint128 tokenToSwap,
        uint128 maxLtv,
        SwapUnit[] memory units,
        uint256 deadline
    ) external returns (uint256 gtId, uint256 netXtOut);

    /**
     * @notice Creates a leveraged position from XT tokens
     * @dev Uses existing XT tokens to create a leveraged position
     * @param recipient Address to receive the position
     * @param market The market to create position in
     * @param xtInAmt Amount of XT tokens to use
     * @param tokenInAmt Amount of additional tokens to use
     * @param maxLtv Maximum loan-to-value ratio
     * @param units Array of swap units defining the swap path
     * @return gtId ID of the generated GT token
     */
    function leverageFromXt(
        address recipient,
        ITermMaxMarket market,
        uint128 xtInAmt,
        uint128 tokenInAmt,
        uint128 maxLtv,
        SwapUnit[] memory units
    ) external returns (uint256 gtId);

    function leverageFromXtAndCollateral(
        address recipient,
        ITermMaxMarket market,
        uint128 xtInAmt,
        uint128 collateralInAmt,
        uint128 maxLtv,
        SwapUnit[] memory units
    ) external returns (uint256 gtId);

    /**
     * @notice Borrows tokens using collateral
     * @dev Creates a collateralized debt position
     * @param recipient Address to receive the borrowed tokens
     * @param market The market to borrow from
     * @param collInAmt Amount of collateral to deposit
     * @param orders Array of orders to execute
     * @param tokenAmtsWantBuy Array of token amounts to buy
     * @param maxDebtAmt Maximum amount of debt to take on
     * @param deadline The deadline timestamp for the transaction
     * @return gtId ID of the generated GT token
     */
    function borrowTokenFromCollateral(
        address recipient,
        ITermMaxMarket market,
        uint256 collInAmt,
        ITermMaxOrder[] memory orders,
        uint128[] memory tokenAmtsWantBuy,
        uint128 maxDebtAmt,
        uint256 deadline
    ) external returns (uint256 gtId);

    /**
     * @notice Borrows tokens using collateral and XT
     * @dev Creates a collateralized debt position
     * @param recipient Address to receive the borrowed tokens
     * @param market The market to borrow from
     * @param collInAmt Amount of collateral to deposit
     * @param borrowAmt Amount of tokens to borrow
     * @return gtId ID of the generated GT token
     */
    function borrowTokenFromCollateral(address recipient, ITermMaxMarket market, uint256 collInAmt, uint256 borrowAmt)
        external
        returns (uint256 gtId);

    /**
     * @notice Borrows tokens from an existing GT position
     * @dev Increases the debt of an existing position
     * @param recipient Address to receive the borrowed tokens
     * @param market The market to borrow from
     * @param gtId ID of the GT token to borrow from
     * @param borrowAmt Amount of tokens to borrow
     */
    function borrowTokenFromGt(address recipient, ITermMaxMarket market, uint256 gtId, uint256 borrowAmt) external;

    /**
     * @notice Repays debt from collateral
     * @dev Repays debt and closes a position
     * @param recipient Address to receive any remaining collateral
     * @param market The market to repay debt in
     * @param gtId ID of the GT token to repay debt from
     * @param orders Array of orders to execute
     * @param amtsToBuyFt Array of amounts to buy for each order
     * @param byDebtToken Whether to repay debt using debt tokens
     * @param units Array of swap units defining the swap path
     * @param deadline The deadline timestamp for the transaction
     * @return netTokenOut Actual amount of tokens received
     */
    function flashRepayFromColl(
        address recipient,
        ITermMaxMarket market,
        uint256 gtId,
        ITermMaxOrder[] memory orders,
        uint128[] memory amtsToBuyFt,
        bool byDebtToken,
        SwapUnit[] memory units,
        uint256 deadline
    ) external returns (uint256 netTokenOut);

    /**
     * @notice Repays debt using FT tokens
     * @dev Repays debt and closes a position
     * @param recipient Address to receive any remaining tokens
     * @param market The market to repay debt in
     * @param gtId ID of the GT token to repay debt from
     * @param orders Array of orders to execute
     * @param ftAmtsWantBuy Array of FT amounts to buy for each order
     * @param maxTokenIn Maximum amount of tokens to spend
     * @param deadline The deadline timestamp for the transaction
     * @return returnAmt Actual amount of tokens returned
     */
    function repayByTokenThroughFt(
        address recipient,
        ITermMaxMarket market,
        uint256 gtId,
        ITermMaxOrder[] memory orders,
        uint128[] memory ftAmtsWantBuy,
        uint128 maxTokenIn,
        uint256 deadline
    ) external returns (uint256 returnAmt);

    /**
     * @notice Redeems FT tokens and swaps for underlying tokens
     * @dev Executes a swap to redeem FT tokens
     * @param recipient Address to receive the output tokens
     * @param market The market to redeem FT tokens in
     * @param ftAmount Amount of FT tokens to redeem
     * @param units Array of swap units defining the swap path
     * @param minTokenOut Minimum amount of output tokens to receive
     * @return redeemedAmt Actual amount of output tokens received
     */
    function redeemAndSwap(
        address recipient,
        ITermMaxMarket market,
        uint256 ftAmount,
        SwapUnit[] memory units,
        uint256 minTokenOut
    ) external returns (uint256 redeemedAmt);

    /**
     * @notice Creates an order and deposits tokens
     * @dev Creates a new order and deposits tokens to the market
     * @param market The market to create order in
     * @param maker Address of the order maker
     * @param maxXtReserve Maximum amount of XT to reserve
     * @param swapTrigger Swap trigger callback
     * @param debtTokenToDeposit Amount of debt tokens to deposit
     * @param ftToDeposit Amount of FT tokens to deposit
     * @param xtToDeposit Amount of XT tokens to deposit
     * @param curveCuts Curve cuts for the order
     * @return order The created order
     */
    function createOrderAndDeposit(
        ITermMaxMarket market,
        address maker,
        uint256 maxXtReserve,
        ISwapCallback swapTrigger,
        uint256 debtTokenToDeposit,
        uint128 ftToDeposit,
        uint128 xtToDeposit,
        CurveCuts memory curveCuts
    ) external returns (ITermMaxOrder order);
}
"
    },
    "contracts/v1/ITermMaxOrder.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import {IMintableERC20, IERC20} from "./tokens/IMintableERC20.sol";
import {IGearingToken} from "./tokens/IGearingToken.sol";
import {ITermMaxMarket} from "./ITermMaxMarket.sol";
import {OrderConfig, MarketConfig, CurveCuts, FeeConfig} from "./storage/TermMaxStorage.sol";
import {ISwapCallback} from "./ISwapCallback.sol";

/**
 * @title TermMax Order interface
 * @author Term Structure Labs
 */
interface ITermMaxOrder {
    /// @notice Initialize the token and configuration of the order
    /// @param maker The maker
    /// @param tokens The tokens
    /// @param gt The Gearing Token
    /// @param maxXtReserve The maximum reserve of XT token
    /// @param curveCuts The curve cuts
    /// @param marketConfig The market configuration
    /// @dev Only factory will call this function once when deploying new market
    function initialize(
        address maker,
        IERC20[3] memory tokens,
        IGearingToken gt,
        uint256 maxXtReserve,
        ISwapCallback trigger,
        CurveCuts memory curveCuts,
        MarketConfig memory marketConfig
    ) external;

    /// @notice Return the configuration
    function orderConfig() external view returns (OrderConfig memory);

    /// @notice Return the maker
    function maker() external view returns (address);

    /// @notice Set the market configuration
    /// @param newOrderConfig New order configuration
    /// @param ftChangeAmt Change amount of FT reserve
    /// @param xtChangeAmt Change amount of XT reserve
    function updateOrder(OrderConfig memory newOrderConfig, int256 ftChangeAmt, int256 xtChangeAmt) external;

    function withdrawAssets(IERC20 token, address recipient, uint256 amount) external;

    function updateFeeConfig(FeeConfig memory newFeeConfig) external;

    /// @notice Return the token reserves
    function tokenReserves() external view returns (uint256 ftReserve, uint256 xtReserve);

    /// @notice Return the tokens in TermMax Market
    /// @return market The market
    function market() external view returns (ITermMaxMarket market);

    /// @notice Return the current apr of the amm order book
    /// @return lendApr Lend APR
    /// @return borrowApr Borrow APR
    function apr() external view returns (uint256 lendApr, uint256 borrowApr);

    /// @notice Swap exact token to token
    /// @param tokenIn The token want to swap
    /// @param tokenOut The token want to receive
    /// @param recipient Who receive output tokens
    /// @param tokenAmtIn The number of tokenIn tokens input
    /// @param minTokenOut Minimum number of tokenOut token outputs required
    /// @param deadline The timestamp after which the transaction will revert
    /// @return netOut The actual number of tokenOut tokens received
    function swapExactTokenToToken(
        IERC20 tokenIn,
        IERC20 tokenOut,
        address recipient,
        uint128 tokenAmtIn,
        uint128 minTokenOut,
        uint256 deadline
    ) external returns (uint256 netOut);

    /// @notice Swap token to exact token
    /// @param tokenIn The token want to swap
    /// @param tokenOut The token want to receive
    /// @param recipient Who receive output tokens
    /// @param tokenAmtOut The number of tokenOut tokens output
    /// @param maxTokenIn Maximum number of tokenIn token inputs required
    /// @param deadline The timestamp after which the transaction will revert
    /// @return netIn The actual number of tokenIn tokens input
    function swapTokenToExactToken(
        IERC20 tokenIn,
        IERC20 tokenOut,
        address recipient,
        uint128 tokenAmtOut,
        uint128 maxTokenIn,
        uint256 deadline
    ) external returns (uint256 netIn);

    /// @notice Suspension of market trading
    function pause() external;

    /// @notice Open Market Trading
    function unpause() external;
}
"
    },
    "contracts/v1/oracle/IOracle.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

/**
 * @title IOracle
 * @author Term Structure Labs
 */
interface IOracle {
    struct Oracle {
        AggregatorV3Interface aggregator;
        AggregatorV3Interface backupAggregator;
        uint32 heartbeat;
    }

    /// @notice Error thrown when the oracle is not working
    error OracleIsNotWorking(address

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

Submitted on: 2025-10-13 11:00:10

Comments

Log in to comment.

No comments yet.