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`
Submitted on: 2025-10-01 13:35:25
Comments
Log in to comment.
No comments yet.