ETH Price: $2,869.12 (-2.46%)

Contract

0x3FA96e9fCE14aAa67b2a84135C80eB0B44852790

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

1 Internal Transaction and 10 Token Transfers found.

Latest 1 internal transaction

Parent Transaction Hash Block From To
4247116462026-01-24 11:33:4440 hrs ago1769254424  Contract Creation0 ETH

Cross-Chain Transactions
Loading...
Loading

Minimal Proxy Contract for 0xac27f3f86e78b14721d07c4f9ce999285f9aaa06

Contract Name:
RepayWithCollateralAaveV3Adapter

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 999999 runs

Other Settings:
cancun EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2025 Aave Labs
pragma solidity 0.8.28;

import {AaveV3BaseAdapter} from 'src/contracts/AaveV3BaseAdapter.sol';
import {
  IRepayWithCollateralAaveV3Adapter,
  DataTypes
} from 'src/interfaces/IRepayWithCollateralAaveV3Adapter.sol';

/// @notice CowSwap Adapter Hook for Aave V3 - Action : Repay Debt With Collateral With Flash Loan.
/// @author Aave Labs.
contract RepayWithCollateralAaveV3Adapter is AaveV3BaseAdapter, IRepayWithCollateralAaveV3Adapter {
  constructor(
    address factory_,
    address aavePool_,
    address settlement_
  ) AaveV3BaseAdapter(factory_, aavePool_, settlement_) {}

  /// @inheritdoc IRepayWithCollateralAaveV3Adapter
  /// @dev For RepayWithCollateral : hookSellTokenAmount => amount to withdraw && hookBuyTokenAmount => amount to repay
  function repayDebtWithFlashLoan(DataTypes.Permit calldata erc20Permit) external checkExpiry {
    // Repay the debt with the received outcome of the swap
    _repay({
      asset: _buyToken,
      user: owner,
      repayAmount: _hookBuyTokenAmount,
      orderAmount: _buyAmount
    });

    // Withdraw the asset to repay the flashloan (and more if specified)
    _withdraw({
      asset: _sellToken,
      user: owner,
      withdrawAmount: _hookSellTokenAmount,
      orderAmount: _sellAmount,
      receiver: address(this),
      erc20Permit: erc20Permit
    });

    // Notify to start the FlashLoan repay process on the Factory
    // and sweep any leftovers in this contract
    uint256 totalFlashLoanAmount = _flashLoanAmount + _flashLoanFeeAmount;
    _repayFlashLoan(_sellToken, totalFlashLoanAmount);
    _sweepDust(_sellToken);
    _sweepDust(_buyToken);
  }
}

// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2025 Aave Labs
pragma solidity 0.8.28;

import {IERC20} from 'openzeppelin/token/ERC20/IERC20.sol';
import {SafeERC20} from 'openzeppelin/token/ERC20/utils/SafeERC20.sol';

import {ICreditDelegationToken} from 'aave-v3-origin/contracts/interfaces/ICreditDelegationToken.sol';
import {IERC20WithPermit} from 'aave-v3-origin/contracts/interfaces/IERC20WithPermit.sol';
import {IPool} from 'aave-v3-origin/contracts/interfaces/IPool.sol';

import {GPv2Order} from 'cowprotocol/contracts/libraries/GPv2Order.sol';

import {ISettlement} from 'src/interfaces/ISettlement.sol';
import {DataTypes} from 'src/libraries/DataTypes.sol';
import {IAaveBaseAdapter} from 'src/interfaces/IAaveBaseAdapter.sol';
import {IBaseAdapterFactory} from 'src/interfaces/IBaseAdapterFactory.sol';

/// @notice Base for AdapterHooks with all the interactions with the Aave V3 Pool and the Adapter Factory contracts.
/// @author Aave Labs.
contract AaveV3BaseAdapter is IAaveBaseAdapter {
  using SafeERC20 for IERC20;
  using GPv2Order for GPv2Order.Data;

  /// @dev Rate mode for variable rate borrowings.
  uint256 private constant BORROW_VARIABLE_RATE = 2;

  /// @dev Referral code to pass to the Aave Pool.
  uint16 private constant REFERRAL_CODE = 4300;

  address public immutable FACTORY;
  address public immutable AAVE_POOL;
  address public immutable SETTLEMENT_CONTRACT;

  bool private initialized;

  /// @notice Owner of the AdapterHook Instance (the user signing the Order).
  address public owner;

  // DataTypes.HookOrderData struct
  address internal transient _sellToken;
  address internal transient _buyToken;
  uint256 internal transient _sellAmount;
  uint256 internal transient _buyAmount;
  bytes32 internal transient _kind;
  uint256 internal transient _validTo;
  uint256 internal transient _flashLoanAmount;
  uint256 internal transient _flashLoanFeeAmount;
  uint256 internal transient _hookSellTokenAmount;
  uint256 internal transient _hookBuyTokenAmount;

  /// @notice Only the Instance owner can call.
  modifier onlyInstanceOwner() {
    require(msg.sender == owner, CallerNotInstanceOwner());
    _;
  }

  /// @notice Check that the Order for the Instance is still valid.
  modifier checkExpiry() {
    require(block.timestamp <= _validTo, OrderExpired());
    _;
  }

  /// @dev Constructor.
  /// @param factory_ The address of the AaveV3AdapterFactory contract.
  /// @param aavePool_ The address of the Aave V3 Pool contract.
  /// @param settlement_ The address of the Cow Settlement contract.
  constructor(address factory_, address aavePool_, address settlement_) {
    require(
      factory_ != address(0) && aavePool_ != address(0) && settlement_ != address(0),
      InvalidZeroAddress()
    );
    FACTORY = factory_;
    AAVE_POOL = aavePool_;
    SETTLEMENT_CONTRACT = settlement_;

    initialized = true;
  }

  /// @inheritdoc IAaveBaseAdapter
  function setParameters(DataTypes.HookOrderData calldata hookData_) external {
    require(!initialized, AlreadyInitialized());
    initialized = true;
    owner = hookData_.owner;

    // Store the Order data in the transient storage for this deployment
    _sellToken = hookData_.sellToken;
    _buyToken = hookData_.buyToken;
    _sellAmount = hookData_.sellAmount;
    _buyAmount = hookData_.buyAmount;
    _kind = hookData_.kind;
    _validTo = hookData_.validTo;
    _flashLoanAmount = hookData_.flashLoanAmount;
    _flashLoanFeeAmount = hookData_.flashLoanFeeAmount;
    _hookSellTokenAmount = hookData_.hookSellTokenAmount;
    _hookBuyTokenAmount = hookData_.hookBuyTokenAmount;

    // Check the postHook amounts
    // and make sure they allow to cover the total amount to repay the FlashLoan
    require(
      hookData_.flashLoanAmount > 0 &&
        hookData_.hookBuyTokenAmount > 0 &&
        hookData_.hookSellTokenAmount > 0,
      InvalidZeroAmount()
    );
    if (hookData_.sellAmount == hookData_.flashLoanAmount) {
      // If we sell the full flashloan amount, we need to withdraw/borrow at least the flashloan amount + fee amount
      // to return the correct funds to the Factory
      require(
        hookData_.hookSellTokenAmount >= (hookData_.flashLoanAmount + hookData_.flashLoanFeeAmount),
        InvalidHookSellAmount()
      );
    } else if (hookData_.sellAmount == hookData_.flashLoanAmount - hookData_.flashLoanFeeAmount) {
      // If we do not sell the full flashloan amount, we want to keep the required fee amount before the swap
      // and only withdraw/borrow the flashloan amount to return the correct funds to the Factory
      require(hookData_.hookSellTokenAmount >= hookData_.flashLoanAmount, InvalidHookSellAmount());
    } else {
      revert InvalidHookSellAmount();
    }

    // Give the allowance to pull the Flashloaned assets for the swap
    IERC20(hookData_.sellToken).forceApprove(
      ISettlement(SETTLEMENT_CONTRACT).vaultRelayer(),
      hookData_.sellAmount
    );
  }

  /// @notice Rescue any ERC20 tokens left on the contract.
  /// @dev Emergency rescue for token stucked on this contract, as failsafe mechanism.
  /// @dev Funds should never remain in this contract more time than during transactions.
  /// @dev Only callable by the owner.
  function rescueTokens(IERC20 token) external onlyInstanceOwner {
    token.safeTransfer(owner, token.balanceOf(address(this)));
  }

  /// @inheritdoc IAaveBaseAdapter
  function getHookData() external view returns (DataTypes.HookOrderData memory) {
    return _getHookData();
  }

  /// @notice Checks that the given Order signature matches the Order used to deploy this contract.
  /// @param _orderHash The hash of the Order to check.
  /// @param _signature The signature to verify.
  function isValidSignature(
    bytes32 _orderHash,
    bytes calldata _signature
  ) external view returns (bytes4) {
    (GPv2Order.Data memory _order, bytes memory _userSignature) = abi.decode(
      _signature,
      (GPv2Order.Data, bytes)
    );

    require(
      IBaseAdapterFactory(FACTORY).verifyOrderSignature(owner, _order, _userSignature),
      InvalidOrderSignature()
    );

    bytes32 _rebuiltOrderHash = _order.hash(ISettlement(SETTLEMENT_CONTRACT).domainSeparator());
    require(_orderHash == _rebuiltOrderHash, OrderHashMismatch());

    require(_order.validTo == _validTo, InvalidOrderExpiry());
    require(block.timestamp <= _order.validTo, OrderExpired());
    require(_order.receiver == address(this), InvalidOrderReceiver());
    require(_order.kind == _kind, InvalidOrderKind());
    require(!_order.partiallyFillable, OrderPartiallyFillable());

    require(address(_order.sellToken) == address(_sellToken), InvalidSellToken());
    require(address(_order.buyToken) == address(_buyToken), InvalidBuyToken());

    require(_order.sellAmount == _sellAmount, InvalidSellAmount());
    require(_order.buyAmount == _buyAmount, InvalidBuyAmount());
    require(_order.feeAmount == 0, OrderFeeNotNull());

    require(_order.sellTokenBalance == GPv2Order.BALANCE_ERC20, InvalidOrderTokenBalancer());
    require(_order.buyTokenBalance == GPv2Order.BALANCE_ERC20, InvalidOrderTokenBalancer());

    return this.isValidSignature.selector;
  }

  /// @dev Executes the Credit Delegation via signature for the debt asset.
  /// @param aavePool The Aave Pool contract.
  /// @param asset The asset to borrow.
  /// @param user The user to borrow from.
  /// @param creditDelegationSig The credit delegation signature signed data.
  function _tryCreditDelegationWithSig(
    IPool aavePool,
    address asset,
    address user,
    DataTypes.CreditDelegationSig calldata creditDelegationSig
  ) internal {
    try
      ICreditDelegationToken(_getVariableDebtToken(aavePool, asset)).delegationWithSig(
        user,
        address(this),
        creditDelegationSig.amount,
        creditDelegationSig.deadline,
        creditDelegationSig.v,
        creditDelegationSig.r,
        creditDelegationSig.s
      )
    {} catch {}
  }

  /// @dev Supplies assets to the pool on behalf of a given user.
  /// @param asset The asset to supply.
  /// @param receiver The address receiving the supply.
  /// @param supplyAmount The amount to supply.
  /// @param orderAmount The amount passed in the Order.
  function _supply(
    address asset,
    address receiver,
    uint256 supplyAmount,
    uint256 orderAmount
  ) internal {
    IPool aavePool = IPool(AAVE_POOL);
    // Check that this contract received the correct amount of assets
    uint256 currentBalance = _getCurrentBalance(asset, address(this));
    require(currentBalance >= orderAmount, InvalidBalance());
    // And supply the full balance, including any excess over the order amount, to avoid any leftover
    if (currentBalance > supplyAmount) {
      supplyAmount = currentBalance;
    }

    // Deposit on behalf of the receiver
    IERC20(asset).forceApprove(address(aavePool), supplyAmount);
    aavePool.supply(asset, supplyAmount, receiver, REFERRAL_CODE);
  }

  /// @dev Withdraws assets pulled from a specified user.
  /// @param asset The asset to withdraw.
  /// @param user The user to withdraw from.
  /// @param withdrawAmount The amount to withdraw.
  /// @param orderAmount The amount passed in the Order.
  /// @param receiver The address receiving the withdrawn assets.
  /// @param erc20Permit The permit data for the aToken transfer, if needed.
  function _withdraw(
    address asset,
    address user,
    uint256 withdrawAmount,
    uint256 orderAmount,
    address receiver,
    DataTypes.Permit calldata erc20Permit
  ) internal {
    IPool aavePool = IPool(AAVE_POOL);
    address aToken = _getAToken(aavePool, asset);
    uint256 withdrawable = IERC20(aToken).balanceOf(user);
    // If the given amount is meant for a max withdraw
    if (withdrawAmount > withdrawable) {
      withdrawAmount = withdrawable;
    }
    require(orderAmount <= withdrawAmount, InvalidAmount());

    // Execute the permit if needed.
    if (erc20Permit.deadline != 0) {
      try
        IERC20WithPermit(aToken).permit(
          user,
          address(this),
          erc20Permit.amount,
          erc20Permit.deadline,
          erc20Permit.v,
          erc20Permit.r,
          erc20Permit.s
        )
      {} catch {}
    }

    // Pull the aToken from the user in this contract.
    IERC20(aToken).safeTransferFrom(user, address(this), withdrawAmount);

    // Withdraw the aToken to receive the asset.
    uint256 received = aavePool.withdraw(asset, withdrawAmount, receiver);

    require(received == withdrawAmount, InvalidWithdraw());
  }

  /// @dev Borrows assets using the given user credit delegation.
  /// @param asset The asset to borrow.
  /// @param user The user to borrow from.
  /// @param borrowAmount The amount to borrow.
  /// @param orderAmount The amount passed in the Order.
  /// @param receiver The address receiving the borrowed assets.
  /// @param creditDelegationSig The credit delegation signature data, if needed.
  function _borrow(
    address asset,
    address user,
    uint256 borrowAmount,
    uint256 orderAmount,
    address receiver,
    DataTypes.CreditDelegationSig calldata creditDelegationSig
  ) internal {
    IPool aavePool = IPool(AAVE_POOL);
    require(orderAmount <= borrowAmount, InvalidAmount());

    // Execute the Credit Delegation if needed.
    if (creditDelegationSig.deadline != 0) {
      _tryCreditDelegationWithSig(aavePool, asset, user, creditDelegationSig);
    }

    uint256 initialBalance = IERC20(asset).balanceOf(address(this));

    // Borrow on the user position, to receive the asset in this contract.
    aavePool.borrow(asset, borrowAmount, BORROW_VARIABLE_RATE, REFERRAL_CODE, user);

    uint256 received = _getCurrentBalance(asset, address(this)) - initialBalance;

    require(received == borrowAmount, InvalidBorrow());

    // Send the borrowed assets to the specified receiver.
    IERC20(asset).safeTransfer(receiver, received);
  }

  /// @dev Repay the asset debt for a given user.
  /// @param asset The asset to repay.
  /// @param user The user to repay for.
  /// @param repayAmount The amount to repay.
  /// @param orderAmount The amount passed as output in the Order.
  function _repay(address asset, address user, uint256 repayAmount, uint256 orderAmount) internal {
    IPool aavePool = IPool(AAVE_POOL);
    // Check that this contract recevied the correct amount of assets and has enough
    // to supply the specified amount.
    uint256 currentBalance = _getCurrentBalance(asset, address(this));
    uint256 currentDebt = _getCurrentDebt(aavePool, asset, user);
    require(currentBalance >= orderAmount, InvalidBalance());

    // If the specified amount is higher than the balance, only repay up to the current balance.
    if (repayAmount > currentBalance) {
      repayAmount = currentBalance;
    }
    // If the specified amount is higher than the current debt, only repay the current debt.
    if (repayAmount > currentDebt) {
      repayAmount = currentDebt;
    }

    // Repay the debt on behalf of the specified user.
    IERC20(asset).forceApprove(address(aavePool), repayAmount);
    aavePool.repay(asset, repayAmount, BORROW_VARIABLE_RATE, user);
  }

  /// @dev Starts the flash loan repayment process by notifying the AaveV3AdapterFactory and setting the allowance for the asset to be pulled.
  function _repayFlashLoan(address asset, uint256 amount) internal {
    IERC20(asset).forceApprove(FACTORY, amount);
    IBaseAdapterFactory(FACTORY).notifyRepayFlashLoan();
  }

  /// @dev Sweeps any leftover of the asset in the contract.
  function _sweepDust(address asset) internal {
    uint256 balance = IERC20(asset).balanceOf(address(this));
    if (balance > 0) {
      IERC20(asset).safeTransfer(owner, balance);
    }
  }

  function _getHookData() internal view returns (DataTypes.HookOrderData memory data) {
    return
      DataTypes.HookOrderData({
        owner: owner,
        receiver: address(this),
        sellToken: _sellToken,
        buyToken: _buyToken,
        sellAmount: _sellAmount,
        buyAmount: _buyAmount,
        kind: _kind,
        validTo: _validTo,
        flashLoanAmount: _flashLoanAmount,
        flashLoanFeeAmount: _flashLoanFeeAmount,
        hookSellTokenAmount: _hookSellTokenAmount,
        hookBuyTokenAmount: _hookBuyTokenAmount
      });
  }

  /// @dev Returns the aToken for a given asset.
  function _getAToken(IPool aavePool, address asset) internal view returns (address) {
    return aavePool.getReserveAToken(asset);
  }

  /// @dev Returns the debt token for a given asset.
  function _getVariableDebtToken(IPool aavePool, address asset) internal view returns (address) {
    return aavePool.getReserveVariableDebtToken(asset);
  }

  /// @dev Returns the current balance of a given address for a given asset.
  function _getCurrentBalance(address asset, address user) internal view returns (uint256) {
    return IERC20(asset).balanceOf(user);
  }

  /// @dev Returns the current debt balance of a given address for a given asset.
  function _getCurrentDebt(
    IPool aavePool,
    address asset,
    address user
  ) internal view returns (uint256) {
    return IERC20(_getVariableDebtToken(aavePool, asset)).balanceOf(user);
  }
}

// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2025 Aave Labs
pragma solidity ^0.8.0;

import {DataTypes} from 'src/libraries/DataTypes.sol';
import {IAaveBaseAdapter} from 'src/interfaces/IAaveBaseAdapter.sol';

/// @notice Interface for the RepayWithCollateralAaveV3Adapter.
/// @author Aave Labs.
interface IRepayWithCollateralAaveV3Adapter is IAaveBaseAdapter {
  /// @notice PostHook to repay user debt with its collateral.
  /// @dev Uses a flashloan & swap to repay the user debt and withdraw the user's collateral to repay the Flashloan.
  /// @param erc20Permit The permit data for the aToken to pull and withdraw.
  function repayDebtWithFlashLoan(DataTypes.Permit calldata erc20Permit) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.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);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

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

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title ICreditDelegationToken
 * @author Aave
 * @notice Defines the basic interface for a token supporting credit delegation.
 */
interface ICreditDelegationToken {
  /**
   * @dev Emitted on `approveDelegation` and `borrowAllowance
   * @param fromUser The address of the delegator
   * @param toUser The address of the delegatee
   * @param asset The address of the delegated asset
   * @param amount The amount being delegated
   */
  event BorrowAllowanceDelegated(
    address indexed fromUser,
    address indexed toUser,
    address indexed asset,
    uint256 amount
  );

  /**
   * @dev Indicates a failure with the `spender`’s `allowance`. Used in borrowing.
   * @param spender Address that may be allowed to operate on tokens without being their owner.
   * @param allowance Amount of tokens a `spender` is allowed to operate with.
   * @param needed Minimum amount required to perform a transfer.
   */
  error InsufficientBorrowAllowance(address spender, uint256 allowance, uint256 needed);

  /**
   * @notice Delegates borrowing power to a user on the specific debt token.
   * Delegation will still respect the liquidation constraints (even if delegated, a
   * delegatee cannot force a delegator HF to go below 1)
   * @param delegatee The address receiving the delegated borrowing power
   * @param amount The maximum amount being delegated.
   */
  function approveDelegation(address delegatee, uint256 amount) external;

  /**
   * @notice Returns the borrow allowance of the user
   * @param fromUser The user to giving allowance
   * @param toUser The user to give allowance to
   * @return The current allowance of `toUser`
   */
  function borrowAllowance(address fromUser, address toUser) external view returns (uint256);

  /**
   * @notice Delegates borrowing power to a user on the specific debt token via ERC712 signature
   * @param delegator The delegator of the credit
   * @param delegatee The delegatee that can use the credit
   * @param value The amount to be delegated
   * @param deadline The deadline timestamp, type(uint256).max for max deadline
   * @param v The V signature param
   * @param s The S signature param
   * @param r The R signature param
   */
  function delegationWithSig(
    address delegator,
    address delegatee,
    uint256 value,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
  ) external;
}

File 7 of 27 : IERC20WithPermit.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';

/**
 * @title IERC20WithPermit
 * @author Aave
 * @notice Interface for the permit function (EIP-2612)
 */
interface IERC20WithPermit is IERC20 {
  /**
   * @notice Allow passing a signed message to approve spending
   * @dev implements the permit function as for
   * https://github.com/ethereum/EIPs/blob/8a34d644aacf0f9f8f00815307fd7dd5da07655f/EIPS/eip-2612.md
   * @param owner The owner of the funds
   * @param spender The spender
   * @param value The amount
   * @param deadline The deadline timestamp, type(uint256).max for max deadline
   * @param v Signature param
   * @param s Signature param
   * @param r Signature param
   */
  function permit(
    address owner,
    address spender,
    uint256 value,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
  ) external;
}

File 8 of 27 : IPool.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IPoolAddressesProvider} from './IPoolAddressesProvider.sol';
import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';

/**
 * @title IPool
 * @author Aave
 * @notice Defines the basic interface for an Aave Pool.
 */
interface IPool {
  /**
   * @dev Emitted on supply()
   * @param reserve The address of the underlying asset of the reserve
   * @param user The address initiating the supply
   * @param onBehalfOf The beneficiary of the supply, receiving the aTokens
   * @param amount The amount supplied
   * @param referralCode The referral code used
   */
  event Supply(
    address indexed reserve,
    address user,
    address indexed onBehalfOf,
    uint256 amount,
    uint16 indexed referralCode
  );

  /**
   * @dev Emitted on withdraw()
   * @param reserve The address of the underlying asset being withdrawn
   * @param user The address initiating the withdrawal, owner of aTokens
   * @param to The address that will receive the underlying
   * @param amount The amount to be withdrawn
   */
  event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount);

  /**
   * @dev Emitted on borrow() and flashLoan() when debt needs to be opened
   * @param reserve The address of the underlying asset being borrowed
   * @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just
   * initiator of the transaction on flashLoan()
   * @param onBehalfOf The address that will be getting the debt
   * @param amount The amount borrowed out
   * @param interestRateMode The rate mode: 2 for Variable, 1 is deprecated (changed on v3.2.0)
   * @param borrowRate The numeric rate at which the user has borrowed, expressed in ray
   * @param referralCode The referral code used
   */
  event Borrow(
    address indexed reserve,
    address user,
    address indexed onBehalfOf,
    uint256 amount,
    DataTypes.InterestRateMode interestRateMode,
    uint256 borrowRate,
    uint16 indexed referralCode
  );

  /**
   * @dev Emitted on repay()
   * @param reserve The address of the underlying asset of the reserve
   * @param user The beneficiary of the repayment, getting his debt reduced
   * @param repayer The address of the user initiating the repay(), providing the funds
   * @param amount The amount repaid
   * @param useATokens True if the repayment is done using aTokens, `false` if done with underlying asset directly
   */
  event Repay(
    address indexed reserve,
    address indexed user,
    address indexed repayer,
    uint256 amount,
    bool useATokens
  );

  /**
   * @dev Emitted on borrow(), repay() and liquidationCall() when using isolated assets
   * @param asset The address of the underlying asset of the reserve
   * @param totalDebt The total isolation mode debt for the reserve
   */
  event IsolationModeTotalDebtUpdated(address indexed asset, uint256 totalDebt);

  /**
   * @dev Emitted when the user selects a certain asset category for eMode
   * @param user The address of the user
   * @param categoryId The category id
   */
  event UserEModeSet(address indexed user, uint8 categoryId);

  /**
   * @dev Emitted on setUserUseReserveAsCollateral()
   * @param reserve The address of the underlying asset of the reserve
   * @param user The address of the user enabling the usage as collateral
   */
  event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user);

  /**
   * @dev Emitted on setUserUseReserveAsCollateral()
   * @param reserve The address of the underlying asset of the reserve
   * @param user The address of the user enabling the usage as collateral
   */
  event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user);

  /**
   * @dev Emitted on flashLoan()
   * @param target The address of the flash loan receiver contract
   * @param initiator The address initiating the flash loan
   * @param asset The address of the asset being flash borrowed
   * @param amount The amount flash borrowed
   * @param interestRateMode The flashloan mode: 0 for regular flashloan,
   *        1 for Stable (Deprecated on v3.2.0), 2 for Variable
   * @param premium The fee flash borrowed
   * @param referralCode The referral code used
   */
  event FlashLoan(
    address indexed target,
    address initiator,
    address indexed asset,
    uint256 amount,
    DataTypes.InterestRateMode interestRateMode,
    uint256 premium,
    uint16 indexed referralCode
  );

  /**
   * @dev Emitted when a borrower is liquidated.
   * @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 liquidatedCollateralAmount The amount of collateral received by the liquidator
   * @param liquidator The address of the liquidator
   * @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants
   * to receive the underlying collateral asset directly
   */
  event LiquidationCall(
    address indexed collateralAsset,
    address indexed debtAsset,
    address indexed user,
    uint256 debtToCover,
    uint256 liquidatedCollateralAmount,
    address liquidator,
    bool receiveAToken
  );

  /**
   * @dev Emitted when the state of a reserve is updated.
   * @param reserve The address of the underlying asset of the reserve
   * @param liquidityRate The next liquidity rate
   * @param stableBorrowRate The next stable borrow rate @note deprecated on v3.2.0
   * @param variableBorrowRate The next variable borrow rate
   * @param liquidityIndex The next liquidity index
   * @param variableBorrowIndex The next variable borrow index
   */
  event ReserveDataUpdated(
    address indexed reserve,
    uint256 liquidityRate,
    uint256 stableBorrowRate,
    uint256 variableBorrowRate,
    uint256 liquidityIndex,
    uint256 variableBorrowIndex
  );

  /**
   * @dev Emitted when the deficit of a reserve is covered.
   * @param reserve The address of the underlying asset of the reserve
   * @param caller The caller that triggered the DeficitCovered event
   * @param amountCovered The amount of deficit covered
   */
  event DeficitCovered(address indexed reserve, address caller, uint256 amountCovered);

  /**
   * @dev Emitted when the protocol treasury receives minted aTokens from the accrued interest.
   * @param reserve The address of the reserve
   * @param amountMinted The amount minted to the treasury
   */
  event MintedToTreasury(address indexed reserve, uint256 amountMinted);

  /**
   * @dev Emitted when deficit is realized on a liquidation.
   * @param user The user address where the bad debt will be burned
   * @param debtAsset The address of the underlying borrowed asset to be burned
   * @param amountCreated The amount of deficit created
   */
  event DeficitCreated(address indexed user, address indexed debtAsset, uint256 amountCreated);

  /**
   * @dev Emitted when a position manager is approved by the user.
   * @param user The user address
   * @param positionManager The address of the position manager
   */
  event PositionManagerApproved(address indexed user, address indexed positionManager);

  /**
   * @dev Emitted when a position manager is revoked by the user.
   * @param user The user address
   * @param positionManager The address of the position manager
   */
  event PositionManagerRevoked(address indexed user, address indexed positionManager);

  /**
   * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
   * - E.g. User supplies 100 USDC and gets in return 100 aUSDC
   * @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.
   *   0 if the action is executed directly by the user, without any middle-man
   */
  function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;

  /**
   * @notice Supply with transfer approval of asset to be supplied done via permit function
   * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713
   * @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 deadline The deadline timestamp that the permit is valid
   * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
   *   0 if the action is executed directly by the user, without any middle-man
   * @param permitV The V parameter of ERC712 permit sig
   * @param permitR The R parameter of ERC712 permit sig
   * @param permitS The S parameter of ERC712 permit sig
   */
  function supplyWithPermit(
    address asset,
    uint256 amount,
    address onBehalfOf,
    uint16 referralCode,
    uint256 deadline,
    uint8 permitV,
    bytes32 permitR,
    bytes32 permitS
  ) external;

  /**
   * @notice Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned
   * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC
   * @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 Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower
   * already supplied enough collateral, or he was given enough allowance by a credit delegator on the VariableDebtToken
   * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet
   *   and 100 variable debt tokens
   * @param asset The address of the underlying asset to borrow
   * @param amount The amount to be borrowed
   * @param interestRateMode 2 for Variable, 1 is deprecated on v3.2.0
   * @param referralCode The code used to register the integrator originating the operation, for potential rewards.
   *   0 if the action is executed directly by the user, without any middle-man
   * @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
   */
  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
   * - E.g. User repays 100 USDC, burning 100 variable debt tokens of the `onBehalfOf` address
   * @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 2 for Variable, 1 is deprecated on v3.2.0
   * @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 Repay with transfer approval of asset to be repaid done via permit function
   * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713
   * @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 2 for Variable, 1 is deprecated on v3.2.0
   * @param onBehalfOf 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
   * @param deadline The deadline timestamp that the permit is valid
   * @param permitV The V parameter of ERC712 permit sig
   * @param permitR The R parameter of ERC712 permit sig
   * @param permitS The S parameter of ERC712 permit sig
   * @return The final amount repaid
   */
  function repayWithPermit(
    address asset,
    uint256 amount,
    uint256 interestRateMode,
    address onBehalfOf,
    uint256 deadline,
    uint8 permitV,
    bytes32 permitR,
    bytes32 permitS
  ) external returns (uint256);

  /**
   * @notice Repays a borrowed `amount` on a specific reserve using the reserve aTokens, burning the
   * equivalent debt tokens
   * - E.g. User repays 100 USDC using 100 aUSDC, burning 100 variable debt tokens
   * @dev  Passing uint256.max as amount will clean up any residual aToken dust balance, if the user aToken
   * balance is not enough to cover the whole debt
   * @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 DEPRECATED in v3.2.0
   * @return The final amount repaid
   */
  function repayWithATokens(
    address asset,
    uint256 amount,
    uint256 interestRateMode
  ) 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
   * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives
   *   a proportionally amount of the `collateralAsset` plus a bonus to cover market risk
   * @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 borrower 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 borrower,
    uint256 debtToCover,
    bool receiveAToken
  ) external;

  /**
   * @notice Allows smartcontracts to access the liquidity of the pool within one transaction,
   * as long as the amount taken plus a fee is returned.
   * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept
   * into consideration. For further details please visit https://docs.aave.com/developers/
   * @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanReceiver interface
   * @param assets The addresses of the assets being flash-borrowed
   * @param amounts The amounts of the assets being flash-borrowed
   * @param interestRateModes Types of the debt to open if the flash loan is not returned:
   *   0 -> Don't open any debt, just revert if funds can't be transferred from the receiver
   *   1 -> Deprecated on v3.2.0
   *   2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
   * @param onBehalfOf The address  that will receive the debt in the case of using 2 on `modes`
   * @param params Variadic packed params to pass to the receiver as extra information
   * @param referralCode The code used to register the integrator originating the operation, for potential rewards.
   *   0 if the action is executed directly by the user, without any middle-man
   */
  function flashLoan(
    address receiverAddress,
    address[] calldata assets,
    uint256[] calldata amounts,
    uint256[] calldata interestRateModes,
    address onBehalfOf,
    bytes calldata params,
    uint16 referralCode
  ) external;

  /**
   * @notice Allows smartcontracts to access the liquidity of the pool within one transaction,
   * as long as the amount taken plus a fee is returned.
   * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept
   * into consideration. For further details please visit https://docs.aave.com/developers/
   * @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanSimpleReceiver interface
   * @param asset The address of the asset being flash-borrowed
   * @param amount The amount of the asset being flash-borrowed
   * @param params Variadic packed params to pass to the receiver as extra information
   * @param referralCode The code used to register the integrator originating the operation, for potential rewards.
   *   0 if the action is executed directly by the user, without any middle-man
   */
  function flashLoanSimple(
    address receiverAddress,
    address asset,
    uint256 amount,
    bytes calldata params,
    uint16 referralCode
  ) external;

  /**
   * @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 Initializes a reserve, activating it, assigning an aToken and debt tokens
   * @dev Only callable by the PoolConfigurator contract
   * @param asset The address of the underlying asset of the reserve
   * @param aTokenAddress The address of the aToken that will be assigned to the reserve
   * @param variableDebtAddress The address of the VariableDebtToken that will be assigned to the reserve
   */
  function initReserve(address asset, address aTokenAddress, address variableDebtAddress) external;

  /**
   * @notice Drop a reserve
   * @dev Only callable by the PoolConfigurator contract
   * @dev Does not reset eMode flags, which must be considered when reusing the same reserve id for a different reserve.
   * @param asset The address of the underlying asset of the reserve
   */
  function dropReserve(address asset) external;

  /**
   * @notice Accumulates interest to all indexes of the reserve
   * @dev Only callable by the PoolConfigurator contract
   * @dev To be used when required by the configurator, for example when updating interest rates strategy data
   * @param asset The address of the underlying asset of the reserve
   */
  function syncIndexesState(address asset) external;

  /**
   * @notice Updates interest rates on the reserve data
   * @dev Only callable by the PoolConfigurator contract
   * @dev To be used when required by the configurator, for example when updating interest rates strategy data
   * @param asset The address of the underlying asset of the reserve
   */
  function syncRatesState(address asset) external;

  /**
   * @notice Sets the configuration bitmap of the reserve as a whole
   * @dev Only callable by the PoolConfigurator contract
   * @param asset The address of the underlying asset of the reserve
   * @param configuration The new configuration bitmap
   */
  function setConfiguration(
    address asset,
    DataTypes.ReserveConfigurationMap calldata configuration
  ) external;

  /**
   * @notice Returns the configuration of the reserve
   * @param asset The address of the underlying asset of the reserve
   * @return The configuration of the reserve
   */
  function getConfiguration(
    address asset
  ) external view returns (DataTypes.ReserveConfigurationMap memory);

  /**
   * @notice Returns the configuration of the user across all the reserves
   * @param user The user address
   * @return The configuration of the user
   */
  function getUserConfiguration(
    address user
  ) external view returns (DataTypes.UserConfigurationMap memory);

  /**
   * @notice Returns the normalized income of the reserve
   * @param asset The address of the underlying asset of the reserve
   * @return The reserve's normalized income
   */
  function getReserveNormalizedIncome(address asset) external view returns (uint256);

  /**
   * @notice Returns the normalized variable debt per unit of asset
   * @dev WARNING: This function is intended to be used primarily by the protocol itself to get a
   * "dynamic" variable index based on time, current stored index and virtual rate at the current
   * moment (approx. a borrower would get if opening a position). This means that is always used in
   * combination with variable debt supply/balances.
   * If using this function externally, consider that is possible to have an increasing normalized
   * variable debt that is not equivalent to how the variable debt index would be updated in storage
   * (e.g. only updates with non-zero variable debt supply)
   * @param asset The address of the underlying asset of the reserve
   * @return The reserve normalized variable debt
   */
  function getReserveNormalizedVariableDebt(address asset) external view returns (uint256);

  /**
   * @notice Returns the state and configuration of the reserve
   * @param asset The address of the underlying asset of the reserve
   * @return The state and configuration data of the reserve
   */
  function getReserveData(address asset) external view returns (DataTypes.ReserveDataLegacy memory);

  /**
   * @notice Returns the virtual underlying balance of the reserve
   * @param asset The address of the underlying asset of the reserve
   * @return The reserve virtual underlying balance
   */
  function getVirtualUnderlyingBalance(address asset) external view returns (uint128);

  /**
   * @notice Validates and finalizes an aToken transfer
   * @dev Only callable by the overlying aToken of the `asset`
   * @param asset The address of the underlying asset of the aToken
   * @param from The user from which the aTokens are transferred
   * @param to The user receiving the aTokens
   * @param scaledAmount The scaled amount being transferred/withdrawn
   * @param scaledBalanceFromBefore The aToken scaled balance of the `from` user before the transfer
   * @param scaledBalanceToBefore The aToken scaled balance of the `to` user before the transfer
   */
  function finalizeTransfer(
    address asset,
    address from,
    address to,
    uint256 scaledAmount,
    uint256 scaledBalanceFromBefore,
    uint256 scaledBalanceToBefore
  ) external;

  /**
   * @notice Returns the list of the underlying assets of all the initialized reserves
   * @dev It does not include dropped reserves
   * @return The addresses of the underlying assets of the initialized reserves
   */
  function getReservesList() external view returns (address[] memory);

  /**
   * @notice Returns the number of initialized reserves
   * @dev It includes dropped reserves
   * @return The count
   */
  function getReservesCount() external view returns (uint256);

  /**
   * @notice Returns the address of the underlying asset of a reserve by the reserve id as stored in the DataTypes.ReserveData struct
   * @param id The id of the reserve as stored in the DataTypes.ReserveData struct
   * @return The address of the reserve associated with id
   */
  function getReserveAddressById(uint16 id) external view returns (address);

  /**
   * @notice Returns the PoolAddressesProvider connected to this contract
   * @return The address of the PoolAddressesProvider
   */
  function ADDRESSES_PROVIDER() external view returns (IPoolAddressesProvider);

  /**
   * @notice Returns the ReserveInterestRateStrategy connected to all the reserves
   * @return The address of the ReserveInterestRateStrategy contract
   */
  function RESERVE_INTEREST_RATE_STRATEGY() external view returns (address);

  /**
   * @notice Updates flash loan premium. All this premium is collected by the protocol treasury.
   * @dev The premium is calculated on the total borrowed amount
   * @dev Only callable by the PoolConfigurator contract
   * @param flashLoanPremium The flash loan premium, expressed in bps
   */
  function updateFlashloanPremium(uint128 flashLoanPremium) external;

  /**
   * @notice Configures a new or alters an existing collateral configuration of an eMode.
   * @dev In eMode, the protocol allows very high borrowing power to borrow assets of the same category.
   * The category 0 is reserved as it's the default for volatile assets
   * @param id The id of the category
   * @param config The configuration of the category
   */
  function configureEModeCategory(
    uint8 id,
    DataTypes.EModeCategoryBaseConfiguration memory config
  ) external;

  /**
   * @notice Replaces the current eMode collateralBitmap.
   * @param id The id of the category
   * @param collateralBitmap The collateralBitmap of the category
   */
  function configureEModeCategoryCollateralBitmap(uint8 id, uint128 collateralBitmap) external;

  /**
   * @notice Replaces the current eMode borrowableBitmap.
   * @param id The id of the category
   * @param borrowableBitmap The borrowableBitmap of the category
   */
  function configureEModeCategoryBorrowableBitmap(uint8 id, uint128 borrowableBitmap) external;

  /**
   * @notice Returns the data of an eMode category
   * @dev DEPRECATED use independent getters instead
   * @param id The id of the category
   * @return The configuration data of the category
   */
  function getEModeCategoryData(
    uint8 id
  ) external view returns (DataTypes.EModeCategoryLegacy memory);

  /**
   * @notice Returns the label of an eMode category
   * @param id The id of the category
   * @return The label of the category
   */
  function getEModeCategoryLabel(uint8 id) external view returns (string memory);

  /**
   * @notice Returns the collateral config of an eMode category
   * @param id The id of the category
   * @return The ltv,lt,lb of the category
   */
  function getEModeCategoryCollateralConfig(
    uint8 id
  ) external view returns (DataTypes.CollateralConfig memory);

  /**
   * @notice Returns the collateralBitmap of an eMode category
   * @param id The id of the category
   * @return The collateralBitmap of the category
   */
  function getEModeCategoryCollateralBitmap(uint8 id) external view returns (uint128);

  /**
   * @notice Returns the borrowableBitmap of an eMode category
   * @param id The id of the category
   * @return The borrowableBitmap of the category
   */
  function getEModeCategoryBorrowableBitmap(uint8 id) external view returns (uint128);

  /**
   * @notice Allows a user to use the protocol in eMode
   * @param categoryId The id of the category
   */
  function setUserEMode(uint8 categoryId) external;

  /**
   * @notice Returns the eMode the user is using
   * @param user The address of the user
   * @return The eMode id
   */
  function getUserEMode(address user) external view returns (uint256);

  /**
   * @notice Resets the isolation mode total debt of the given asset to zero
   * @dev It requires the given asset has zero debt ceiling
   * @param asset The address of the underlying asset to reset the isolationModeTotalDebt
   */
  function resetIsolationModeTotalDebt(address asset) external;

  /**
   * @notice Sets the liquidation grace period of the given asset
   * @dev To enable a liquidation grace period, a timestamp in the future should be set,
   *      To disable a liquidation grace period, any timestamp in the past works, like 0
   * @param asset The address of the underlying asset to set the liquidationGracePeriod
   * @param until Timestamp when the liquidation grace period will end
   **/
  function setLiquidationGracePeriod(address asset, uint40 until) external;

  /**
   * @notice Returns the liquidation grace period of the given asset
   * @param asset The address of the underlying asset
   * @return Timestamp when the liquidation grace period will end
   **/
  function getLiquidationGracePeriod(address asset) external view returns (uint40);

  /**
   * @notice Returns the total fee on flash loans.
   * @dev From v3.4 all flashloan fees will be send to the treasury.
   * @return The total fee on flashloans
   */
  function FLASHLOAN_PREMIUM_TOTAL() external view returns (uint128);

  /**
   * @notice Returns the part of the flashloan fees sent to protocol
   * @dev From v3.4 all flashloan fees will be send to the treasury and this value
   *      is always 100_00.
   * @return The flashloan fee sent to the protocol treasury
   */
  function FLASHLOAN_PREMIUM_TO_PROTOCOL() external view returns (uint128);

  /**
   * @notice Returns the maximum number of reserves supported to be listed in this Pool
   * @return The maximum number of reserves supported
   */
  function MAX_NUMBER_RESERVES() external view returns (uint16);

  /**
   * @notice Mints the assets accrued through the reserve factor to the treasury in the form of aTokens
   * @param assets The list of reserves for which the minting needs to be executed
   */
  function mintToTreasury(address[] calldata assets) external;

  /**
   * @notice Rescue and transfer tokens locked in this contract
   * @param token The address of the token
   * @param to The address of the recipient
   * @param amount The amount of token to transfer
   */
  function rescueTokens(address token, address to, uint256 amount) external;

  /**
   * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
   * - E.g. User supplies 100 USDC and gets in return 100 aUSDC
   * @dev Deprecated: Use the `supply` function instead
   * @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.
   *   0 if the action is executed directly by the user, without any middle-man
   */
  function deposit(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;

  /**
   * @notice It covers the deficit of a specified reserve by burning the equivalent aToken `amount` for assets
   * @dev The deficit of a reserve can occur due to situations where borrowed assets are not repaid, leading to bad debt.
   * @param asset The address of the underlying asset to cover the deficit.
   * @param amount The amount to be covered, in aToken
   * @return The amount of tokens burned
   */
  function eliminateReserveDeficit(address asset, uint256 amount) external returns (uint256);

  /**
   * @notice Approves or disapproves a position manager. This position manager will be able
   * to call the `setUserUseReserveAsCollateralOnBehalfOf` and the
   * `setUserEModeOnBehalfOf` function on behalf of the user.
   * @param positionManager The address of the position manager
   * @param approve True if the position manager should be approved, false otherwise
   */
  function approvePositionManager(address positionManager, bool approve) external;

  /**
   * @notice Renounces a position manager role for a given user.
   * @param user The address of the user
   */
  function renouncePositionManagerRole(address user) external;

  /**
   * @notice Sets the use as collateral flag for the user on the specific reserve on behalf of the user.
   * @param asset The address of the underlying asset of the reserve
   * @param useAsCollateral True if the user wants to use the reserve as collateral, false otherwise
   * @param onBehalfOf The address of the user
   */
  function setUserUseReserveAsCollateralOnBehalfOf(
    address asset,
    bool useAsCollateral,
    address onBehalfOf
  ) external;

  /**
   * @notice Sets the eMode category for the user on the specific reserve on behalf of the user.
   * @param categoryId The id of the category
   * @param onBehalfOf The address of the user
   */
  function setUserEModeOnBehalfOf(uint8 categoryId, address onBehalfOf) external;

  /*
   * @notice Returns true if the `positionManager` address is approved to use the position manager role on behalf of the user.
   * @param user The address of the user
   * @param positionManager The address of the position manager
   * @return True if the user is approved to use the position manager, false otherwise
   */
  function isApprovedPositionManager(
    address user,
    address positionManager
  ) external view returns (bool);

  /**
   * @notice Returns the current deficit of a reserve.
   * @param asset The address of the underlying asset of the reserve
   * @return The current deficit of the reserve
   */
  function getReserveDeficit(address asset) external view returns (uint256);

  /**
   * @notice Returns the aToken address of a reserve.
   * @param asset The address of the underlying asset of the reserve
   * @return The address of the aToken
   */
  function getReserveAToken(address asset) external view returns (address);

  /**
   * @notice Returns the variableDebtToken address of a reserve.
   * @param asset The address of the underlying asset of the reserve
   * @return The address of the variableDebtToken
   */
  function getReserveVariableDebtToken(address asset) external view returns (address);

  /**
   * @notice Gets the address of the external FlashLoanLogic
   */
  function getFlashLoanLogic() external view returns (address);

  /**
   * @notice Gets the address of the external BorrowLogic
   */
  function getBorrowLogic() external view returns (address);

  /**
   * @notice Gets the address of the external EModeLogic
   */
  function getEModeLogic() external view returns (address);

  /**
   * @notice Gets the address of the external LiquidationLogic
   */
  function getLiquidationLogic() external view returns (address);

  /**
   * @notice Gets the address of the external PoolLogic
   */
  function getPoolLogic() external view returns (address);

  /**
   * @notice Gets the address of the external SupplyLogic
   */
  function getSupplyLogic() external view returns (address);
}

// SPDX-License-Identifier: LGPL-3.0-or-later
pragma solidity >=0.7.6 <0.9.0;

import "../interfaces/IERC20.sol";

/// @title Gnosis Protocol v2 Order Library
/// @author Gnosis Developers
library GPv2Order {
    /// @dev The complete data for a Gnosis Protocol order. This struct contains
    /// all order parameters that are signed for submitting to GP.
    struct Data {
        IERC20 sellToken;
        IERC20 buyToken;
        address receiver;
        uint256 sellAmount;
        uint256 buyAmount;
        uint32 validTo;
        bytes32 appData;
        uint256 feeAmount;
        bytes32 kind;
        bool partiallyFillable;
        bytes32 sellTokenBalance;
        bytes32 buyTokenBalance;
    }

    /// @dev The order EIP-712 type hash for the [`GPv2Order.Data`] struct.
    ///
    /// This value is pre-computed from the following expression:
    /// ```
    /// keccak256(
    ///     "Order(" +
    ///         "address sellToken," +
    ///         "address buyToken," +
    ///         "address receiver," +
    ///         "uint256 sellAmount," +
    ///         "uint256 buyAmount," +
    ///         "uint32 validTo," +
    ///         "bytes32 appData," +
    ///         "uint256 feeAmount," +
    ///         "string kind," +
    ///         "bool partiallyFillable," +
    ///         "string sellTokenBalance," +
    ///         "string buyTokenBalance" +
    ///     ")"
    /// )
    /// ```
    bytes32 internal constant TYPE_HASH =
        hex"d5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e489";

    /// @dev The marker value for a sell order for computing the order struct
    /// hash. This allows the EIP-712 compatible wallets to display a
    /// descriptive string for the order kind (instead of 0 or 1).
    ///
    /// This value is pre-computed from the following expression:
    /// ```
    /// keccak256("sell")
    /// ```
    bytes32 internal constant KIND_SELL =
        hex"f3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee346775";

    /// @dev The OrderKind marker value for a buy order for computing the order
    /// struct hash.
    ///
    /// This value is pre-computed from the following expression:
    /// ```
    /// keccak256("buy")
    /// ```
    bytes32 internal constant KIND_BUY =
        hex"6ed88e868af0a1983e3886d5f3e95a2fafbd6c3450bc229e27342283dc429ccc";

    /// @dev The TokenBalance marker value for using direct ERC20 balances for
    /// computing the order struct hash.
    ///
    /// This value is pre-computed from the following expression:
    /// ```
    /// keccak256("erc20")
    /// ```
    bytes32 internal constant BALANCE_ERC20 =
        hex"5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9";

    /// @dev The TokenBalance marker value for using Balancer Vault external
    /// balances (in order to re-use Vault ERC20 approvals) for computing the
    /// order struct hash.
    ///
    /// This value is pre-computed from the following expression:
    /// ```
    /// keccak256("external")
    /// ```
    bytes32 internal constant BALANCE_EXTERNAL =
        hex"abee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea0632";

    /// @dev The TokenBalance marker value for using Balancer Vault internal
    /// balances for computing the order struct hash.
    ///
    /// This value is pre-computed from the following expression:
    /// ```
    /// keccak256("internal")
    /// ```
    bytes32 internal constant BALANCE_INTERNAL =
        hex"4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce";

    /// @dev Marker address used to indicate that the receiver of the trade
    /// proceeds should the owner of the order.
    ///
    /// This is chosen to be `address(0)` for gas efficiency as it is expected
    /// to be the most common case.
    address internal constant RECEIVER_SAME_AS_OWNER = address(0);

    /// @dev The byte length of an order unique identifier.
    uint256 internal constant UID_LENGTH = 56;

    /// @dev Returns the actual receiver for an order. This function checks
    /// whether or not the [`receiver`] field uses the marker value to indicate
    /// it is the same as the order owner.
    ///
    /// @return receiver The actual receiver of trade proceeds.
    function actualReceiver(
        Data memory order,
        address owner
    ) internal pure returns (address receiver) {
        if (order.receiver == RECEIVER_SAME_AS_OWNER) {
            receiver = owner;
        } else {
            receiver = order.receiver;
        }
    }

    /// @dev Return the EIP-712 signing hash for the specified order.
    ///
    /// @param order The order to compute the EIP-712 signing hash for.
    /// @param domainSeparator The EIP-712 domain separator to use.
    /// @return orderDigest The 32 byte EIP-712 struct hash.
    function hash(
        Data memory order,
        bytes32 domainSeparator
    ) internal pure returns (bytes32 orderDigest) {
        bytes32 structHash;

        // NOTE: Compute the EIP-712 order struct hash in place. As suggested
        // in the EIP proposal, noting that the order struct has 12 fields, and
        // prefixing the type hash `(1 + 12) * 32 = 416` bytes to hash.
        // <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#rationale-for-encodedata>
        // solhint-disable-next-line no-inline-assembly
        assembly {
            let dataStart := sub(order, 32)
            let temp := mload(dataStart)
            mstore(dataStart, TYPE_HASH)
            structHash := keccak256(dataStart, 416)
            mstore(dataStart, temp)
        }

        // NOTE: Now that we have the struct hash, compute the EIP-712 signing
        // hash using scratch memory past the free memory pointer. The signing
        // hash is computed from `"\x19\x01" || domainSeparator || structHash`.
        // <https://docs.soliditylang.org/en/v0.7.6/internals/layout_in_memory.html#layout-in-memory>
        // <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#specification>
        // solhint-disable-next-line no-inline-assembly
        assembly {
            let freeMemoryPointer := mload(0x40)
            mstore(freeMemoryPointer, "\x19\x01")
            mstore(add(freeMemoryPointer, 2), domainSeparator)
            mstore(add(freeMemoryPointer, 34), structHash)
            orderDigest := keccak256(freeMemoryPointer, 66)
        }
    }

    /// @dev Packs order UID parameters into the specified memory location. The
    /// result is equivalent to `abi.encodePacked(...)` with the difference that
    /// it allows re-using the memory for packing the order UID.
    ///
    /// This function reverts if the order UID buffer is not the correct size.
    ///
    /// @param orderUid The buffer pack the order UID parameters into.
    /// @param orderDigest The EIP-712 struct digest derived from the order
    /// parameters.
    /// @param owner The address of the user who owns this order.
    /// @param validTo The epoch time at which the order will stop being valid.
    function packOrderUidParams(
        bytes memory orderUid,
        bytes32 orderDigest,
        address owner,
        uint32 validTo
    ) internal pure {
        require(orderUid.length == UID_LENGTH, "GPv2: uid buffer overflow");

        // NOTE: Write the order UID to the allocated memory buffer. The order
        // parameters are written to memory in **reverse order** as memory
        // operations write 32-bytes at a time and we want to use a packed
        // encoding. This means, for example, that after writing the value of
        // `owner` to bytes `20:52`, writing the `orderDigest` to bytes `0:32`
        // will **overwrite** bytes `20:32`. This is desirable as addresses are
        // only 20 bytes and `20:32` should be `0`s:
        //
        //        |           1111111111222222222233333333334444444444555555
        //   byte | 01234567890123456789012345678901234567890123456789012345
        // -------+---------------------------------------------------------
        //  field | [.........orderDigest..........][......owner.......][vT]
        // -------+---------------------------------------------------------
        // mstore |                         [000000000000000000000000000.vT]
        //        |                     [00000000000.......owner.......]
        //        | [.........orderDigest..........]
        //
        // Additionally, since Solidity `bytes memory` are length prefixed,
        // 32 needs to be added to all the offsets.
        //
        // solhint-disable-next-line no-inline-assembly
        assembly {
            mstore(add(orderUid, 56), validTo)
            mstore(add(orderUid, 52), owner)
            mstore(add(orderUid, 32), orderDigest)
        }
    }

    /// @dev Extracts specific order information from the standardized unique
    /// order id of the protocol.
    ///
    /// @param orderUid The unique identifier used to represent an order in
    /// the protocol. This uid is the packed concatenation of the order digest,
    /// the validTo order parameter and the address of the user who created the
    /// order. It is used by the user to interface with the contract directly,
    /// and not by calls that are triggered by the solvers.
    /// @return orderDigest The EIP-712 signing digest derived from the order
    /// parameters.
    /// @return owner The address of the user who owns this order.
    /// @return validTo The epoch time at which the order will stop being valid.
    function extractOrderUidParams(
        bytes calldata orderUid
    )
        internal
        pure
        returns (bytes32 orderDigest, address owner, uint32 validTo)
    {
        require(orderUid.length == UID_LENGTH, "GPv2: invalid uid");

        // Use assembly to efficiently decode packed calldata.
        // solhint-disable-next-line no-inline-assembly
        assembly {
            orderDigest := calldataload(orderUid.offset)
            owner := shr(96, calldataload(add(orderUid.offset, 32)))
            validTo := shr(224, calldataload(add(orderUid.offset, 52)))
        }
    }
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

/// @title ISettlement
/// @notice External interface of CoW Protocol's SolutionSettler contract.
interface ISettlement {
  /// @return domainSeparator The domain separator for IERC1271 signature.
  /// @dev Immutable value, would not change on chain forks.
  function domainSeparator() external view returns (bytes32 domainSeparator);

  /// @return vaultRelayer The address that'll use the pool liquidity in CoWprotocol swaps.
  /// @dev Address that will transfer and transferFrom the pool. Has an infinite allowance.
  function vaultRelayer() external view returns (address vaultRelayer);
}

File 11 of 27 : DataTypes.sol
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2025 Aave Labs
pragma solidity ^0.8.10;

/// @notice Data types used in the Adapter Hooks & Factory.
/// @author Aave Labs.
library DataTypes {
  struct Permit {
    uint256 amount;
    uint256 deadline;
    uint8 v;
    bytes32 r;
    bytes32 s;
  }

  struct CreditDelegationSig {
    uint256 amount;
    uint256 deadline;
    uint8 v;
    bytes32 r;
    bytes32 s;
  }

  // keccak256('AdapterOrderSig(address instance,address sellToken,address buyToken,uint256 sellAmount,uint256 buyAmount,bytes32 kind,uint32 validTo,bytes32 appData)')
  bytes32 public constant ADAPTER_ORDER_TYPEHASH =
    0x1ca15395c04ac473d5b42656e3782ae1fce1a113fdb5432b57f8fb0870fa3178;

  struct AdapterOrderSig {
    address instance;
    address sellToken;
    address buyToken;
    uint256 sellAmount;
    uint256 buyAmount;
    bytes32 kind;
    uint32 validTo;
    bytes32 appData;
  }

  /// @dev Data needed by the AdapterHook for the postHook execution.
  struct HookOrderData {
    // Owner of the AdapterHook Instance (the user signing the Order)
    address owner;
    // Address of the Instance to be receiver of the Order (as specified in the GPv2Order.Data)
    address receiver;
    // The asset being sold (as specified in the GPv2Order.Data)
    address sellToken;
    // The asset being bought (as specified in the GPv2Order.Data)
    address buyToken;
    // The amount to sell (as specified in the GPv2Order.Data)
    uint256 sellAmount;
    // The amount to buy (as specified in the GPv2Order.Data)
    uint256 buyAmount;
    // The kind of swap (as specified in the GPv2Order.Data)
    bytes32 kind;
    // The expiry date of the Order (as specified in the GPv2Order.Data)
    uint256 validTo;
    // The amount taken as Flashloan
    uint256 flashLoanAmount;
    // The fee amount to be repaid on top of the flashLoanAmount
    uint256 flashLoanFeeAmount;
    // The amount of sell token given as parameter for the postHook
    uint256 hookSellTokenAmount;
    // The amount of buy token given as parameter for the postHook
    uint256 hookBuyTokenAmount;
  }

  struct HookAmounts {
    // The amount taken as Flashloan
    uint256 flashLoanAmount;
    // The fee amount to be repaid on top of the flashLoanAmount
    uint256 flashLoanFeeAmount;
    // The amount of sell token given as parameter for the postHook
    uint256 sellTokenAmount;
    // The amount of buy token given as parameter for the postHook
    uint256 buyTokenAmount;
  }

  struct OpenFlashLoan {
    // Whether the AdapterHook Instance that took the Flashloan is active
    bool instanceActive;
    // The asset being lent
    address asset;
    // The total amount of the flashloan (principal + fees)
    uint256 totalAmount;
  }
}

// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2025 Aave Labs
pragma solidity ^0.8.0;

import {DataTypes} from 'src/libraries/DataTypes.sol';

/// @notice Base interface for all Adapter Hooks.
/// @author Aave Labs.
interface IAaveBaseAdapter {
  /// @notice Thrown when the Instance is already initialized.
  error AlreadyInitialized();

  /// @notice Thrown when the caller is not the Instance owner.
  error CallerNotInstanceOwner();

  /// @notice Thrown when the withdrawn amount is not the expected one.
  error InvalidWithdraw();

  /// @notice Thrown when the borrowed amount is not the expected one.
  error InvalidBorrow();

  /// @notice Thrown when the specified amount is invalid.
  error InvalidAmount();

  /// @notice Thrown when the specified `HookSellAmount` is invalid.
  error InvalidHookSellAmount();

  /// @notice Thrown when the current Instance balance is not the amount expected.
  error InvalidBalance();

  /// @notice Thrown when the specified amount is zero.
  error InvalidZeroAmount();

  /// @notice Thrown when the specified address is the zero address.
  error InvalidZeroAddress();

  /// @notice Thrown when the given Order signature is invalid.
  error InvalidOrderSignature();

  /// @notice Thrown when the given Order hash does not match the computed one.
  error OrderHashMismatch();

  /// @notice Thrown when the given Order buyToken is not the expected one.
  error InvalidBuyToken();

  /// @notice Thrown when the given Order sellToken is not the expected one.
  error InvalidSellToken();

  /// @notice Thrown when the given Order expiry is invalid.
  error InvalidOrderExpiry();

  /// @notice Thrown when the Order is expired.
  error OrderExpired();

  /// @notice Thrown when the given Order is a "partially fillable" one.
  error OrderPartiallyFillable();

  /// @notice Thrown when the given Order sellAmount is invalid.
  error InvalidSellAmount();

  /// @notice Thrown when the given Order buyAmount is invalid.
  error InvalidBuyAmount();

  /// @notice Thrown when the given Order kind is invalid.
  error InvalidOrderKind();

  /// @notice Thrown when the given Order receiver is invalid.
  error InvalidOrderReceiver();

  /// @notice Thrown when the given Order fee is not null.
  error OrderFeeNotNull();

  /// @notice Thrown when the given Order sellTokenBalance or buyTokenBalance is not null.
  error InvalidOrderTokenBalancer();

  /// @notice Sets the parameters of an Instance.
  /// @param hookData_ The HookOrderData struct containing the order details & postHook parameters.
  function setParameters(DataTypes.HookOrderData calldata hookData_) external;

  /// @notice Returns the stored HookOrderData struct.
  /// @return The stored HookOrderData struct.
  function getHookData() external view returns (DataTypes.HookOrderData memory);

  /// @notice AaveV3AdapterFactory contract.
  function FACTORY() external view returns (address);

  /// @notice Settlement contract.
  function SETTLEMENT_CONTRACT() external view returns (address);

  /// @notice Aave Pool contract.
  function AAVE_POOL() external view returns (address);
}

// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2025 Aave Labs
pragma solidity ^0.8.0;

import {IFlashLoanRouter} from 'cowprotocol/flash-loan-router/interface/IFlashLoanRouter.sol';
import {ICowSettlement} from 'cowprotocol/flash-loan-router/interface/ICowSettlement.sol';
import {GPv2Order} from 'cowprotocol/contracts/libraries/GPv2Order.sol';

import {DataTypes} from 'src/libraries/DataTypes.sol';

/// @notice Adapter Factory Base interface.
/// @author Aave Labs.
interface IBaseAdapterFactory {
  /// @notice Thrown when the caller is not an Instance deployed by the Factory.
  error CallerNotInstance();

  /// @notice Thrown when the caller is not the Router.
  error CallerNotRouter();

  /// @notice Thrown when the specified amount is null.
  error InvalidZeroAmount();

  /// @notice Thrown when the specified address is the zero address.
  error InvalidZeroAddress();

  /// @notice Thrown when the specified implementation is already listed.
  error ImplementationAlreadyListed();

  /// @notice Thrown when the specified implementation is not active.
  error ImplementationNotActive();

  /// @notice Thrown when the Instance is not initialized.
  error InstanceNotInitialized();

  /// @notice Thrown when the Instance is already deployed.
  error InstanceAlreadyDeployed();

  /// @notice Thrown when the order receiver is invalid.
  error InvalidOrderReceiver();

  /// @notice Thrown when the specified lender is not the valid one for the Factory.
  error InvalidLender();

  /// @notice Thrown when the calling Instance has nothing to repay.
  error NothingToRepay();

  /// @notice Thrown when the order has been cancelled by the user.
  error InstanceCancelled();

  /// @notice Emitted when an AdapterHook Implementations status is updated.
  event SetAdapterImplementation(address indexed adapterImplementation, bool active);

  /// @notice Emitted when an Instance owner cancels it.
  event CancelInstance(address indexed user, address indexed instanceAddress);

  /// @notice Settlement contract.
  function SETTLEMENT_CONTRACT() external view returns (ICowSettlement);

  /// @notice FlashLoanRouter contract.
  function ROUTER() external view returns (IFlashLoanRouter);

  /// @notice Returns the domain separator used in the EIP712 encoding of the AdapterOrderSig struct.
  /// @return The domain separator.
  function DOMAIN_SEPARATOR() external view returns (bytes32);

  /// @notice Notifies the AdapterFactory that a FlashLoan is ready to be repaid.
  function notifyRepayFlashLoan() external;

  /// @notice Deploys an Adapter Instance and transfers the FlashLoaned assets to it (must have been initiated before).
  /// @param adapterImplementation The address of the Adapter Instance implementation to clone.
  /// @param hookData The HookOrderData struct containing the order details & postHook parameters.
  function deployAndTransferFlashLoan(
    address adapterImplementation,
    DataTypes.HookOrderData memory hookData
  ) external;

  /// @notice Cancels an Adapter Instance to be deployed by the Factory.
  /// @dev This is used to cancel a pending EIP-1271 Order before it is executed, by blocking the deployment of the Instance.
  /// @param instance The address of the Adapter Instance to cancel.
  function cancelInstance(address instance) external;

  /// @notice Returns the determined address of an Adapter Instance to clone based on a specific Order.
  /// @param adapterImplementation The address of the Adapter Implementation to clone.
  /// @param hookData The HookOrderData struct containing the order details & postHook parameters.
  /// @return The determined address of the Adapter Instance.
  function getInstanceDeterministicAddress(
    address adapterImplementation,
    DataTypes.HookOrderData memory hookData
  ) external view returns (address);

  /// @notice Verifies that the signature provided for an Order using an Adapter is valid.
  /// @param orderOwner The address of the owner of the Order.
  /// @param order The Order data to verify.
  /// @param signature The signature to verify.
  /// @return True if the signature is valid, false otherwise.
  function verifyOrderSignature(
    address orderOwner,
    GPv2Order.Data memory order,
    bytes memory signature
  ) external view returns (bool);

  /// @notice Sets the status of an AdapterHook Implementation.
  /// @param adapterImplementation The address of the Adapter Implementation.
  /// @param active True to activate, false to deactivate.
  function setAdapterImplementation(address adapterImplementation, bool active) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)

pragma solidity >=0.6.2;

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

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
  /**
   * @dev Returns the amount of tokens in existence.
   */
  function totalSupply() external view returns (uint256);

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

  /**
   * @dev Moves `amount` tokens from the caller's account to `recipient`.
   *
   * Returns a boolean value indicating whether the operation succeeded.
   *
   * Emits a {Transfer} event.
   */
  function transfer(address recipient, uint256 amount) 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 `amount` 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 amount) external returns (bool);

  /**
   * @dev Moves `amount` tokens from `sender` to `recipient` using the
   * allowance mechanism. `amount` is then deducted from the caller's
   * allowance.
   *
   * Returns a boolean value indicating whether the operation succeeded.
   *
   * Emits a {Transfer} event.
   */
  function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

  /**
   * @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);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title IPoolAddressesProvider
 * @author Aave
 * @notice Defines the basic interface for a Pool Addresses Provider.
 */
interface IPoolAddressesProvider {
  /**
   * @dev Emitted when the market identifier is updated.
   * @param oldMarketId The old id of the market
   * @param newMarketId The new id of the market
   */
  event MarketIdSet(string indexed oldMarketId, string indexed newMarketId);

  /**
   * @dev Emitted when the pool is updated.
   * @param oldAddress The old address of the Pool
   * @param newAddress The new address of the Pool
   */
  event PoolUpdated(address indexed oldAddress, address indexed newAddress);

  /**
   * @dev Emitted when the pool configurator is updated.
   * @param oldAddress The old address of the PoolConfigurator
   * @param newAddress The new address of the PoolConfigurator
   */
  event PoolConfiguratorUpdated(address indexed oldAddress, address indexed newAddress);

  /**
   * @dev Emitted when the price oracle is updated.
   * @param oldAddress The old address of the PriceOracle
   * @param newAddress The new address of the PriceOracle
   */
  event PriceOracleUpdated(address indexed oldAddress, address indexed newAddress);

  /**
   * @dev Emitted when the ACL manager is updated.
   * @param oldAddress The old address of the ACLManager
   * @param newAddress The new address of the ACLManager
   */
  event ACLManagerUpdated(address indexed oldAddress, address indexed newAddress);

  /**
   * @dev Emitted when the ACL admin is updated.
   * @param oldAddress The old address of the ACLAdmin
   * @param newAddress The new address of the ACLAdmin
   */
  event ACLAdminUpdated(address indexed oldAddress, address indexed newAddress);

  /**
   * @dev Emitted when the price oracle sentinel is updated.
   * @param oldAddress The old address of the PriceOracleSentinel
   * @param newAddress The new address of the PriceOracleSentinel
   */
  event PriceOracleSentinelUpdated(address indexed oldAddress, address indexed newAddress);

  /**
   * @dev Emitted when the pool data provider is updated.
   * @param oldAddress The old address of the PoolDataProvider
   * @param newAddress The new address of the PoolDataProvider
   */
  event PoolDataProviderUpdated(address indexed oldAddress, address indexed newAddress);

  /**
   * @dev Emitted when a new proxy is created.
   * @param id The identifier of the proxy
   * @param proxyAddress The address of the created proxy contract
   * @param implementationAddress The address of the implementation contract
   */
  event ProxyCreated(
    bytes32 indexed id,
    address indexed proxyAddress,
    address indexed implementationAddress
  );

  /**
   * @dev Emitted when a new non-proxied contract address is registered.
   * @param id The identifier of the contract
   * @param oldAddress The address of the old contract
   * @param newAddress The address of the new contract
   */
  event AddressSet(bytes32 indexed id, address indexed oldAddress, address indexed newAddress);

  /**
   * @dev Emitted when the implementation of the proxy registered with id is updated
   * @param id The identifier of the contract
   * @param proxyAddress The address of the proxy contract
   * @param oldImplementationAddress The address of the old implementation contract
   * @param newImplementationAddress The address of the new implementation contract
   */
  event AddressSetAsProxy(
    bytes32 indexed id,
    address indexed proxyAddress,
    address oldImplementationAddress,
    address indexed newImplementationAddress
  );

  /**
   * @notice Returns the id of the Aave market to which this contract points to.
   * @return The market id
   */
  function getMarketId() external view returns (string memory);

  /**
   * @notice Associates an id with a specific PoolAddressesProvider.
   * @dev This can be used to create an onchain registry of PoolAddressesProviders to
   * identify and validate multiple Aave markets.
   * @param newMarketId The market id
   */
  function setMarketId(string calldata newMarketId) external;

  /**
   * @notice Returns an address by its identifier.
   * @dev The returned address might be an EOA or a contract, potentially proxied
   * @dev It returns ZERO if there is no registered address with the given id
   * @param id The id
   * @return The address of the registered for the specified id
   */
  function getAddress(bytes32 id) external view returns (address);

  /**
   * @notice General function to update the implementation of a proxy registered with
   * certain `id`. If there is no proxy registered, it will instantiate one and
   * set as implementation the `newImplementationAddress`.
   * @dev IMPORTANT Use this function carefully, only for ids that don't have an explicit
   * setter function, in order to avoid unexpected consequences
   * @param id The id
   * @param newImplementationAddress The address of the new implementation
   */
  function setAddressAsProxy(bytes32 id, address newImplementationAddress) external;

  /**
   * @notice Sets an address for an id replacing the address saved in the addresses map.
   * @dev IMPORTANT Use this function carefully, as it will do a hard replacement
   * @param id The id
   * @param newAddress The address to set
   */
  function setAddress(bytes32 id, address newAddress) external;

  /**
   * @notice Returns the address of the Pool proxy.
   * @return The Pool proxy address
   */
  function getPool() external view returns (address);

  /**
   * @notice Updates the implementation of the Pool, or creates a proxy
   * setting the new `pool` implementation when the function is called for the first time.
   * @param newPoolImpl The new Pool implementation
   */
  function setPoolImpl(address newPoolImpl) external;

  /**
   * @notice Returns the address of the PoolConfigurator proxy.
   * @return The PoolConfigurator proxy address
   */
  function getPoolConfigurator() external view returns (address);

  /**
   * @notice Updates the implementation of the PoolConfigurator, or creates a proxy
   * setting the new `PoolConfigurator` implementation when the function is called for the first time.
   * @param newPoolConfiguratorImpl The new PoolConfigurator implementation
   */
  function setPoolConfiguratorImpl(address newPoolConfiguratorImpl) external;

  /**
   * @notice Returns the address of the price oracle.
   * @return The address of the PriceOracle
   */
  function getPriceOracle() external view returns (address);

  /**
   * @notice Updates the address of the price oracle.
   * @param newPriceOracle The address of the new PriceOracle
   */
  function setPriceOracle(address newPriceOracle) external;

  /**
   * @notice Returns the address of the ACL manager.
   * @return The address of the ACLManager
   */
  function getACLManager() external view returns (address);

  /**
   * @notice Updates the address of the ACL manager.
   * @param newAclManager The address of the new ACLManager
   */
  function setACLManager(address newAclManager) external;

  /**
   * @notice Returns the address of the ACL admin.
   * @return The address of the ACL admin
   */
  function getACLAdmin() external view returns (address);

  /**
   * @notice Updates the address of the ACL admin.
   * @param newAclAdmin The address of the new ACL admin
   */
  function setACLAdmin(address newAclAdmin) external;

  /**
   * @notice Returns the address of the price oracle sentinel.
   * @return The address of the PriceOracleSentinel
   */
  function getPriceOracleSentinel() external view returns (address);

  /**
   * @notice Updates the address of the price oracle sentinel.
   * @param newPriceOracleSentinel The address of the new PriceOracleSentinel
   */
  function setPriceOracleSentinel(address newPriceOracleSentinel) external;

  /**
   * @notice Returns the address of the data provider.
   * @return The address of the DataProvider
   */
  function getPoolDataProvider() external view returns (address);

  /**
   * @notice Updates the address of the data provider.
   * @param newDataProvider The address of the new DataProvider
   */
  function setPoolDataProvider(address newDataProvider) external;
}

File 17 of 27 : DataTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

library DataTypes {
  /**
   * This exists specifically to maintain the `getReserveData()` interface, since the new, internal
   * `ReserveData` struct includes the reserve's `virtualUnderlyingBalance`.
   */
  struct ReserveDataLegacy {
    //stores the reserve configuration
    ReserveConfigurationMap configuration;
    //the liquidity index. Expressed in ray
    uint128 liquidityIndex;
    //the current supply rate. Expressed in ray
    uint128 currentLiquidityRate;
    //variable borrow index. Expressed in ray
    uint128 variableBorrowIndex;
    //the current variable borrow rate. Expressed in ray
    uint128 currentVariableBorrowRate;
    // DEPRECATED on v3.2.0
    uint128 currentStableBorrowRate;
    //timestamp of last update
    uint40 lastUpdateTimestamp;
    //the id of the reserve. Represents the position in the list of the active reserves
    uint16 id;
    //aToken address
    address aTokenAddress;
    // DEPRECATED on v3.2.0
    address stableDebtTokenAddress;
    //variableDebtToken address
    address variableDebtTokenAddress;
    // DEPRECATED on v3.4.0, should use the `RESERVE_INTEREST_RATE_STRATEGY` variable from the Pool contract
    address interestRateStrategyAddress;
    //the current treasury balance, scaled
    uint128 accruedToTreasury;
    // DEPRECATED on v3.4.0
    uint128 unbacked;
    //the outstanding debt borrowed against this asset in isolation mode
    uint128 isolationModeTotalDebt;
  }

  struct ReserveData {
    //stores the reserve configuration
    ReserveConfigurationMap configuration;
    //the liquidity index. Expressed in ray
    uint128 liquidityIndex;
    //the current supply rate. Expressed in ray
    uint128 currentLiquidityRate;
    //variable borrow index. Expressed in ray
    uint128 variableBorrowIndex;
    //the current variable borrow rate. Expressed in ray
    uint128 currentVariableBorrowRate;
    /// @notice reused `__deprecatedStableBorrowRate` storage from pre 3.2
    // the current accumulate deficit in underlying tokens
    uint128 deficit;
    //timestamp of last update
    uint40 lastUpdateTimestamp;
    //the id of the reserve. Represents the position in the list of the active reserves
    uint16 id;
    //timestamp until when liquidations are not allowed on the reserve, if set to past liquidations will be allowed
    uint40 liquidationGracePeriodUntil;
    //aToken address
    address aTokenAddress;
    // DEPRECATED on v3.2.0
    address __deprecatedStableDebtTokenAddress;
    //variableDebtToken address
    address variableDebtTokenAddress;
    // DEPRECATED on v3.4.0, should use the `RESERVE_INTEREST_RATE_STRATEGY` variable from the Pool contract
    address __deprecatedInterestRateStrategyAddress;
    //the current treasury balance, scaled
    uint128 accruedToTreasury;
    // In aave 3.3.0 this storage slot contained the `unbacked`
    uint128 virtualUnderlyingBalance;
    //the outstanding debt borrowed against this asset in isolation mode
    uint128 isolationModeTotalDebt;
    //the amount of underlying accounted for by the protocol
    // DEPRECATED on v3.4.0. Moved into the same slot as accruedToTreasury for optimized storage access.
    uint128 __deprecatedVirtualUnderlyingBalance;
  }

  struct ReserveConfigurationMap {
    //bit 0-15: LTV
    //bit 16-31: Liq. threshold
    //bit 32-47: Liq. bonus
    //bit 48-55: Decimals
    //bit 56: reserve is active
    //bit 57: reserve is frozen
    //bit 58: borrowing is enabled
    //bit 59: DEPRECATED: stable rate borrowing enabled
    //bit 60: asset is paused
    //bit 61: borrowing in isolation mode is enabled
    //bit 62: siloed borrowing enabled
    //bit 63: flashloaning enabled
    //bit 64-79: reserve factor
    //bit 80-115: borrow cap in whole tokens, borrowCap == 0 => no cap
    //bit 116-151: supply cap in whole tokens, supplyCap == 0 => no cap
    //bit 152-167: liquidation protocol fee
    //bit 168-175: DEPRECATED: eMode category
    //bit 176-211: DEPRECATED: unbacked mint cap
    //bit 212-251: debt ceiling for isolation mode with (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals
    //bit 252: DEPRECATED: virtual accounting is enabled for the reserve
    //bit 253-255 unused

    uint256 data;
  }

  struct UserConfigurationMap {
    /**
     * @dev Bitmap of the users collaterals and borrows. It is divided in pairs of bits, one pair per asset.
     * The first bit indicates if an asset is used as collateral by the user, the second whether an
     * asset is borrowed by the user.
     */
    uint256 data;
  }

  // DEPRECATED: kept for backwards compatibility, might be removed in a future version
  struct EModeCategoryLegacy {
    // each eMode category has a custom ltv and liquidation threshold
    uint16 ltv;
    uint16 liquidationThreshold;
    uint16 liquidationBonus;
    // DEPRECATED
    address priceSource;
    string label;
  }

  struct CollateralConfig {
    uint16 ltv;
    uint16 liquidationThreshold;
    uint16 liquidationBonus;
  }

  struct EModeCategoryBaseConfiguration {
    uint16 ltv;
    uint16 liquidationThreshold;
    uint16 liquidationBonus;
    string label;
  }

  struct EModeCategory {
    // each eMode category has a custom ltv and liquidation threshold
    uint16 ltv;
    uint16 liquidationThreshold;
    uint16 liquidationBonus;
    uint128 collateralBitmap;
    string label;
    uint128 borrowableBitmap;
  }

  enum InterestRateMode {
    NONE,
    __DEPRECATED,
    VARIABLE
  }

  struct ReserveCache {
    uint256 currScaledVariableDebt;
    uint256 nextScaledVariableDebt;
    uint256 currLiquidityIndex;
    uint256 nextLiquidityIndex;
    uint256 currVariableBorrowIndex;
    uint256 nextVariableBorrowIndex;
    uint256 currLiquidityRate;
    uint256 currVariableBorrowRate;
    uint256 reserveFactor;
    ReserveConfigurationMap reserveConfiguration;
    address aTokenAddress;
    address variableDebtTokenAddress;
    uint40 reserveLastUpdateTimestamp;
  }

  struct ExecuteLiquidationCallParams {
    address liquidator;
    uint256 debtToCover;
    address collateralAsset;
    address debtAsset;
    address borrower;
    bool receiveAToken;
    address priceOracle;
    uint8 borrowerEModeCategory;
    address priceOracleSentinel;
    address interestRateStrategyAddress;
  }

  struct ExecuteSupplyParams {
    address user;
    address asset;
    address interestRateStrategyAddress;
    uint256 amount;
    address onBehalfOf;
    uint16 referralCode;
  }

  struct ExecuteBorrowParams {
    address asset;
    address user;
    address onBehalfOf;
    address interestRateStrategyAddress;
    uint256 amount;
    InterestRateMode interestRateMode;
    uint16 referralCode;
    bool releaseUnderlying;
    address oracle;
    uint8 userEModeCategory;
    address priceOracleSentinel;
  }

  struct ExecuteRepayParams {
    address asset;
    address user;
    address interestRateStrategyAddress;
    uint256 amount;
    InterestRateMode interestRateMode;
    address onBehalfOf;
    bool useATokens;
    address oracle;
    uint8 userEModeCategory;
  }

  struct ExecuteWithdrawParams {
    address user;
    address asset;
    address interestRateStrategyAddress;
    uint256 amount;
    address to;
    address oracle;
    uint8 userEModeCategory;
  }

  struct ExecuteEliminateDeficitParams {
    address user;
    address asset;
    address interestRateStrategyAddress;
    uint256 amount;
  }

  struct FinalizeTransferParams {
    address asset;
    address from;
    address to;
    uint256 scaledAmount;
    uint256 scaledBalanceFromBefore;
    uint256 scaledBalanceToBefore;
    address oracle;
    uint8 fromEModeCategory;
  }

  struct FlashloanParams {
    address user;
    address receiverAddress;
    address[] assets;
    uint256[] amounts;
    uint256[] interestRateModes;
    address interestRateStrategyAddress;
    address onBehalfOf;
    bytes params;
    uint16 referralCode;
    uint256 flashLoanPremium;
    address addressesProvider;
    address pool;
    uint8 userEModeCategory;
    bool isAuthorizedFlashBorrower;
  }

  struct FlashloanSimpleParams {
    address user;
    address receiverAddress;
    address asset;
    address interestRateStrategyAddress;
    uint256 amount;
    bytes params;
    uint16 referralCode;
    uint256 flashLoanPremium;
  }

  struct FlashLoanRepaymentParams {
    address user;
    uint256 amount;
    uint256 totalPremium;
    address asset;
    address interestRateStrategyAddress;
    address receiverAddress;
    uint16 referralCode;
  }

  struct CalculateUserAccountDataParams {
    UserConfigurationMap userConfig;
    address user;
    address oracle;
    uint8 userEModeCategory;
  }

  struct ValidateBorrowParams {
    ReserveCache reserveCache;
    UserConfigurationMap userConfig;
    address asset;
    address userAddress;
    uint256 amountScaled;
    InterestRateMode interestRateMode;
    address oracle;
    uint8 userEModeCategory;
    address priceOracleSentinel;
  }

  struct ValidateLiquidationCallParams {
    ReserveCache debtReserveCache;
    uint256 totalDebt;
    uint256 healthFactor;
    address priceOracleSentinel;
    address borrower;
    address liquidator;
  }

  struct CalculateInterestRatesParams {
    uint256 unbacked;
    uint256 liquidityAdded;
    uint256 liquidityTaken;
    uint256 totalDebt;
    uint256 reserveFactor;
    address reserve;
    // @notice DEPRECATED in 3.4, but kept for backwards compatibility
    bool usingVirtualBalance;
    uint256 virtualUnderlyingBalance;
  }

  struct InitReserveParams {
    address asset;
    address aTokenAddress;
    address variableDebtAddress;
    uint16 reservesCount;
    uint16 maxNumberReserves;
  }
}

// SPDX-License-Identifier: MIT

// Vendored from OpenZeppelin contracts with minor modifications:
// - Modified Solidity version
// - Formatted code
// - Added `name`, `symbol` and `decimals` function declarations
// <https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/token/ERC20/IERC20.sol>

pragma solidity >=0.7.6 <0.9.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface 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 number of decimals the token uses.
     */
    function decimals() external view returns (uint8);

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

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

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(
        address recipient,
        uint256 amount
    ) 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 `amount` 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 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    /**
     * @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
    );
}

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8;

import {Loan} from "../library/Loan.sol";
import {ICowAuthentication} from "../vendored/ICowAuthentication.sol";
import {ICowSettlement} from "./ICowSettlement.sol";

/// @title Flash-loan Router Interface
/// @author CoW DAO developers
/// @notice Interface describing the functions available for interacting with
/// the flash-loan router.
/// @dev The flash loan router is intended to be a solver for CoW Protocol.
interface IFlashLoanRouter {
    /// @notice Request all flash loan specified in the input and, after that,
    /// executes the specified settlement.
    /// @dev It's the solver's responsibility to make sure the loan is specified
    /// correctly. The router contract offers no validation of the fact that
    /// the flash loan proceeds are available for spending.
    ///
    /// The repayment of a flash loan is different based on the protocol. For
    /// example, some expect to retrieve the funds from this borrower contract
    /// through `transferFrom`, while other check the lender balance is as
    /// expected after the flash loan has been processed. The executed
    /// settlement must be built to cater to the needs of the specified lender.
    ///
    /// A settlement can be executed at most once in a call. The settlement
    /// data cannot change during execution. Only the settle function can be
    /// called. All of this is also the case if the lender is untrusted.
    /// @param loans The list of flash loans to be requested before the
    /// settlement is executed. The loans will be requested in the specified
    /// order.
    /// @param settlement The ABI-encoded bytes for a call to `settle()` (as
    /// in `abi.encodeCall`).
    function flashLoanAndSettle(Loan.Data[] calldata loans, bytes calldata settlement) external;

    /// @notice Once a borrower has received the proceeds of a flash loan, it
    /// calls back the router through this function.
    /// @param encodedLoansWithSettlement The data the borrower received when
    /// it was called, without any modification.
    function borrowerCallBack(bytes calldata encodedLoansWithSettlement) external;

    /// @notice The settlement contract supported by this router. This is the
    /// contract that will be called when the settlement is executed.
    function settlementContract() external view returns (ICowSettlement);

    /// @notice The settlement authenticator contract for CoW Protocol. This
    /// contract determines who the solvers for CoW Protocol are.
    function settlementAuthentication() external view returns (ICowAuthentication);
}

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8;

/// @notice An interface for CoW Protocol's settlement contract that only
/// enumerates the functions and types needed for this project.
/// For more information, see the project's repository:
/// <https://github.com/cowprotocol/contracts/blob/9c1984b864d0a6703a877a088be6dac56450808c/src/contracts/GPv2Settlement.sol>
/// The code and comments have been mostly copied from the linked resources.
interface ICowSettlement {
    /// @notice A struct representing a trade to be executed as part a batch
    /// settlement.
    /// @dev See <https://github.com/cowprotocol/contracts/blob/9c1984b864d0a6703a877a088be6dac56450808c/src/contracts/libraries/GPv2Trade.sol#L14-L28>.
    struct Trade {
        uint256 sellTokenIndex;
        uint256 buyTokenIndex;
        address receiver;
        uint256 sellAmount;
        uint256 buyAmount;
        uint32 validTo;
        bytes32 appData;
        uint256 feeAmount;
        uint256 flags;
        uint256 executedAmount;
        bytes signature;
    }

    /// @notice Interaction data for performing arbitrary contract interactions.
    /// Submitted to [`GPv2Settlement.settle`] for code execution.
    /// @dev See <https://github.com/cowprotocol/contracts/blob/9c1984b864d0a6703a877a088be6dac56450808c/src/contracts/libraries/GPv2Interaction.sol#L7-L13>.
    struct Interaction {
        address target;
        uint256 value;
        bytes callData;
    }

    /// @notice The authenticator is used to determine who can call the settle
    /// function. That is, only authorized solvers have the ability to invoke
    /// settlements. Any valid authenticator implements an isSolver method
    /// called by the onlySolver modifier below.
    /// @dev See <https://github.com/cowprotocol/contracts/blob/9c1984b864d0a6703a877a088be6dac56450808c/src/contracts/GPv2Settlement.sol#L28-L32>.
    function authenticator() external view returns (address);

    /// @notice Settle the specified orders at a clearing price. Note that it is
    /// the responsibility of the caller to ensure that all GPv2 invariants are
    /// upheld for the input settlement, otherwise this call will revert.
    /// Namely:
    /// - All orders are valid and signed
    /// - Accounts have sufficient balance and approval.
    /// - Settlement contract has sufficient balance to execute trades. Note
    ///   this implies that the accumulated fees held in the contract can also
    ///   be used for settlement. This is OK since:
    ///   - Solvers need to be authorized
    ///   - Misbehaving solvers will be slashed for abusing accumulated fees for
    ///     settlement
    ///   - Critically, user orders are entirely protected
    ///
    /// @param tokens An array of ERC20 tokens to be traded in the settlement.
    /// Trades encode tokens as indices into this array.
    /// @param clearingPrices An array of clearing prices where the `i`-th price
    /// is for the `i`-th token in the [`tokens`] array.
    /// @param trades Trades for signed orders.
    /// @param interactions Smart contract interactions split into three
    /// separate lists to be run before the settlement, during the settlement
    /// and after the settlement respectively.
    /// @dev See <https://github.com/cowprotocol/contracts/blob/9c1984b864d0a6703a877a088be6dac56450808c/src/contracts/GPv2Settlement.sol#L99-L126>.
    function settle(
        address[] calldata tokens,
        uint256[] calldata clearingPrices,
        Trade[] calldata trades,
        Interaction[][3] calldata interactions
    ) external;
}

File 21 of 27 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

pragma solidity >=0.4.16;

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

File 22 of 27 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity >=0.4.16;

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

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8;

import {IBorrower} from "../interface/IBorrower.sol";
import {IERC20} from "../vendored/IERC20.sol";

/// @title Loan Library
/// @author CoW DAO developers
/// @notice A library describing a flash-loan request by the flash-loan router
/// and providing related utility functions.
library Loan {
    /// @notice The representation of a flash-loan request by the flash-loan
    /// router.
    struct Data {
        /// @notice The amount of funds requested from the lender.
        uint256 amount;
        /// @notice The contract that directly requests the flash loan from the
        /// lender and eventually calls back the router.
        IBorrower borrower;
        /// @notice The contract that loans out the funds to the borrower.
        address lender;
        /// @notice The token that is requested in the flash loan.
        IERC20 token;
    }

    /// @notice A type that wraps a pointer to raw data in memory.
    /// @dev A loan is expected to be encoded in memory as follows:
    ///
    /// Content: |--  amount  --||-- borrower --||--  lender  --||--  token   --|
    /// Length:  |<--32 bytes-->||<--20 bytes-->||<--20 bytes-->||<--20 bytes-->|
    type EncodedData is uint256;

    // This is a list of offsets to add to the memory pointer to get the memory
    // location of the respective loan parameter. Note: -12 because addresses
    // are zero-padded to the left and mload/mstore work on groups of 32 bytes.
    uint256 private constant OFFSET_BORROWER = 32 - 12;
    uint256 private constant OFFSET_LENDER = 32 + 1 * 20 - 12;
    uint256 private constant OFFSET_TOKEN = 32 + 2 * 20 - 12;

    /// @notice The number of sequential bytes required to encode a loan in
    /// memory.
    uint256 internal constant ENCODED_LOAN_BYTE_SIZE = 32 + 3 * 20;

    /// @notice Write the input loan to the memory location pointed to by the
    /// input encodedLoan.
    /// @param encodedLoan The memory location from which to start writing the
    /// byte representation of the loan. It is assumed to have at least
    /// `ENCODED_LOAN_BYTE_SIZE` available from that point it in memory.
    /// @param loan The loan to store.
    function store(EncodedData encodedLoan, Data calldata loan) internal pure {
        uint256 amount = loan.amount;
        IBorrower borrower = loan.borrower;
        address lender = loan.lender;
        IERC20 token = loan.token;

        // Note: addresses are right-aligned, memory is written to starting
        // from the end and overwriting the address left-side padding.
        assembly ("memory-safe") {
            // Unchecked: we assume that the input value isn't at the end of the
            // memory array. This does not happen with Solidity standard memory
            // allocation.
            mstore(add(encodedLoan, OFFSET_TOKEN), token)
            mstore(add(encodedLoan, OFFSET_LENDER), lender)
            mstore(add(encodedLoan, OFFSET_BORROWER), borrower)
            // offset is zero
            mstore(encodedLoan, amount)
        }
    }

    /// @notice Reads the loan parameter from the input location in memory.
    /// @param loan The memory location from which to read the loan.
    /// @return amount The amount to be borrowed (see `Loan.Data`).
    /// @return borrower The address of the borrower contract (see `Loan.Data`).
    /// @return lender The lender address (see `Loan.Data`).
    /// @return token The token to borrow (see `Loan.Data`).
    function decode(EncodedData loan)
        internal
        pure
        returns (uint256 amount, IBorrower borrower, address lender, IERC20 token)
    {
        assembly ("memory-safe") {
            // Note: the values don't need to be masked since masking occurs
            // when the value is accessed and not when stored.
            // <https://docs.soliditylang.org/en/v0.8.28/assembly.html#access-to-external-variables-functions-and-libraries>
            amount := mload(loan)
            borrower := mload(add(loan, OFFSET_BORROWER))
            lender := mload(add(loan, OFFSET_LENDER))
            token := mload(add(loan, OFFSET_TOKEN))
        }
    }
}

// SPDX-License-Identifier: LGPL-3.0-or-later

// Vendored from CoW DAO contracts with minor modifications:
// - Formatted code
// - Changed contract name
// <https://github.com/cowprotocol/contracts/blob/9c1984b864d0a6703a877a088be6dac56450808c/src/contracts/interfaces/GPv2Authentication.sol>

pragma solidity >=0.7.6 <0.9.0;

/// @title Gnosis Protocol v2 Authentication Interface
/// @author Gnosis Developers
interface ICowAuthentication {
    /// @dev determines whether the provided address is an authenticated solver.
    /// @param prospectiveSolver the address of prospective solver.
    /// @return true when prospectiveSolver is an authenticated solver, otherwise false.
    function isSolver(address prospectiveSolver) external view returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity >=0.4.16;

/**
 * @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);
}

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8;

import {IERC20} from "../vendored/IERC20.sol";
import {ICowSettlement} from "./ICowSettlement.sol";
import {IFlashLoanRouter} from "./IFlashLoanRouter.sol";

/// @title Flash-loan Borrower
/// @author CoW DAO developers
/// @notice The CoW Protocol flash-loan router uses the flash-loan borrower
/// contract as the intermediary that requests funds through a flash loan.
/// Different flash-loan protocols have different logic for flash loans:
/// usually, the call-back function name and parameters are different. Each
/// flash-loan protocol must have a dedicated Borrower contract to be supported
/// by the flash-loan router.
/// A concrete borrower implementation generally calls a dedicated flash-loan
/// function on the lender and then awaits for a callback from it. The borrower
/// then calls back the router for further processing.
interface IBorrower {
    /// @notice Requests a flash loan with the specified parameters from the
    /// lender and, once the funds have been received, call back the router
    /// while passing through the specified custom data. The flash-loan
    /// repayment is expected to take place during the final settlement in the
    /// router.
    /// @param lender The address of the flash-loan lender from which to borrow.
    /// @param token The token that is requested in the flash loan.
    /// @param amount The amount of funds requested from the lender.
    /// @param callBackData The data to send back when calling the router once
    /// the loan is received.
    function flashLoanAndCallBack(address lender, IERC20 token, uint256 amount, bytes calldata callBackData) external;

    /// @notice Approves the target address to spend the specified token on
    /// behalf of the Borrower up to the specified amount.
    /// @dev In general, the only way to transfer funds out of this contract is
    /// through a call to this function and a subsequent call to `transferFrom`.
    /// This approval is expected to work similarly to an ERC-20 approval (in
    /// particular, the allowance doesn't reset once the call is terminated).
    /// @param token The token to approve for transferring.
    /// @param target The address that will be allowed to spend the token.
    /// @param amount The amount of tokens to set as the allowance.
    function approve(IERC20 token, address target, uint256 amount) external;

    /// @notice The settlement contract supported by this contract.
    function settlementContract() external view returns (ICowSettlement);

    /// @notice The router contract that manages this borrower contract. It will
    /// be called back once the flash-loan proceeds are received and is the only
    /// address that can trigger a flash loan request.
    function router() external view returns (IFlashLoanRouter);
}

// SPDX-License-Identifier: MIT

// Vendored from OpenZeppelin contracts with minor modifications:
// - Formatted code
// <https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v5.2/contracts/token/ERC20/IERC20.sol>
// Note: v5.2 points to commit acd4ff74de833399287ed6b31b4debf6b2b35527.

// 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);
}

Settings
{
  "remappings": [
    "forge-std/=lib/forge-std/src/",
    "solidity-utils/=lib/aave-v3-origin/lib/solidity-utils/src/contracts/",
    "aave-v3-origin/=lib/aave-v3-origin/src/",
    "aave-address-book/=lib/aave-address-book/src/",
    "openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "cowprotocol/flash-loan-router/=lib/flash-loan-router/src/",
    "cowprotocol/contracts/=lib/contracts/src/contracts/",
    "cowprotocol/test/=lib/contracts/test/",
    "@openzeppelin/contracts-upgradeable/=lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "contracts/=lib/contracts/src/",
    "ds-test/=lib/aave-v3-origin/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "flash-loan-router/=lib/flash-loan-router/",
    "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
    "openzeppelin-contracts-upgradeable/=lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 999999
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false
}

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"factory_","type":"address"},{"internalType":"address","name":"aavePool_","type":"address"},{"internalType":"address","name":"settlement_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"CallerNotInstanceOwner","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidBalance","type":"error"},{"inputs":[],"name":"InvalidBorrow","type":"error"},{"inputs":[],"name":"InvalidBuyAmount","type":"error"},{"inputs":[],"name":"InvalidBuyToken","type":"error"},{"inputs":[],"name":"InvalidHookSellAmount","type":"error"},{"inputs":[],"name":"InvalidOrderExpiry","type":"error"},{"inputs":[],"name":"InvalidOrderKind","type":"error"},{"inputs":[],"name":"InvalidOrderReceiver","type":"error"},{"inputs":[],"name":"InvalidOrderSignature","type":"error"},{"inputs":[],"name":"InvalidOrderTokenBalancer","type":"error"},{"inputs":[],"name":"InvalidSellAmount","type":"error"},{"inputs":[],"name":"InvalidSellToken","type":"error"},{"inputs":[],"name":"InvalidWithdraw","type":"error"},{"inputs":[],"name":"InvalidZeroAddress","type":"error"},{"inputs":[],"name":"InvalidZeroAmount","type":"error"},{"inputs":[],"name":"OrderExpired","type":"error"},{"inputs":[],"name":"OrderFeeNotNull","type":"error"},{"inputs":[],"name":"OrderHashMismatch","type":"error"},{"inputs":[],"name":"OrderPartiallyFillable","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"AAVE_POOL","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FACTORY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SETTLEMENT_CONTRACT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getHookData","outputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"sellToken","type":"address"},{"internalType":"address","name":"buyToken","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"bytes32","name":"kind","type":"bytes32"},{"internalType":"uint256","name":"validTo","type":"uint256"},{"internalType":"uint256","name":"flashLoanAmount","type":"uint256"},{"internalType":"uint256","name":"flashLoanFeeAmount","type":"uint256"},{"internalType":"uint256","name":"hookSellTokenAmount","type":"uint256"},{"internalType":"uint256","name":"hookBuyTokenAmount","type":"uint256"}],"internalType":"struct DataTypes.HookOrderData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_orderHash","type":"bytes32"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct DataTypes.Permit","name":"erc20Permit","type":"tuple"}],"name":"repayDebtWithFlashLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"rescueTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"sellToken","type":"address"},{"internalType":"address","name":"buyToken","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"bytes32","name":"kind","type":"bytes32"},{"internalType":"uint256","name":"validTo","type":"uint256"},{"internalType":"uint256","name":"flashLoanAmount","type":"uint256"},{"internalType":"uint256","name":"flashLoanFeeAmount","type":"uint256"},{"internalType":"uint256","name":"hookSellTokenAmount","type":"uint256"},{"internalType":"uint256","name":"hookBuyTokenAmount","type":"uint256"}],"internalType":"struct DataTypes.HookOrderData","name":"hookData_","type":"tuple"}],"name":"setParameters","outputs":[],"stateMutability":"nonpayable","type":"function"}]

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.