FlashLoanOrchestrator

Description:

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

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

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

import "./strategies/AaveStrategy.sol";
import "./PermissionsManager.sol";

// Official protocol interfaces
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "lib/pendle-core-v2-public/contracts/interfaces/IPAllActionV3.sol";
import "lib/pendle-core-v2-public/contracts/interfaces/IPAllActionTypeV3.sol";
import "lib/morpho-blue/src/interfaces/IMorpho.sol";
import "lib/morpho-blue/src/interfaces/IMorphoCallbacks.sol";

// Using official Pendle types

/// @title FlashLoanOrchestrator
/// @notice Flash loan based leveraged position orchestrator using Morpho and Pendle
contract FlashLoanOrchestrator is IMorphoFlashLoanCallback {
    /*//////////////////////////////////////////////////////////////
                              CONSTANTS
    //////////////////////////////////////////////////////////////*/

    uint256 public constant SAFE_BUFFER = 100; // wei

    /*//////////////////////////////////////////////////////////////
                              IMMUTABLES
    //////////////////////////////////////////////////////////////*/

    AaveStrategy public immutable AAVE_STRATEGY;
    IMorpho public immutable MORPHO;
    IPAllActionV3 public immutable PENDLE_ROUTER;
    PermissionsManager public immutable PERMISSIONS;

    /*//////////////////////////////////////////////////////////////
                              STORAGE
    //////////////////////////////////////////////////////////////*/

    // Temporary storage for flash loan execution - optimized packing
    struct FlashLoanData {
        address caller; // 20 bytes
        uint96 userInputAmount; // 12 bytes } slot 1 (32 bytes total)
        address inputToken; // 20 bytes
        uint96 borrowAmount; // 12 bytes } slot 2 (32 bytes total)
        address outputToken; // 20 bytes } slot 3 (20 bytes)
        bytes pendleTxBytes; // dynamic   } slot 4+
    }

    FlashLoanData private flashLoanData;

    /*//////////////////////////////////////////////////////////////
                                EVENTS
    //////////////////////////////////////////////////////////////*/

    event FlashLoanPositionEntered(
        address indexed caller,
        address indexed inputToken,
        address indexed outputToken,
        uint256 flashLoanAmount,
        uint96 userInputAmount,
        uint256 finalSuppliedAmount,
        uint96 finalBorrowedAmount
    );

    event DebugSwapExecution(
        address inputToken,
        address outputToken,
        uint256 inputBalance,
        address contractAddress,
        address pendleRouter
    );

    /*//////////////////////////////////////////////////////////////
                                ERRORS
    //////////////////////////////////////////////////////////////*/

    error InvalidAsset();
    error InvalidMarket();
    error InvalidAmount();
    error TransferFailed();
    error UnauthorizedCallback();
    error InsufficientRepayment();
    error SwapFailed();

    /*//////////////////////////////////////////////////////////////
                               MODIFIERS
    //////////////////////////////////////////////////////////////*/

    /// @notice Restricts function access to authorized callers only
    modifier onlyAuthorized() {
        if (!PERMISSIONS.isAuthorized(msg.sender)) {
            revert("Unauthorized caller");
        }
        _;
    }

    /*//////////////////////////////////////////////////////////////
                            CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    /// @notice Deploy orchestrator with strategy and protocol addresses
    /// @param permissions Address of the permissions manager contract
    /// @param aaveStrategy Deployed Aave strategy address
    /// @param morpho Morpho protocol address
    /// @param pendleRouter Pendle Router V4 address
    constructor(
        address permissions,
        address aaveStrategy,
        address morpho,
        address pendleRouter
    ) {
        require(
            permissions != address(0) &&
                aaveStrategy != address(0) &&
                morpho != address(0) &&
                pendleRouter != address(0),
            "Invalid addresses"
        );

        PERMISSIONS = PermissionsManager(permissions);
        AAVE_STRATEGY = AaveStrategy(aaveStrategy);
        MORPHO = IMorpho(morpho);
        PENDLE_ROUTER = IPAllActionV3(pendleRouter);
    }

    /*//////////////////////////////////////////////////////////////
                            MAIN FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Execute leveraged position using flash loan with raw Pendle API transaction bytes
    /// @param caller Caller address
    /// @param inputToken Token to flash loan (e.g., USDC)
    /// @param outputToken Token to get from Pendle (e.g., PT-USDe)
    /// @param flashLoanAmount Amount to flash loan
    /// @param userInputAmount Amount of inputToken user provides (max ~79B tokens with 18 decimals)
    /// @param borrowAmount Amount to borrow from Aave (max ~79B tokens with 18 decimals)
    /// @param pendleTxBytes Raw transaction bytes from Pendle API (routes[0].tx field with caller as receiver)
    function executeFlashLoanPosition(
        address caller,
        address inputToken,
        address outputToken,
        uint256 flashLoanAmount,
        uint96 userInputAmount,
        uint96 borrowAmount,
        bytes calldata pendleTxBytes
    ) external onlyAuthorized {
        // Validation
        if (inputToken == address(0) || outputToken == address(0))
            revert InvalidAsset();
        if (
            pendleTxBytes.length == 0 ||
            flashLoanAmount == 0 ||
            borrowAmount == 0
        ) revert InvalidAmount();

        // Transfer user's input tokens to this contract
        bool success = IERC20(inputToken).transferFrom(
            caller,
            address(this),
            userInputAmount
        );
        if (!success) revert TransferFailed();

        // Store flash loan execution data
        flashLoanData = FlashLoanData({
            caller: caller,
            inputToken: inputToken,
            outputToken: outputToken,
            userInputAmount: userInputAmount,
            borrowAmount: borrowAmount,
            pendleTxBytes: pendleTxBytes
        });

        // Initiate flash loan
        MORPHO.flashLoan(inputToken, flashLoanAmount, "");
    }

    /// @notice Morpho flash loan callback - executes the leveraged position logic
    /// @param assets The flash loan amount
    function onMorphoFlashLoan(
        uint256 assets,
        bytes calldata /* data */
    ) external override {
        // Ensure this is called by Morpho
        if (msg.sender != address(MORPHO)) revert UnauthorizedCallback();

        FlashLoanData memory params = flashLoanData;

        // Step 1: We now have flashLoanAmount of inputToken + user input amount
        // Total available = flashLoanAmount + userInputAmount

        // Step 2: Execute Pendle swap using raw transaction bytes from API (no encoding/decoding issues)
        uint256 outputTokenAmount = _executePendleSwapWithRawTx(
            params.pendleTxBytes,
            params.outputToken
        );

        // Step 3: Supply outputToken to Aave as collateral on behalf of user
        // User immediately owns the aTokens (Aave "Supply On Behalf" pattern)
        _supplyToAave(params.outputToken, outputTokenAmount, params.caller);

        // Step 4: Borrow on behalf of user (requires debt delegation)
        // This is standard Aave pattern for borrowing on behalf of another
        uint256 borrowedAmount = _borrowFromAave(
            params.inputToken,
            params.borrowAmount,
            params.caller
        );

        // Step 5: Approve Morpho to pull back the flash loan amount
        IERC20(params.inputToken).approve(address(MORPHO), assets);

        // Verify we have enough to repay (borrowed amount + user input should cover flash loan)
        uint256 contractBalance = IERC20(params.inputToken).balanceOf(
            address(this)
        );
        if (contractBalance < assets) revert InsufficientRepayment();

        // Note: After flash loan repayment, user will have:
        // - PT tokens as collateral in Aave
        // - Debt of borrowAmount in Aave
        // - Net effect: User leveraged their capital to get leveraged PT exposure

        // Clean up storage
        delete flashLoanData;

        emit FlashLoanPositionEntered(
            params.caller,
            params.inputToken,
            params.outputToken,
            assets,
            params.userInputAmount,
            outputTokenAmount,
            uint96(borrowedAmount)
        );
    }

    /*//////////////////////////////////////////////////////////////
                          INTERNAL FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Execute Pendle swap using raw transaction bytes from API
    /// @param pendleTxBytes Raw transaction bytes from Pendle API (routes[0].tx field)
    /// @param outputToken Expected output token address
    /// @return amountOut Amount of output tokens received
    function _executePendleSwapWithRawTx(
        bytes memory pendleTxBytes,
        address outputToken
    ) internal returns (uint256 amountOut) {
        // Cache input token from storage and get balance (reduced external calls)
        address inputToken = flashLoanData.inputToken;
        uint256 inputBalance = IERC20(inputToken).balanceOf(address(this));

        // Approve Pendle Router to spend input tokens
        IERC20(inputToken).approve(address(PENDLE_ROUTER), inputBalance);

        // Debug: Log key information for debugging
        emit DebugSwapExecution(
            inputToken,
            outputToken,
            inputBalance,
            address(this), // our contract address
            address(PENDLE_ROUTER)
        );

        // Track contract's output token balance before swap (optimized)
        uint256 contractBalanceBefore = IERC20(outputToken).balanceOf(
            address(this)
        );

        // Execute Pendle swap using raw transaction bytes
        (bool success, bytes memory result) = address(PENDLE_ROUTER).call(
            pendleTxBytes
        );
        if (!success) {
            // Extract revert reason if available
            if (result.length > 0) {
                assembly {
                    revert(add(result, 32), mload(result))
                }
            }
            revert SwapFailed();
        }

        // Check if tokens came to contract directly or need to be pulled from receiver
        uint256 contractBalanceAfter = IERC20(outputToken).balanceOf(
            address(this)
        );

        if (contractBalanceAfter > contractBalanceBefore) {
            // Tokens came directly to contract - optimal path (saves gas)
            amountOut = contractBalanceAfter - contractBalanceBefore;
        } else {
            // Tokens went to receiver - need to transfer back (fallback path)
            address caller = flashLoanData.caller;
            uint256 receiverBalance = IERC20(outputToken).balanceOf(caller);

            if (receiverBalance == 0) revert SwapFailed();

            // Transfer from receiver to contract
            bool transferSuccess = IERC20(outputToken).transferFrom(
                caller,
                address(this),
                receiverBalance
            );
            if (!transferSuccess) revert TransferFailed();

            amountOut = receiverBalance;
        }

        if (amountOut == 0) revert SwapFailed();

        // Note: We don't clean up approvals to save gas
        // Pendle Router is trusted and any remaining approval will be overwritten on next use
    }

    /// @notice Supply tokens to Aave on behalf of user
    /// @param asset Asset to supply
    /// @param amount Amount to supply
    /// @param onBehalfOf User address
    function _supplyToAave(
        address asset,
        uint256 amount,
        address onBehalfOf
    ) internal {
        IERC20(asset).approve(address(AAVE_STRATEGY), amount);
        AAVE_STRATEGY.supply(asset, amount, onBehalfOf);
    }

    /// @notice Borrow tokens from Aave on behalf of user
    /// @param asset Asset to borrow
    /// @param amount Amount to borrow
    /// @param onBehalfOf User address
    /// @return actualAmount Actual amount borrowed
    function _borrowFromAave(
        address asset,
        uint256 amount,
        address onBehalfOf
    ) internal returns (uint256 actualAmount) {
        return AAVE_STRATEGY.borrow(asset, amount, onBehalfOf);
    }

    /*//////////////////////////////////////////////////////////////
                           VIEW FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Get protocol addresses
    function getProtocols()
        external
        view
        returns (address aave, address morpho, address pendleRouter)
    {
        return (
            address(AAVE_STRATEGY),
            address(MORPHO),
            address(PENDLE_ROUTER)
        );
    }

    /// @notice Get user account data from Aave strategy
    /// @param user User address to check
    function getUserAccountData(
        address user
    )
        external
        view
        returns (
            uint256 totalCollateralETH,
            uint256 totalDebtETH,
            uint256 availableBorrowsETH,
            uint256 currentLiquidationThreshold,
            uint256 ltv,
            uint256 healthFactor
        )
    {
        return AAVE_STRATEGY.getUserAccountData(user);
    }

    /*//////////////////////////////////////////////////////////////
                           EMERGENCY FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Emergency withdraw any ERC20 token
    /// @param token Token address to withdraw
    function emergencyWithdraw(address token) external onlyAuthorized {
        uint256 balance = IERC20(token).balanceOf(address(this));
        if (balance > 0) {
            // Transfer to the admin of the permissions contract
            address admin = PERMISSIONS.admin();
            bool success = IERC20(token).transfer(admin, balance);
            if (!success) revert TransferFailed();
        }
    }
}
"
    },
    "src/strategies/AaveStrategy.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "../interfaces/IAavePool.sol";
import "../interfaces/IAaveDataProvider.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "../PermissionsManager.sol";

/// @title AaveStrategy
/// @notice Flexible Aave lending strategy with dynamic asset support and permissions
contract AaveStrategy {
    /*//////////////////////////////////////////////////////////////
                              IMMUTABLES
    //////////////////////////////////////////////////////////////*/

    IAavePool public immutable AAVE_POOL;
    IAaveDataProvider public immutable AAVE_DATA_PROVIDER;
    PermissionsManager public immutable PERMISSIONS;

    /*//////////////////////////////////////////////////////////////
                              CONSTANTS
    //////////////////////////////////////////////////////////////*/

    uint16 public constant REFERRAL_CODE = 0;
    uint256 public constant VARIABLE_DEBT = 2;

    /*//////////////////////////////////////////////////////////////
                                EVENTS
    //////////////////////////////////////////////////////////////*/

    event AssetSupplied(
        address indexed asset,
        uint256 amount,
        address indexed onBehalfOf
    );
    event AssetWithdrawn(
        address indexed asset,
        uint256 amount,
        address indexed to
    );
    event AssetBorrowed(
        address indexed asset,
        uint256 amount,
        address indexed onBehalfOf
    );
    event AssetRepaid(
        address indexed asset,
        uint256 amount,
        address indexed onBehalfOf
    );
    event EmodeSet(address indexed user, uint8 categoryId);

    /*//////////////////////////////////////////////////////////////
                                ERRORS
    //////////////////////////////////////////////////////////////*/

    error InvalidAsset();
    error InvalidAmount();
    error TransferFailed();

    /*//////////////////////////////////////////////////////////////
                               MODIFIERS
    //////////////////////////////////////////////////////////////*/

    /// @notice Restricts function access to authorized callers only
    modifier onlyAuthorized() {
        if (!PERMISSIONS.isAuthorized(msg.sender)) {
            revert("Unauthorized caller");
        }
        _;
    }

    /*//////////////////////////////////////////////////////////////
                            CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    /// @notice Deploy Aave strategy with protocol addresses and permissions
    /// @param permissions Address of the permissions manager contract
    /// @param aavePool Aave lending pool address
    /// @param aaveDataProvider Aave protocol data provider address
    constructor(
        address permissions,
        address aavePool,
        address aaveDataProvider
    ) {
        require(permissions != address(0), "Invalid permissions");
        require(aavePool != address(0), "Invalid pool");
        require(aaveDataProvider != address(0), "Invalid data provider");
        PERMISSIONS = PermissionsManager(permissions);
        AAVE_POOL = IAavePool(aavePool);
        AAVE_DATA_PROVIDER = IAaveDataProvider(aaveDataProvider);
    }

    /*//////////////////////////////////////////////////////////////
                        LENDING OPERATIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Supply any asset to Aave
    /// @param asset Asset address to supply
    /// @param amount Amount to supply
    /// @param onBehalfOf Address to supply on behalf of
    function supply(
        address asset,
        uint256 amount,
        address onBehalfOf
    ) external onlyAuthorized returns (uint256) {
        if (asset == address(0)) revert InvalidAsset();
        if (amount == 0) revert InvalidAmount();

        IERC20(asset).transferFrom(msg.sender, address(this), amount);
        IERC20(asset).approve(address(AAVE_POOL), amount);

        AAVE_POOL.supply(asset, amount, onBehalfOf, REFERRAL_CODE);

        emit AssetSupplied(asset, amount, onBehalfOf);
        return amount;
    }

    /// @notice Borrow any asset from Aave
    /// @param asset Asset address to borrow
    /// @param amount Amount to borrow
    /// @param onBehalfOf Address to borrow on behalf of
    function borrow(
        address asset,
        uint256 amount,
        address onBehalfOf
    ) external onlyAuthorized returns (uint256) {
        if (asset == address(0)) revert InvalidAsset();
        if (amount == 0) revert InvalidAmount();

        AAVE_POOL.borrow(
            asset,
            amount,
            VARIABLE_DEBT,
            REFERRAL_CODE,
            onBehalfOf
        );

        // Transfer borrowed amount to caller
        bool success = IERC20(asset).transfer(msg.sender, amount);
        if (!success) revert TransferFailed();

        emit AssetBorrowed(asset, amount, onBehalfOf);
        return amount;
    }

    /// @notice Set eMode category for the calling contract
    /// @param categoryId eMode category ID (27 for PT-USDe Stablecoins Nov 2025)
    /// @dev This sets eMode for the caller (msg.sender) - used when contract opens positions in its own name
    function setContractEMode(uint8 categoryId) external onlyAuthorized {
        AAVE_POOL.setUserEMode(categoryId);
        emit EmodeSet(msg.sender, categoryId);
    }

    /*//////////////////////////////////////////////////////////////
                            VIEW FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Get user account data from Aave
    /// @param user User address to check
    function getUserAccountData(
        address user
    )
        external
        view
        returns (
            uint256 totalCollateral,
            uint256 totalDebt,
            uint256 availableBorrows,
            uint256 currentLiquidationThreshold,
            uint256 ltv,
            uint256 healthFactor
        )
    {
        return AAVE_POOL.getUserAccountData(user);
    }

    /// @notice Get reserve configuration for an asset
    /// @param asset Asset address to check
    function getAssetLTV(address asset) external view returns (uint256) {
        if (asset == address(0)) revert InvalidAsset();

        (, uint256 ltv, , , , , , , , ) = AAVE_POOL.getConfiguration(asset);
        return ltv;
    }

    /// @notice Get reserve caps for an asset (supply cap and borrow cap)
    /// @param asset Asset address to check
    /// @return borrowCap The borrow cap in asset units
    /// @return supplyCap The supply cap in asset units
    function getReserveCaps(
        address asset
    ) external view returns (uint256 borrowCap, uint256 supplyCap) {
        if (asset == address(0)) revert InvalidAsset();

        (borrowCap, supplyCap) = AAVE_DATA_PROVIDER.getReserveCaps(asset);

        // Convert to asset units
        uint8 assetDecimals = IERC20Metadata(asset).decimals();
        borrowCap = borrowCap * 10 ** assetDecimals;
        supplyCap = supplyCap * 10 ** assetDecimals;
    }

    /// @notice Get current total supply for an asset (total aTokens)
    /// @param asset Asset address to check
    /// @return totalSupply Current total supply of the asset in Aave
    function getTotalSupply(
        address asset
    ) external view returns (uint256 totalSupply) {
        if (asset == address(0)) revert InvalidAsset();

        return AAVE_DATA_PROVIDER.getATokenTotalSupply(asset);
    }

    /// @notice Get the debt token address for an asset
    /// @param asset The asset address
    /// @return The variable debt token address
    function getDebtToken(address asset) external view returns (address) {
        (, , address variableDebtToken) = AAVE_DATA_PROVIDER
            .getReserveTokensAddresses(asset);
        return variableDebtToken;
    }

    /// @notice Get the aToken address for an asset
    /// @param asset The asset address
    /// @return The aToken address
    function getAToken(address asset) external view returns (address) {
        (address aToken, , ) = AAVE_DATA_PROVIDER.getReserveTokensAddresses(
            asset
        );
        return aToken;
    }
}
"
    },
    "src/PermissionsManager.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

/// @title PermissionsManager
/// @notice Manages admin and whitelisted caller permissions for the lending system
contract PermissionsManager {
    /*//////////////////////////////////////////////////////////////
                                STORAGE
    //////////////////////////////////////////////////////////////*/

    /// @notice The admin address who can manage permissions
    address public admin;

    /// @notice Mapping of whitelisted callers
    mapping(address => bool) public whitelistedCallers;

    /*//////////////////////////////////////////////////////////////
                                EVENTS
    //////////////////////////////////////////////////////////////*/

    event AdminUpdated(address indexed oldAdmin, address indexed newAdmin);
    event CallerWhitelisted(address indexed caller);
    event CallerRemovedFromWhitelist(address indexed caller);

    /*//////////////////////////////////////////////////////////////
                                ERRORS
    //////////////////////////////////////////////////////////////*/

    error OnlyAdmin();
    error UnauthorizedCaller();
    error AdminZeroAddress();
    error CallerAlreadyWhitelisted();
    error CallerNotWhitelisted();

    /*//////////////////////////////////////////////////////////////
                               MODIFIERS
    //////////////////////////////////////////////////////////////*/

    /// @notice Restricts function access to admin only
    modifier onlyAdmin() {
        if (msg.sender != admin) revert OnlyAdmin();
        _;
    }

    /// @notice Restricts function access to whitelisted callers only
    modifier onlyAuthorized() {
        if (!whitelistedCallers[msg.sender]) revert UnauthorizedCaller();
        _;
    }

    /*//////////////////////////////////////////////////////////////
                              CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    /// @notice Constructor sets the initial admin
    /// @param _admin The initial admin address
    constructor(address _admin) {
        if (_admin == address(0)) revert AdminZeroAddress();
        admin = _admin;

        // Admin is automatically whitelisted
        whitelistedCallers[_admin] = true;

        emit AdminUpdated(address(0), _admin);
        emit CallerWhitelisted(_admin);
    }

    /*//////////////////////////////////////////////////////////////
                           ADMIN FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Updates the admin address
    /// @param newAdmin The new admin address
    function updateAdmin(address newAdmin) external onlyAdmin {
        if (newAdmin == address(0)) revert AdminZeroAddress();

        address oldAdmin = admin;
        admin = newAdmin;

        // Automatically whitelist new admin
        whitelistedCallers[newAdmin] = true;

        emit AdminUpdated(oldAdmin, newAdmin);
        emit CallerWhitelisted(newAdmin);
    }

    /// @notice Adds a caller to the whitelist
    /// @param caller The address to whitelist
    function addWhitelistedCaller(address caller) external onlyAdmin {
        if (whitelistedCallers[caller]) revert CallerAlreadyWhitelisted();

        whitelistedCallers[caller] = true;
        emit CallerWhitelisted(caller);
    }

    /// @notice Removes a caller from the whitelist
    /// @param caller The address to remove from whitelist
    function removeWhitelistedCaller(address caller) external onlyAdmin {
        if (!whitelistedCallers[caller]) revert CallerNotWhitelisted();
        if (caller == admin) revert OnlyAdmin(); // Cannot remove admin from whitelist

        whitelistedCallers[caller] = false;
        emit CallerRemovedFromWhitelist(caller);
    }

    /*//////////////////////////////////////////////////////////////
                            VIEW FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Checks if a caller is authorized (whitelisted)
    /// @param caller The address to check
    /// @return True if the caller is whitelisted
    function isAuthorized(address caller) external view returns (bool) {
        return whitelistedCallers[caller];
    }

    /// @notice Gets the current admin address
    /// @return The admin address
    function getAdmin() external view returns (address) {
        return admin;
    }
}
"
    },
    "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)

pragma solidity >=0.4.16;

/**
 * @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);
}
"
    },
    "lib/pendle-core-v2-public/contracts/interfaces/IPAllActionV3.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.8.0;

import "./IPActionAddRemoveLiqV3.sol";
import "./IPActionSwapPTV3.sol";
import "./IPActionSwapYTV3.sol";
import "./IPActionMiscV3.sol";
import "./IPActionCallbackV3.sol";
import "./IPActionStorageV4.sol";
import "./IPActionSimple.sol";

interface IPAllActionV3 is
    IPActionAddRemoveLiqV3,
    IPActionSwapPTV3,
    IPActionSwapYTV3,
    IPActionMiscV3,
    IPActionCallbackV3,
    IPActionStorageV4,
    IPActionSimple
{}
"
    },
    "lib/pendle-core-v2-public/contracts/interfaces/IPAllActionTypeV3.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;

import "../router/swap-aggregator/IPSwapAggregator.sol";
import "./IPLimitRouter.sol";

/*
 * NOTICE:
 * For detailed information on TokenInput, TokenOutput, ApproxParams, and LimitOrderData,
 * refer to https://docs.pendle.finance/Developers/Contracts/PendleRouter
 *
 * It's recommended to use Pendle's Hosted SDK to generate these parameters for:
 * 1. Optimal liquidity and gas efficiency
 * 2. Access to deeper liquidity via limit orders
 * 3. Zapping in/out using any ERC20 token
 *
 * Else, to generate these parameters fully onchain, use the following functions:
 * - For TokenInput: Use createTokenInputSimple
 * - For TokenOutput: Use createTokenOutputSimple
 * - For ApproxParams: Use createDefaultApproxParams
 * - For LimitOrderData: Use createEmptyLimitOrderData
 *
 * These generated parameters can be directly passed into the respective function calls.
 *
 * Examples:
 *
 * addLiquiditySingleToken(
 *     msg.sender,
 *     MARKET_ADDRESS,
 *     minLpOut,
 *     createDefaultApproxParams(),
 *     createTokenInputSimple(USDC_ADDRESS, 1000e6),
 *     createEmptyLimitOrderData()
 * )
 *
 * swapExactTokenForPt(
 *     msg.sender,
 *     MARKET_ADDRESS,
 *     minPtOut,
 *     createDefaultApproxParams(),
 *     createTokenInputSimple(USDC_ADDRESS, 1000e6),
 *     createEmptyLimitOrderData()
 * )
 */

/// @dev Creates a TokenInput struct without using any swap aggregator
/// @param tokenIn must be one of the SY's tokens in (obtain via `IStandardizedYield#getTokensIn`)
/// @param netTokenIn amount of token in
function createTokenInputSimple(address tokenIn, uint256 netTokenIn) pure returns (TokenInput memory) {
    return
        TokenInput({
            tokenIn: tokenIn,
            netTokenIn: netTokenIn,
            tokenMintSy: tokenIn,
            pendleSwap: address(0),
            swapData: createSwapTypeNoAggregator()
        });
}

/// @dev Creates a TokenOutput struct without using any swap aggregator
/// @param tokenOut must be one of the SY's tokens out (obtain via `IStandardizedYield#getTokensOut`)
/// @param minTokenOut minimum amount of token out
function createTokenOutputSimple(address tokenOut, uint256 minTokenOut) pure returns (TokenOutput memory) {
    return
        TokenOutput({
            tokenOut: tokenOut,
            minTokenOut: minTokenOut,
            tokenRedeemSy: tokenOut,
            pendleSwap: address(0),
            swapData: createSwapTypeNoAggregator()
        });
}

function createEmptyLimitOrderData() pure returns (LimitOrderData memory) {}

/// @dev Creates default ApproxParams for on-chain approximation
function createDefaultApproxParams() pure returns (ApproxParams memory) {
    return ApproxParams({guessMin: 0, guessMax: type(uint256).max, guessOffchain: 0, maxIteration: 256, eps: 1e14});
}

function createSwapTypeNoAggregator() pure returns (SwapData memory) {}

struct TokenInput {
    address tokenIn;
    uint256 netTokenIn;
    address tokenMintSy;
    address pendleSwap;
    SwapData swapData;
}

struct TokenOutput {
    address tokenOut;
    uint256 minTokenOut;
    address tokenRedeemSy;
    address pendleSwap;
    SwapData swapData;
}

struct LimitOrderData {
    address limitRouter;
    uint256 epsSkipMarket;
    FillOrderParams[] normalFills;
    FillOrderParams[] flashFills;
    bytes optData;
}

struct ApproxParams {
    uint256 guessMin;
    uint256 guessMax;
    uint256 guessOffchain;
    uint256 maxIteration;
    uint256 eps;
}

struct ExitPreExpReturnParams {
    uint256 netPtFromRemove;
    uint256 netSyFromRemove;
    uint256 netPyRedeem;
    uint256 netSyFromRedeem;
    uint256 netPtSwap;
    uint256 netYtSwap;
    uint256 netSyFromSwap;
    uint256 netSyFee;
    uint256 totalSyOut;
}

struct ExitPostExpReturnParams {
    uint256 netPtFromRemove;
    uint256 netSyFromRemove;
    uint256 netPtRedeem;
    uint256 netSyFromRedeem;
    uint256 totalSyOut;
}

struct RedeemYtIncomeToTokenStruct {
    IPYieldToken yt;
    bool doRedeemInterest;
    bool doRedeemRewards;
    address tokenRedeemSy;
    uint256 minTokenRedeemOut;
}
"
    },
    "lib/morpho-blue/src/interfaces/IMorpho.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

type Id is bytes32;

struct MarketParams {
    address loanToken;
    address collateralToken;
    address oracle;
    address irm;
    uint256 lltv;
}

/// @dev Warning: For `feeRecipient`, `supplyShares` does not contain the accrued shares since the last interest
/// accrual.
struct Position {
    uint256 supplyShares;
    uint128 borrowShares;
    uint128 collateral;
}

/// @dev Warning: `totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalSupplyShares` does not contain the additional shares accrued by `feeRecipient` since the last
/// interest accrual.
struct Market {
    uint128 totalSupplyAssets;
    uint128 totalSupplyShares;
    uint128 totalBorrowAssets;
    uint128 totalBorrowShares;
    uint128 lastUpdate;
    uint128 fee;
}

struct Authorization {
    address authorizer;
    address authorized;
    bool isAuthorized;
    uint256 nonce;
    uint256 deadline;
}

struct Signature {
    uint8 v;
    bytes32 r;
    bytes32 s;
}

/// @dev This interface is used for factorizing IMorphoStaticTyping and IMorpho.
/// @dev Consider using the IMorpho interface instead of this one.
interface IMorphoBase {
    /// @notice The EIP-712 domain separator.
    /// @dev Warning: Every EIP-712 signed message based on this domain separator can be reused on another chain sharing
    /// the same chain id because the domain separator would be the same.
    function DOMAIN_SEPARATOR() external view returns (bytes32);

    /// @notice The owner of the contract.
    /// @dev It has the power to change the owner.
    /// @dev It has the power to set fees on markets and set the fee recipient.
    /// @dev It has the power to enable but not disable IRMs and LLTVs.
    function owner() external view returns (address);

    /// @notice The fee recipient of all markets.
    /// @dev The recipient receives the fees of a given market through a supply position on that market.
    function feeRecipient() external view returns (address);

    /// @notice Whether the `irm` is enabled.
    function isIrmEnabled(address irm) external view returns (bool);

    /// @notice Whether the `lltv` is enabled.
    function isLltvEnabled(uint256 lltv) external view returns (bool);

    /// @notice Whether `authorized` is authorized to modify `authorizer`'s position on all markets.
    /// @dev Anyone is authorized to modify their own positions, regardless of this variable.
    function isAuthorized(address authorizer, address authorized) external view returns (bool);

    /// @notice The `authorizer`'s current nonce. Used to prevent replay attacks with EIP-712 signatures.
    function nonce(address authorizer) external view returns (uint256);

    /// @notice Sets `newOwner` as `owner` of the contract.
    /// @dev Warning: No two-step transfer ownership.
    /// @dev Warning: The owner can be set to the zero address.
    function setOwner(address newOwner) external;

    /// @notice Enables `irm` as a possible IRM for market creation.
    /// @dev Warning: It is not possible to disable an IRM.
    function enableIrm(address irm) external;

    /// @notice Enables `lltv` as a possible LLTV for market creation.
    /// @dev Warning: It is not possible to disable a LLTV.
    function enableLltv(uint256 lltv) external;

    /// @notice Sets the `newFee` for the given market `marketParams`.
    /// @param newFee The new fee, scaled by WAD.
    /// @dev Warning: The recipient can be the zero address.
    function setFee(MarketParams memory marketParams, uint256 newFee) external;

    /// @notice Sets `newFeeRecipient` as `feeRecipient` of the fee.
    /// @dev Warning: If the fee recipient is set to the zero address, fees will accrue there and will be lost.
    /// @dev Modifying the fee recipient will allow the new recipient to claim any pending fees not yet accrued. To
    /// ensure that the current recipient receives all due fees, accrue interest manually prior to making any changes.
    function setFeeRecipient(address newFeeRecipient) external;

    /// @notice Creates the market `marketParams`.
    /// @dev Here is the list of assumptions on the market's dependencies (tokens, IRM and oracle) that guarantees
    /// Morpho behaves as expected:
    /// - The token should be ERC-20 compliant, except that it can omit return values on `transfer` and `transferFrom`.
    /// - The token balance of Morpho should only decrease on `transfer` and `transferFrom`. In particular, tokens with
    /// burn functions are not supported.
    /// - The token should not re-enter Morpho on `transfer` nor `transferFrom`.
    /// - The token balance of the sender (resp. receiver) should decrease (resp. increase) by exactly the given amount
    /// on `transfer` and `transferFrom`. In particular, tokens with fees on transfer are not supported.
    /// - The IRM should not re-enter Morpho.
    /// - The oracle should return a price with the correct scaling.
    /// @dev Here is a list of properties on the market's dependencies that could break Morpho's liveness properties
    /// (funds could get stuck):
    /// - The token can revert on `transfer` and `transferFrom` for a reason other than an approval or balance issue.
    /// - A very high amount of assets (~1e35) supplied or borrowed can make the computation of `toSharesUp` and
    /// `toSharesDown` overflow.
    /// - The IRM can revert on `borrowRate`.
    /// - A very high borrow rate returned by the IRM can make the computation of `interest` in `_accrueInterest`
    /// overflow.
    /// - The oracle can revert on `price`. Note that this can be used to prevent `borrow`, `withdrawCollateral` and
    /// `liquidate` from being used under certain market conditions.
    /// - A very high price returned by the oracle can make the computation of `maxBorrow` in `_isHealthy` overflow, or
    /// the computation of `assetsRepaid` in `liquidate` overflow.
    /// @dev The borrow share price of a market with less than 1e4 assets borrowed can be decreased by manipulations, to
    /// the point where `totalBorrowShares` is very large and borrowing overflows.
    function createMarket(MarketParams memory marketParams) external;

    /// @notice Supplies `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's
    /// `onMorphoSupply` function with the given `data`.
    /// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the
    /// caller is guaranteed to have `assets` tokens pulled from their balance, but the possibility to mint a specific
    /// amount of shares is given for full compatibility and precision.
    /// @dev Supplying a large amount can revert for overflow.
    /// @dev Supplying an amount of shares may lead to supply more or fewer assets than expected due to slippage.
    /// Consider using the `assets` parameter to avoid this.
    /// @param marketParams The market to supply assets to.
    /// @param assets The amount of assets to supply.
    /// @param shares The amount of shares to mint.
    /// @param onBehalf The address that will own the increased supply position.
    /// @param data Arbitrary data to pass to the `onMorphoSupply` callback. Pass empty data if not needed.
    /// @return assetsSupplied The amount of assets supplied.
    /// @return sharesSupplied The amount of shares minted.
    function supply(
        MarketParams memory marketParams,
        uint256 assets,
        uint256 shares,
        address onBehalf,
        bytes memory data
    ) external returns (uint256 assetsSupplied, uint256 sharesSupplied);

    /// @notice Withdraws `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`.
    /// @dev Either `assets` or `shares` should be zero. To withdraw max, pass the `shares`'s balance of `onBehalf`.
    /// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
    /// @dev Withdrawing an amount corresponding to more shares than supplied will revert for underflow.
    /// @dev It is advised to use the `shares` input when withdrawing the full position to avoid reverts due to
    /// conversion roundings between shares and assets.
    /// @param marketParams The market to withdraw assets from.
    /// @param assets The amount of assets to withdraw.
    /// @param shares The amount of shares to burn.
    /// @param onBehalf The address of the owner of the supply position.
    /// @param receiver The address that will receive the withdrawn assets.
    /// @return assetsWithdrawn The amount of assets withdrawn.
    /// @return sharesWithdrawn The amount of shares burned.
    function withdraw(
        MarketParams memory marketParams,
        uint256 assets,
        uint256 shares,
        address onBehalf,
        address receiver
    ) external returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn);

    /// @notice Borrows `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`.
    /// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the
    /// caller is guaranteed to borrow `assets` of tokens, but the possibility to mint a specific amount of shares is
    /// given for full compatibility and precision.
    /// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
    /// @dev Borrowing a large amount can revert for overflow.
    /// @dev Borrowing an amount of shares may lead to borrow fewer assets than expected due to slippage.
    /// Consider using the `assets` parameter to avoid this.
    /// @param marketParams The market to borrow assets from.
    /// @param assets The amount of assets to borrow.
    /// @param shares The amount of shares to mint.
    /// @param onBehalf The address that will own the increased borrow position.
    /// @param receiver The address that will receive the borrowed assets.
    /// @return assetsBorrowed The amount of assets borrowed.
    /// @return sharesBorrowed The amount of shares minted.
    function borrow(
        MarketParams memory marketParams,
        uint256 assets,
        uint256 shares,
        address onBehalf,
        address receiver
    ) external returns (uint256 assetsBorrowed, uint256 sharesBorrowed);

    /// @notice Repays `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's
    /// `onMorphoReplay` function with the given `data`.
    /// @dev Either `assets` or `shares` should be zero. To repay max, pass the `shares`'s balance of `onBehalf`.
    /// @dev Repaying an amount corresponding to more shares than borrowed will revert for underflow.
    /// @dev It is advised to use the `shares` input when repaying the full position to avoid reverts due to conversion
    /// roundings between shares and assets.
    /// @dev An attacker can front-run a repay with a small repay making the transaction revert for underflow.
    /// @param marketParams The market to repay assets to.
    /// @param assets The amount of assets to repay.
    /// @param shares The amount of shares to burn.
    /// @param onBehalf The address of the owner of the debt position.
    /// @param data Arbitrary data to pass to the `onMorphoRepay` callback. Pass empty data if not needed.
    /// @return assetsRepaid The amount of assets repaid.
    /// @return sharesRepaid The amount of shares burned.
    function repay(
        MarketParams memory marketParams,
        uint256 assets,
        uint256 shares,
        address onBehalf,
        bytes memory data
    ) external returns (uint256 assetsRepaid, uint256 sharesRepaid);

    /// @notice Supplies `assets` of collateral on behalf of `onBehalf`, optionally calling back the caller's
    /// `onMorphoSupplyCollateral` function with the given `data`.
    /// @dev Interest are not accrued since it's not required and it saves gas.
    /// @dev Supplying a large amount can revert for overflow.
    /// @param marketParams The market to supply collateral to.
    /// @param assets The amount of collateral to supply.
    /// @param onBehalf The address that will own the increased collateral position.
    /// @param data Arbitrary data to pass to the `onMorphoSupplyCollateral` callback. Pass empty data if not needed.
    function supplyCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, bytes memory data)
        external;

    /// @notice Withdraws `assets` of collateral on behalf of `onBehalf` and sends the assets to `receiver`.
    /// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
    /// @dev Withdrawing an amount corresponding to more collateral than supplied will revert for underflow.
    /// @param marketParams The market to withdraw collateral from.
    /// @param assets The amount of collateral to withdraw.
    /// @param onBehalf The address of the owner of the collateral position.
    /// @param receiver The address that will receive the collateral assets.
    function withdrawCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, address receiver)
        external;

    /// @notice Liquidates the given `repaidShares` of debt asset or seize the given `seizedAssets` of collateral on the
    /// given market `marketParams` of the given `borrower`'s position, optionally calling back the caller's
    /// `onMorphoLiquidate` function with the given `data`.
    /// @dev Either `seizedAssets` or `repaidShares` should be zero.
    /// @dev Seizing more than the collateral balance will underflow and revert without any error message.
    /// @dev Repaying more than the borrow balance will underflow and revert without any error message.
    /// @dev An attacker can front-run a liquidation with a small repay making the transaction revert for underflow.
    /// @param marketParams The market of the position.
    /// @param borrower The owner of the position.
    /// @param seizedAssets The amount of collateral to seize.
    /// @param repaidShares The amount of shares to repay.
    /// @param data Arbitrary data to pass to the `onMorphoLiquidate` callback. Pass empty data if not needed.
    /// @return The amount of assets seized.
    /// @return The amount of assets repaid.
    function liquidate(
        MarketParams memory marketParams,
        address borrower,
        uint256 seizedAssets,
        uint256 repaidShares,
        bytes memory data
    ) external returns (uint256, uint256);

    /// @notice Executes a flash loan.
    /// @dev Flash loans have access to the whole balance of the contract (the liquidity and deposited collateral of all
    /// markets combined, plus donations).
    /// @dev Warning: Not ERC-3156 compliant but compatibility is easily reached:
    /// - `flashFee` is zero.
    /// - `maxFlashLoan` is the token's balance of this contract.
    /// - The receiver of `assets` is the caller.
    /// @param token The token to flash loan.
    /// @param assets The amount of assets to flash loan.
    /// @param data Arbitrary data to pass to the `onMorphoFlashLoan` callback.
    function flashLoan(address token, uint256 assets, bytes calldata data) external;

    /// @notice Sets the authorization for `authorized` to manage `msg.sender`'s positions.
    /// @param authorized The authorized address.
    /// @param newIsAuthorized The new authorization status.
    function setAuthorization(address authorized, bool newIsAuthorized) external;

    /// @notice Sets the authorization for `authorization.authorized` to manage `authorization.authorizer`'s positions.
    /// @dev Warning: Reverts if the signature has already been submitted.
    /// @dev The signature is malleable, but it has no impact on the security here.
    /// @dev The nonce is passed as argument to be able to revert with a different error message.
    /// @param authorization The `Authorization` struct.
    /// @param signature The signature.
    function setAuthorizationWithSig(Authorization calldata authorization, Signature calldata signature) external;

    /// @notice Accrues interest for the given market `marketParams`.
    function accrueInterest(MarketParams memory marketParams) external;

    /// @notice Returns the data stored on the different `slots`.
    function extSloads(bytes32[] memory slots) external view returns (bytes32[] memory);
}

/// @dev This interface is inherited by Morpho so that function signatures are checked by the compiler.
/// @dev Consider using the IMorpho interface instead of this one.
interface IMorphoStaticTyping is IMorphoBase {
    /// @notice The state of the position of `user` on the market corresponding to `id`.
    /// @dev Warning: For `feeRecipient`, `supplyShares` does not contain the accrued shares since the last interest
    /// accrual.
    function position(Id id, address user)
        external
        view
        returns (uint256 supplyShares, uint128 borrowShares, uint128 collateral);

    /// @notice The state of the market corresponding to `id`.
    /// @dev Warning: `totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
    /// @dev Warning: `totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
    /// @dev Warning: `totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last interest
    /// accrual.
    function market(Id id)
        external
        view
        returns (
            uint128 totalSupplyAssets,
            uint128 totalSupplyShares,
            uint128 totalBorrowAssets,
            uint128 totalBorrowShares,
            uint128 lastUpdate,
            uint128 fee
        );

    /// @notice The market params corresponding to `id`.
    /// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer
    /// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`.
    function idToMarketParams(Id id)
        external
        view
        returns (address loanToken, address collateralToken, address oracle, address irm, uint256 lltv);
}

/// @title IMorpho
/// @author Morpho Labs
/// @custom:contact security@morpho.org
/// @dev Use this interface for Morpho to have access to all the functions with the appropriate function signatures.
interface IMorpho is IMorphoBase {
    /// @notice The state of the position of `user` on the market corresponding to `id`.
    /// @dev Warning: For `feeRecipient`, `p.supplyShares` does not contain the accrued shares since the last interest
    /// accrual.
    function position(Id id, address user) external view returns (Position memory p);

    /// @notice The state of the market corresponding to `id`.
    /// @dev Warning: `m.totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
    /// @dev Warning: `m.totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
    /// @dev Warning: `m.totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last
    /// interest accrual.
    function market(Id id) external view returns (Market memory m);

    /// @notice The market params corresponding to `id`.
    /// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer
    /// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`.
    function idToMarketParams(Id id) external view returns (MarketParams memory);
}
"
    },
    "lib/morpho-blue/src/interfaces/IMorphoCallbacks.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title IMorphoLiquidateCallback
/// @notice Interface that liquidators willing to use `liquidate`'s callback must implement.
interface IMorphoLiquidateCallback {
    /// @notice Callback called when a liquidation occurs.
    /// @dev The callback is called only if data is not empty.
    /// @param repaidAssets The amount of repaid assets.
    /// @param data Arbitrary data passed to the `liquidate` function.
    function onMorphoLiquidate(uint256 repaidAssets, bytes calldata data) external;
}

/// @title IMorphoRepayCallback
/// @notice Interface that users willing to use `repay`'s callback must implement.
interface IMorphoRepayCallback {
    /// @notice Callback called when a repayment occurs.
    /// @dev The callback is called only if data is not empty.
    /// @param assets The amount of repaid assets.
    /// @param data Arbitrary data passed to the `repay` function.
    function onMorphoRepay(uint256 assets, bytes calldata data) external;
}

/// @title IMorphoSupplyCallback
/// @notice Interface that users willing to use `supply`'s callback must implement.
interface IMorphoSupplyCallback {
    /// @notice Callback called when a supply occurs.
    /// @dev The callback is called only if data is not empty.
    /// @param assets The amount of supplied assets.
    /// @param data Arbitrary data passed to the `supply` function.
    function onMorphoSupply(uint256 assets, bytes calldata data) external;
}

/// @title IMorphoSupplyCollateralCallback
/// @notice Interface that users willing to use `supplyCollateral`'s callback must implement.
interface IMorphoSupplyCollateralCallback {
    /// @notice Callback called when a supply of collateral occurs.
    /// @dev The callback is called only if data is not empty.
    /// @param assets The amount of supplied collateral.
    /// @param data Arbitrary data passed to the `supplyCollateral` function.
    function onMorphoSupplyCollateral(uint256 assets, bytes calldata data) external;
}

/// @title IMorphoFlashLoanCallback
/// @notice Interface that users willing to use `flashLoan`'s callback must implement.
interface IMorphoFlashLoanCallback {
    /// @notice Callback called when a flash loan occurs.
    /// @dev The callback is called only if data is not empty.
    /// @param assets The amount of assets that was flash loaned.
    /// @param data Arbitrary data passed to the `flashLoan` function.
    function onMorphoFlashLoan(uint256 assets, bytes calldata data) external;
}
"
    },
    "src/interfaces/IAavePool.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

/// @title IAavePool
/// @notice Interface for Aave V3 Pool contract
interface IAavePool {
    /// @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
    /// @param asset The address of the underlying asset to supply
    /// @param amount The amount to be supplied
    /// @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user wants to receive them on his own wallet, or a different address if the beneficiary of aTokens is a different wallet
    /// @param referralCode Code used to register the integrator originating the operation, for potential rewards from the Aave protocol
    function supply(
        address asset,
        uint256 amount,
        address onBehalfOf,
        uint16 referralCode
    ) external;

    /// @notice Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower already supplied enough collateral
    /// @param asset The address of the underlying asset to borrow
    /// @param amount The amount to be borrowed
    /// @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable
    /// @param referralCode Code used to register the integrator originating the operation, for potential rewards from the Aave protocol
    /// @param onBehalfOf The address of the user who will receive the debt. Should be the address of the borrower itself calling the function if he wants to borrow against his own collateral, or the address of the credit delegator if he has been given credit delegation allowance to msg.sender
    function borrow(
        address asset,
        uint256 amount,
        uint256 interestRateMode,
        uint16 referralCode,
        address onBehalfOf
    ) external;

    /// @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned
    /// @param asset The address of the borrowed underlying asset previously borrowed
    /// @param amount The amount to repay
    /// - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
    /// @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
    /// @param onBehalfOf The address of the user who will get his debt reduced/removed. Should be the address of the user calling the function if he wants to reduce/remove his own debt, or the address of any other other borrower whose debt should be removed
    /// @return The final amount repaid
    function repay(
        address asset,
        uint256 amount,
        uint256 interestRateMode,
        address onBehalfOf
    ) external returns (uint256);

    /// @notice Allows suppliers to enable/disable a specific supplied asset as collateral
    /// @param asset The address of the underlying asset supplied
    /// @param useAsCollateral True if the user wants to use the supply as collateral, false otherwise
    function setUserUseReserveAsCollateral(
        address asset,
        bool useAsCollateral
    ) external;

    /// @notice Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1
    /// @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
    /// @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
    /// @param user The address of the borrower getting liquidated
    /// @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
    /// @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants to receive the underlying collateral asset directly
    function liquidationCall(
        address collateralAsset,
        address debtAsset,
        address user,
        uint256 debtToCover,
        bool receiveAToken
    ) external;

    /// @notice Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned
    /// @param asset The address of the underlying asset to withdraw
    /// @param amount The underlying amount to be withdrawn
    /// - Send the value type(uint256).max in order to withdraw the whole aToken balance
    /// @param to The address that will receive the underlying, same as msg.sender if the user wants to receive it on his own wallet, or a different address if the beneficiary is a different wallet
    /// @return The final amount withdrawn
    function withdraw(
        address asset,
        uint256 amount,
        address to
    ) external returns (uint256);

    /// @notice Returns the user account data across all the reserves
    /// @param user The address of the user
    /// @return totalCollateralBase The total collateral of the user in the base currency used by the price feed
    /// @return totalDebtBase The total debt of the user in the base currency used by the price feed
    /// @return availableBorrowsBase The borrowing power left of the user in the base currency used by the price feed
    /// @return currentLiquidationThreshold The liquidation threshold of the user
    /// @return ltv The loan to value of the user
    /// @return healthFactor The current health factor of the user
    function getUserAccountData(
        address user
    )
        external
        view
        returns (
            uint256 totalCollateralBase,
            uint256 totalDebtBase,
            uint256 availableBorrowsBase,
            uint256 currentLiquidationThreshold,
            uint256 ltv,
            uint256 healthFactor
        );

    /// @notice Returns the configuration of the reserve
    /// @param asset The address of the underlying asset of the reserve
    /// @return decimals The decimals of the reserve
    /// @return ltv The ltv of the reserve
    /// @return liquidationThreshold The liquidationThreshold of the reserve
    /// @return liquidationBonus The liquidationBonus of the reserve
    /// @return reserveFactor The reserveFactor of the reserve
    /// @return usageAsCollateralEnabled True if the usage as collateral is enabled, false otherwise
    /// @return borrowingEnabled True if borrowing is enabled, false otherwise
    /// @return stableBo

Tags:
ERC20, Multisig, Mintable, Burnable, Swap, Liquidity, Yield, Multi-Signature, Factory, Oracle|addr:0xdfec5477957635f7db24f85a3c077e2b7a4f24b9|verified:true|block:23416960|tx:0x4ce90e40257e251dd7919953fa9c4fcd51304b424e51afbf4923bf9a63e3ca7e|first_check:1758537682

Submitted on: 2025-09-22 12:41:22

Comments

Log in to comment.

No comments yet.