Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x4778CBf91d8369843281c8f5a2D7b56d1420dFF5
Balance 0 ETH
Nonce 19
Code Size 1653 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

1653 bytes
0x60806040526004361015610011575f80fd5b5f5f3560e01c80636aec18e7146104475780637e790995146100825763c65b512d1461003b575f80fd5b3461007f578060031936011261007f576040517f0000000000000000000000001c9152b1981f3a67b66e8879c4513096fefc55406001600160a01b03168152602090f35b80fd5b5034610420576040366003190112610420576004359067ffffffffffffffff82116104205761010060031983360301126104205760405191610100830183811067ffffffffffffffff821117610433576040526100e18160040161058f565b83526100ef6024820161058f565b60208401908152604482013560408501908152936064830135926001600160a01b0384168403610420576060820193845260808201906084810135825260a481013567ffffffffffffffff81116104205761015090600436918401016105c5565b60a0840190815260c482013567ffffffffffffffff81116104205761017b90600436918501016105c5565b9260e460c086019385855201359367ffffffffffffffff851685036104205760e086019485526e5af43d82803e903d91602b57fd5bf37f0000000000000000000000001c9152b1981f3a67b66e8879c4513096fefc55409161020e61023660018060a01b038c5116926102208851916040519485936020850197338952604086015260a0606086015260c085019061061b565b838103601f190160808501529061061b565b60243560a083015203601f1981018352826105a3565b51902091763d602d80600a3d3981f3363d3d373d3d3d363d7300000062ffffff8260881c16175f5260781b1760205260018060a01b0390603760095ff51696871561042457873b15610420576040516377e1731b60e01b81526020600482015286516001600160a01b0390811660248301528851811660448301528b5160648301528251166084820152825160a4820152835161010060c4830152909a905f908c908190610300906102ed9061012484019061061b565b89518382036023190160e485015261061b565b67ffffffffffffffff8a51166101048301520381838d5af19a8b156104155760209b6103e1575b506040805197516001600160a01b03908116895298518916888d015290519087015251909516606085015293516080840152925180519293879385939267ffffffffffffffff9260a0929091879190819083018886015e8a848289010152601f8019910116860191518051918291018484015e89838284010152601f8019910116010191511681520301902060405192827f8d49b14f2b628cc0c1a7ad5e098155260cd1881003c9d3107c728be96f706b33339280a48152f35b8b9796959288929b509460a09467ffffffffffffffff966104035f86956105a3565b5f9d9450949798995094509450610327565b6040513d5f823e3d90fd5b5f80fd5b63b06ebf3d60e01b5f5260045ffd5b634e487b7160e01b5f52604160045260245ffd5b346104205760a0366003190112610420576004356001600160a01b03811690819003610420576024356001600160a01b03811691908290036104205760443567ffffffffffffffff8111610420576104a39036906004016105c5565b60643567ffffffffffffffff8111610420576020936104f16104cc6105079336906004016105c5565b61020e604051958694898601988952604086015260a0606086015260c085019061061b565b60843560a083015203601f1981018352826105a3565b519020604051903060388301526f5af43d82803e903d91602b57fd5bf3ff60248301527f0000000000000000000000001c9152b1981f3a67b66e8879c4513096fefc55406014830152733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c82012060788201526055604360018060a01b0392012016604051908152f35b35906001600160a01b038216820361042057565b90601f8019910116810190811067ffffffffffffffff82111761043357604052565b81601f820112156104205780359067ffffffffffffffff821161043357604051926105fa601f8401601f1916602001856105a3565b8284526020838301011161042057815f926020809301838601378301015290565b805180835260209291819084018484015e5f828201840152601f01601f191601019056fea26469706673582212208e29fa66a3ffc910eaac7789e962343eb722fb77103e28816af2b760ee4ccc4964736f6c634300081b0033

Verified Source Code Full Match

Compiler: v0.8.27+commit.40a35a09 EVM: cancun Optimization: Yes (200 runs)
FactoryErrors.sol 19 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title Factory Errors Interface
 * @notice Custom errors for the TermMax factory operations
 */
interface FactoryErrors {
    /**
     * @notice Error thrown when attempting to initialize with an invalid implementation
     */
    error InvalidImplementation();

    /**
     * @notice Error thrown when a requested Gearing Token implementation cannot be found
     * @dev This occurs when trying to use a GT implementation that hasn't been registered
     */
    error CantNotFindGtImplementation();
}
VaultFactory.sol 54 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
import {ITermMaxVault} from "contracts/vault/ITermMaxVault.sol";
import {VaultInitialParams} from "contracts/storage/TermMaxStorage.sol";
import {FactoryEvents} from "contracts/events/FactoryEvents.sol";
import {FactoryErrors} from "contracts/errors/FactoryErrors.sol";
import {IVaultFactory} from "./IVaultFactory.sol";

/**
 * @title The TermMax vault factory
 * @author Term Structure Labs
 */
contract VaultFactory is FactoryEvents, IVaultFactory, FactoryErrors {
    /**
     * @notice The implementation of TermMax Vault contract
     */
    address public immutable TERMMAX_VAULT_IMPLEMENTATION;

    constructor(address TERMMAX_VAULT_IMPLEMENTATION_) {
        if (TERMMAX_VAULT_IMPLEMENTATION_ == address(0)) {
            revert InvalidImplementation();
        }
        TERMMAX_VAULT_IMPLEMENTATION = TERMMAX_VAULT_IMPLEMENTATION_;
    }

    /**
     * @inheritdoc IVaultFactory
     */
    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 IVaultFactory
     */
    function createVault(VaultInitialParams 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))
        );
        ITermMaxVault(vault).initialize(initialParams);
        emit CreateVault(vault, msg.sender, initialParams);
    }
}
Clones.sol 262 lines
// 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
            );
    }
}
ITermMaxVault.sol 296 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {ITermMaxMarket} from "contracts/ITermMaxMarket.sol";
import {CurveCuts, VaultInitialParams} from "contracts/storage/TermMaxStorage.sol";
import {ITermMaxOrder} from "contracts/ITermMaxOrder.sol";
import {PendingAddress, PendingUint192} from "contracts/lib/PendingLib.sol";
import {OrderInfo} from "./VaultStorage.sol";

/**
 * @title TermMax Vault Interface
 * @author Term Structure Labs
 * @notice Interface for TermMax vaults that extends the ERC4626 standard
 * @dev Implements ERC4626 tokenized vault standard with additional TermMax-specific functionality
 */
interface ITermMaxVault is IERC4626 {
    /**
     * @notice Initializes the vault
     * @param params The initial parameters of the vault
     */
    function initialize(VaultInitialParams memory params) external;

    /**
     * @notice Handles bad debt by exchanging shares for collateral
     * @param collaretal The collateral token address
     * @param badDebtAmt The amount of bad debt to handle
     * @param recipient The recipient of the collateral
     * @param owner The owner of the shares
     * @return shares The amount of shares burned
     * @return collaretalOut The amount of collateral released
     */
    function dealBadDebt(address collaretal, uint256 badDebtAmt, address recipient, address owner)
        external
        returns (uint256 shares, uint256 collaretalOut);

    /**
     * @notice Returns the current Annual Percentage Rate (APR)
     * @return The current APR as a percentage with 8 decimals
     */
    function apr() external view returns (uint256);

    /**
     * @notice Returns the guardian address
     * @return The address of the guardian
     */
    function guardian() external view returns (address);

    /**
     * @notice Returns the curator address
     * @return The address of the curator
     */
    function curator() external view returns (address);

    /**
     * @notice Checks if an address is an allocator
     * @param allocator The address to check
     * @return True if the address is an allocator, false otherwise
     */
    function isAllocator(address allocator) external view returns (bool);

    /**
     * @notice Checks if a market is whitelisted
     * @param market The market address to check
     * @return True if the market is whitelisted, false otherwise
     */
    function marketWhitelist(address market) external view returns (bool);

    /**
     * @notice Returns the timelock duration
     * @return The timelock duration in seconds
     */
    function timelock() external view returns (uint256);

    /**
     * @notice Returns the pending market information
     * @param market The market address to check
     */
    function pendingMarkets(address market) external view returns (PendingUint192 memory);

    /**
     * @notice Returns the pending timelock information
     */
    function pendingTimelock() external view returns (PendingUint192 memory);

    /**
     * @notice Returns the pending performance fee rate information
     */
    function pendingPerformanceFeeRate() external view returns (PendingUint192 memory);

    /**
     * @notice Returns the pending guardian information
     */
    function pendingGuardian() external view returns (PendingAddress memory);

    /**
     * @notice Returns the performance fee rate
     * @return The performance fee rate as a percentage with 18 decimals
     */
    function performanceFeeRate() external view returns (uint64);

    /**
     * @notice Returns the total amount of ft tokens
     * @return The total amount of ft tokens
     */
    function totalFt() external view returns (uint256);

    /**
     * @notice Returns the accreting principal amount
     * @return The accreting principal amount
     */
    function accretingPrincipal() external view returns (uint256);

    /**
     * @notice Returns the annualized interest
     * @return The annualized interest
     */
    function annualizedInterest() external view returns (uint256);

    /**
     * @notice Returns the performance fee amount
     * @return The performance fee amount
     */
    function performanceFee() external view returns (uint256);

    /**
     * @notice Returns the supply queue information
     * @param index The index of the supply queue to retrieve
     * @return The address of the supply queue at the specified index
     */
    function supplyQueue(uint256 index) external view returns (address);

    /**
     * @notice Returns the withdraw queue information
     * @param index The index of the withdraw queue to retrieve
     * @return The address of the withdraw queue at the specified index
     */
    function withdrawQueue(uint256 index) external view returns (address);

    /// @notice Return the length of the supply queue
    function supplyQueueLength() external view returns (uint256);

    /// @notice Return the length of the withdraw queue
    function withdrawQueueLength() external view returns (uint256);

    /**
     * @notice Returns the order mapping information
     * @param order The order address to retrieve
     */
    function orderMapping(address order) external view returns (OrderInfo memory);

    /**
     * @notice Returns the bad debt mapping information
     * @param collateral The collateral address to retrieve
     * @return The bad debt amount associated with the collateral
     */
    function badDebtMapping(address collateral) external view returns (uint256);

    /**
     * @notice Creates a new order
     * @param market The market address to create the order for
     * @param maxSupply The maximum supply of the order
     * @param initialReserve The initial reserve amount of the order
     * @param curveCuts The curve cuts to use for the order
     * @return order The newly created order
     */
    function createOrder(ITermMaxMarket market, uint256 maxSupply, uint256 initialReserve, CurveCuts calldata curveCuts)
        external
        returns (ITermMaxOrder order);

    /**
     * @notice Updates multiple orders
     * @param orders The orders to update
     * @param changes The changes to apply to each order
     * @param maxSupplies The maximum supplies to update for each order
     * @param curveCuts The curve cuts to update for each order
     */
    function updateOrders(
        ITermMaxOrder[] calldata orders,
        int256[] calldata changes,
        uint256[] calldata maxSupplies,
        CurveCuts[] calldata curveCuts
    ) external;

    /**
     * @notice Updates the supply queue
     * @param indexes The indexes to update in the supply queue
     */
    function updateSupplyQueue(uint256[] calldata indexes) external;

    /**
     * @notice Updates the withdraw queue
     * @param indexes The indexes to update in the withdraw queue
     */
    function updateWithdrawQueue(uint256[] calldata indexes) external;

    /**
     * @notice Redeems an order
     * @param order The order to redeem
     */
    function redeemOrder(ITermMaxOrder order) external;

    /**
     * @notice Withdraws performance fee
     * @param recipient The recipient of the performance fee
     * @param amount The amount of performance fee to withdraw
     */
    function withdrawPerformanceFee(address recipient, uint256 amount) external;

    /**
     * @notice Submits a new guardian address
     * @param newGuardian The new guardian address
     */
    function submitGuardian(address newGuardian) external;

    /**
     * @notice Sets a new curator address
     * @param newCurator The new curator address
     */
    function setCurator(address newCurator) external;

    /**
     * @notice Submits a new timelock duration
     * @param newTimelock The new timelock duration
     */
    function submitTimelock(uint256 newTimelock) external;

    /**
     * @notice Sets a new capacity
     * @param newCapacity The new capacity
     */
    function setCapacity(uint256 newCapacity) external;

    /**
     * @notice Sets whether an address is an allocator
     * @param newAllocator The address to set as an allocator
     * @param newIsAllocator Whether the address is an allocator
     */
    function setIsAllocator(address newAllocator, bool newIsAllocator) external;

    /**
     * @notice Submits a new performance fee rate
     * @param newPerformanceFeeRate The new performance fee rate
     */
    function submitPerformanceFeeRate(uint184 newPerformanceFeeRate) external;

    /**
     * @notice Submits a new market for whitelisting
     * @param market The market address to whitelist
     * @param isWhitelisted Whether the market is whitelisted
     */
    function submitMarket(address market, bool isWhitelisted) external;

    /**
     * @notice Revokes the pending timelock
     */
    function revokePendingTimelock() external;

    /**
     * @notice Revokes the pending guardian
     */
    function revokePendingGuardian() external;

    /**
     * @notice Revokes the pending market
     * @param market The market address to revoke
     */
    function revokePendingMarket(address market) external;

    /**
     * @notice Revokes the pending performance fee rate
     */
    function revokePendingPerformanceFeeRate() external;

    /**
     * @notice Accepts the pending timelock
     */
    function acceptTimelock() external;

    /**
     * @notice Accepts the pending guardian
     */
    function acceptGuardian() external;

    /**
     * @notice Accepts the pending market
     * @param market The market address to accept
     */
    function acceptMarket(address market) external;

    /**
     * @notice Accepts the pending performance fee rate
     */
    function acceptPerformanceFeeRate() external;
}
TermMaxStorage.sol 124 lines
// 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;
}
FactoryEvents.sol 34 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {VaultInitialParams} from "contracts/storage/TermMaxStorage.sol";

/**
 * @title Factory Events Interface
 * @notice Events emitted by the TermMax factory contracts
 */
interface FactoryEvents {
    /**
     * @notice Emitted when a new Gearing Token implementation is set
     * @param key The unique identifier for the GT implementation
     * @param gtImplement The address of the GT implementation contract
     */
    event SetGtImplement(bytes32 key, address gtImplement);

    /**
     * @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
     */
    event CreateMarket(address indexed market, address indexed collateral, IERC20 indexed debtToken);

    /**
     * @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 CreateVault(address indexed vault, address indexed creator, VaultInitialParams indexed initialParams);
}
IVaultFactory.sol 41 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {VaultInitialParams} from "contracts/storage/TermMaxStorage.sol";

/**
 * @title TermMax Vault Factory Interface
 * @author Term Structure Labs
 * @notice Interface for creating new TermMax vaults
 */
interface IVaultFactory {
    /**
     * @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(VaultInitialParams memory initialParams, uint256 salt) external returns (address);
}
Create2.sol 92 lines
// 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)
        }
    }
}
Errors.sol 34 lines
// 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);
}
IERC4626.sol 230 lines
// 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);
}
IERC20.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../token/ERC20/IERC20.sol";
ITermMaxMarket.sol 103 lines
// 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);
}
ITermMaxOrder.sol 100 lines
// 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;
}
PendingLib.sol 38 lines
// 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 [email protected]
/// @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);
    }
}
VaultStorage.sol 58 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import {ITermMaxMarket} from "contracts/ITermMaxMarket.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {PendingAddress, PendingUint192} from "contracts/lib/PendingLib.sol";

struct OrderInfo {
    ITermMaxMarket market;
    IERC20 ft;
    IERC20 xt;
    uint128 maxSupply;
    uint64 maturity;
}

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

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

    PendingUint192 internal _pendingTimelock;
    PendingUint192 internal _pendingPerformanceFeeRate;
    PendingAddress internal _pendingGuardian;

    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;

    uint64 internal _performanceFeeRate;

    address[] internal _supplyQueue;
    address[] internal _withdrawQueue;

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

    /// @dev The last time the interest was accurately calculated
    uint64 internal _lastUpdateTime;
    /// @dev A one-way linked list presented using a mapping structure, recorded in order according to matiruty
    /// @dev 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;
    /// @dev A mapping from maturity to its annualized interest
    mapping(uint64 => uint256) internal _maturityToInterest;
}
IERC20Metadata.sol 26 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Interface for the optional metadata functions from the ERC-20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}
IERC20.sol 79 lines
// 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` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}
IOracle.sol 26 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/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 asset);

    /// @notice Get the price of an asset
    function getPrice(address asset) external view returns (uint256 price, uint8 decimals);

    function submitPendingOracle(address asset, Oracle memory oracle) external;

    function acceptPendingOracle(address asset) external;
}
ISwapCallback.sol 18 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title TermMax Swap Callback Interface
 * @author Term Structure Labs
 * @notice Interface for handling callbacks after swap operations in TermMax
 */
interface ISwapCallback {
    /**
     * @notice Callback function called after a swap operation
     * @param ftReserve The reserve of the FT token
     * @param xtReserve The reserve of the XT token
     * @param deltaFt The change in FT token balance (positive for receiving, negative for paying)
     * @param deltaXt The change in XT token balance (positive for receiving, negative for paying)
     */
    function afterSwap(uint256 ftReserve, uint256 xtReserve, int256 deltaFt, int256 deltaXt) external;
}
IMintableERC20.sol 38 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

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

/**
 * @title TermMax ERC20 token interface
 * @author Term Structure Labs
 */
interface IMintableERC20 is IERC20 {
    /// @notice Error when using offline signature but spender is not the maerket
    error SpenderIsNotMarket(address spender);

    // @notice Initial function
    /// @param name The token's name
    /// @param symbol The token's symbol
    /// @param _decimals The token's decimals
    function initialize(string memory name, string memory symbol, uint8 _decimals) external;

    /// @notice Mint this token to an address
    /// @param to The address receiving token
    /// @param amount The amount of token minted
    /// @dev Only the market can mint TermMax tokens
    function mint(address to, uint256 amount) external;

    /// @notice Return the market's address
    function marketAddr() external view returns (address);

    /// @notice Burn tokens from sender
    /// @param amount The number of tokens to be burned
    /// @dev Only the market can burn TermMax tokens
    function burn(uint256 amount) external;

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}
IGearingToken.sol 125 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import {IERC20Metadata, IERC20} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IERC721Enumerable} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import {GtConfig} from "../storage/TermMaxStorage.sol";

/**
 * @title TermMax Gearing token interface
 * @author Term Structure Labs
 */
interface IGearingToken is IERC721Enumerable {
    // @notice Initial function
    /// @param name The token's name
    /// @param symbol The token's symbol
    /// @param config Configuration of GT
    /// @param initalParams The initilization parameters of implementation
    function initialize(string memory name, string memory symbol, GtConfig memory config, bytes memory initalParams)
        external;

    /// @notice Set the treasurer address
    /// @param treasurer New address of treasurer
    /// @dev Only the market can call this function
    function setTreasurer(address treasurer) external;

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

    /// @notice Return the configuration of Gearing Token
    function getGtConfig() external view returns (GtConfig memory);

    /// @notice Return the flag to indicate debt is liquidatable or not
    function liquidatable() external view returns (bool);

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

    /// @notice Mint this token to an address
    /// @param  collateralProvider Who provide collateral token
    /// @param  to The address receiving token
    /// @param  debtAmt The amount of debt, unit by debtToken token
    /// @param  collateralData The encoded data of collateral
    /// @return id The id of Gearing Token
    /// @dev Only the market can mint Gearing Token
    function mint(address collateralProvider, address to, uint128 debtAmt, bytes memory collateralData)
        external
        returns (uint256 id);

    /// @notice Augment the debt of Gearing Token
    /// @param  id The id of Gearing Token
    /// @param  ftAmt The amount of debt, unit by debtToken token
    function augmentDebt(address caller, uint256 id, uint256 ftAmt) external;

    /// @notice Return the loan information of Gearing Token
    /// @param  id The id of Gearing Token
    /// @return owner The owner of Gearing Token
    /// @return debtAmt The amount of debt, unit by debtToken token
    /// @return collateralData The encoded data of collateral
    function loanInfo(uint256 id) external view returns (address owner, uint128 debtAmt, bytes memory collateralData);

    /// @notice Merge multiple Gearing Tokens into one
    /// @param  ids The array of Gearing Tokens to be merged
    /// @return newId The id of new Gearing Token
    function merge(uint256[] memory ids) external returns (uint256 newId);

    /// @notice Repay the debt of Gearing Token.
    ///         If repay amount equals the debt amount, Gearing Token's owner will get his collateral.
    /// @param id The id of Gearing Token
    /// @param repayAmt The amount of debt you want to repay
    /// @param byDebtToken Repay using debtToken token or bonds token
    function repay(uint256 id, uint128 repayAmt, bool byDebtToken) external;

    /// @notice Repay the debt of Gearing Token,
    ///         the collateral will send by flashloan first.
    /// @param id The id of Gearing Token
    /// @param byDebtToken Repay using debtToken token or bonds token
    function flashRepay(uint256 id, bool byDebtToken, bytes calldata callbackData) external;

    /// @notice Remove collateral from the loan.
    ///         Require the loan to value bigger than maxLtv after this action.
    /// @param id The id of Gearing Token
    /// @param collateralData Collateral data to be removed
    function removeCollateral(uint256 id, bytes memory collateralData) external;

    /// @notice Add collateral to the loan
    /// @param id The id of Gearing Token
    /// @param collateralData Collateral data to be added
    function addCollateral(uint256 id, bytes memory collateralData) external;

    /// @notice Return the liquidation info of the loan
    /// @param  id The id of the G-token
    /// @return isLiquidable Whether the loan is liquidable
    /// @return ltv The loan to collateral
    /// @return maxRepayAmt The maximum amount of the debt to be repaid
    function getLiquidationInfo(uint256 id)
        external
        view
        returns (bool isLiquidable, uint128 ltv, uint128 maxRepayAmt);

    /// @notice Liquidate the loan when its ltv bigger than liquidationLtv or expired.
    ///         The ltv can not inscrease after liquidation.
    ///         A maximum of 10% of the repayment amount of collateral is given as a
    ///         reward to the protocol and liquidator,
    ///         The proportion of collateral liquidated will not exceed the debt liquidation ratio.
    /// @param  id The id of the G-token
    /// @param  repayAmt The amount of the debt to be liquidate
    /// @param  byDebtToken Repay using debtToken token or bonds token
    function liquidate(uint256 id, uint128 repayAmt, bool byDebtToken) external;

    /// @notice Preview the delivery data
    /// @param  proportion The proportion of collateral that should be obtained
    /// @return deliveryData The delivery data
    function previewDelivery(uint256 proportion) external view returns (bytes memory deliveryData);

    /// @notice Deilivery outstanding debts after maturity
    /// @param  proportion The proportion of collateral that should be obtained
    /// @param  to The address receiving collateral token
    /// @dev    Only the market can delivery collateral
    function delivery(uint256 proportion, address to) external returns (bytes memory deliveryData);

    /// @notice Return the value of collateral in USD with base decimals
    /// @param collateralData encoded collateral data
    /// @return collateralValue collateral's value in USD
    function getCollateralValue(bytes memory collateralData) external view returns (uint256 collateralValue);
}
AggregatorV3Interface.sol 20 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// solhint-disable-next-line interface-starts-with-i
interface AggregatorV3Interface {
  function decimals() external view returns (uint8);

  function description() external view returns (string memory);

  function version() external view returns (uint256);

  function getRoundData(
    uint80 _roundId
  ) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);

  function latestRoundData()
    external
    view
    returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}
IERC721Enumerable.sol 29 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Enumerable.sol)

pragma solidity ^0.8.20;

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

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {
    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}
IERC721.sol 135 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC-721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC-721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
     *   {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Read Contract

TERMMAX_VAULT_IMPLEMENTATION 0xc65b512d → address
predictVaultAddress 0x6aec18e7 → address

Write Contract 1 functions

These functions modify contract state and require a wallet transaction to execute.

createVault 0x50c227ec
tuple initialParams
uint256 salt
returns: address

Recent Transactions

No transactions found for this address