Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x9da8B48441583a2b93e2eF8213aAD0EC0b392C69
Balance 0 ETH
Nonce 1
Code Size 3549 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

3549 bytes
0x608060405234801561000f575f5ffd5b506004361061004a575f3560e01c806302ebcbea1461004e5780630dae46861461009e578063e7c438c9146100b3578063ea42418b146100c6575b5f5ffd5b6100757f0000000000000000000000002c4c28ddbdac9c5e7055b4c863b72ea0149d8afe81565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100b16100ac366004610a60565b6100ed565b005b6100b16100c1366004610b95565b6101ef565b6100757f0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab4181565b3373ffffffffffffffffffffffffffffffffffffffff5f5c1614610172576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4e6f74207468652070656e64696e6720626f72726f776572000000000000000060448201526064015b60405180910390fd5b8051602082012060015c146101e3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f446174612066726f6d20626f72726f776572206e6f74206d61746368696e67006044820152606401610169565b6101ec81610485565b50565b6040517f02cc250d0000000000000000000000000000000000000000000000000000000081523360048201527f0000000000000000000000002c4c28ddbdac9c5e7055b4c863b72ea0149d8afe73ffffffffffffffffffffffffffffffffffffffff16906302cc250d90602401602060405180830381865afa158015610277573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061029b9190610c30565b610301576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4e6f74206120736f6c76657200000000000000000000000000000000000000006044820152606401610169565b5f5c73ffffffffffffffffffffffffffffffffffffffff1615610380576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f416e6f7468657220736574746c656d656e7420696e2070726f677265737300006044820152606401610169565b60405133907f40338ce1a7c49204f0099533b1e9a7ee0a3d261f84974ab7af36105b8c4e9db4905f90a25f6103b7858585856105cc565b90506103c281610485565b5f5c73ffffffffffffffffffffffffffffffffffffffff1673aa50e8d10a8747c958be00c966b6f36fffaf0eb814610456576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f5465726d696e6174656420776974686f757420736574746c696e6700000000006044820152606401610169565b5f7fffffffffffffffffffffffff0000000000000000000000000000000000000000815c16815d505050505050565b60208101515f036104e05773aa50e8d10a8747c958be00c966b6f36fffaf0eb85f805c7fffffffffffffffffffffffff0000000000000000000000000000000000000000168217905d506101ec6104db8261065f565b610703565b5f5f5f5f6104ed856108a9565b9350935093509350825f5f6101000a815c8173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905d50845160208601208060015d506040517f5678d21600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690635678d21690610598908590859089908b90600401610c56565b5f604051808303815f87803b1580156105af575f5ffd5b505af11580156105c1573d5f5f3e3d5ffd5b505050505050505050565b6060605c840282016020016105e0816109a3565b60208101869052915060408201838582378301855b8015610654577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff018161064889898481811061063357610633610cea565b905060800201826109ce90919063ffffffff16565b605c83019250506105f5565b505050949350505050565b606061066c826020015190565b156106d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f50656e64696e67206c6f616e73000000000000000000000000000000000000006044820152606401610169565b5080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001602090910190815290565b7f13d79a0b0000000000000000000000000000000000000000000000000000000061072d82610a1d565b7fffffffff0000000000000000000000000000000000000000000000000000000016146107b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f6e6c7920736574746c65282920697320616c6c6f77656400000000000000006044820152606401610169565b5f7f0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab4173ffffffffffffffffffffffffffffffffffffffff16826040516107fc9190610d17565b5f604051808303815f865af19150503d805f8114610835576040519150601f19603f3d011682016040523d82523d5f602084013e61083a565b606091505b50509050806108a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f536574746c656d656e74207265766572746564000000000000000000000000006044820152606401610169565b5050565b5f5f5f5f5f6108b9866020015190565b90505f8111610924576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f4e6f206c6f616e7320617661696c61626c6500000000000000000000000000006044820152606401610169565b85517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909101907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa4015f6109788860200190565b9782905250908652909401805160148201516028830151603c90930151919790965091945092509050565b6040516060905f836109b6602084610d2d565b6109c09190610d2d565b938252506040929092525090565b80355f6109e16040840160208501610d8c565b90505f6109f46060850160408601610d8c565b90505f610a076080860160608701610d8c565b603c870152506028850152601484015290915250565b5f6004825110610a2e575060208101515b919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f60208284031215610a70575f5ffd5b813567ffffffffffffffff811115610a86575f5ffd5b8201601f81018413610a96575f5ffd5b803567ffffffffffffffff811115610ab057610ab0610a33565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff82111715610b1c57610b1c610a33565b604052818152828201602001861015610b33575f5ffd5b816020840160208301375f91810160200191909152949350505050565b5f5f83601f840112610b60575f5ffd5b50813567ffffffffffffffff811115610b77575f5ffd5b602083019150836020828501011115610b8e575f5ffd5b9250929050565b5f5f5f5f60408587031215610ba8575f5ffd5b843567ffffffffffffffff811115610bbe575f5ffd5b8501601f81018713610bce575f5ffd5b803567ffffffffffffffff811115610be4575f5ffd5b8760208260071b8401011115610bf8575f5ffd5b60209182019550935085013567ffffffffffffffff811115610c18575f5ffd5b610c2487828801610b50565b95989497509550505050565b5f60208284031215610c40575f5ffd5b81518015158114610c4f575f5ffd5b9392505050565b73ffffffffffffffffffffffffffffffffffffffff8516815273ffffffffffffffffffffffffffffffffffffffff84166020820152826040820152608060608201525f8251806080840152806020850160a085015e5f60a0828501015260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505095945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82518060208501845e5f920191825250919050565b80820180821115610d65577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b92915050565b73ffffffffffffffffffffffffffffffffffffffff811681146101ec575f5ffd5b5f60208284031215610d9c575f5ffd5b8135610c4f81610d6b56fea264697066735822122093c52ba9e3ebfca599e3e79eed21ace736056c26f15a4d453276ad8c19ba38e164736f6c634300081c0033

Verified Source Code Full Match

Compiler: v0.8.28+commit.7893614a EVM: cancun Optimization: Yes (1000000 runs)
IERC20.sol 85 lines
// 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);
}
FlashLoanRouter.sol 155 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8;

import {IBorrower} from "./interface/IBorrower.sol";
import {ICowSettlement} from "./interface/ICowSettlement.sol";
import {IFlashLoanRouter} from "./interface/IFlashLoanRouter.sol";
import {Loan} from "./library/Loan.sol";
import {LoansWithSettlement} from "./library/LoansWithSettlement.sol";
import {ICowAuthentication} from "./vendored/ICowAuthentication.sol";
import {IERC20} from "./vendored/IERC20.sol";

/// @title Flash-loan Router
/// @author CoW DAO developers
/// @notice Solver contract for CoW Protocol that requests flash loans before
/// executing a settlement. Every CoW Protocol solver can call this
/// contract to borrow the funds needed for executing a settlement.
contract FlashLoanRouter is IFlashLoanRouter {
    using LoansWithSettlement for bytes;

    /// @notice Event emitted to indicate that a settlement will be executed
    /// on behalf of the indicated solver.
    /// @param solver The address on behalf of which this contract will execute
    /// the settlement.
    event Settlement(address indexed solver);

    /// @notice Flag address signalling that the router is not currently
    /// preparing or executing a settlement. This is the case at the start or
    /// at the end of the call to `flashLoanAndSettle`.
    IBorrower internal constant READY = IBorrower(address(0));
    /// @notice Flag address signalling that the router is currently in the
    /// process of executing a settlement.
    IBorrower internal constant SETTLING = IBorrower(address(bytes20(keccak256("FlashLoanRouter: settling"))));

    /// @inheritdoc IFlashLoanRouter
    ICowSettlement public immutable settlementContract;
    /// @inheritdoc IFlashLoanRouter
    ICowAuthentication public immutable settlementAuthentication;

    /// @notice This variable has the following possible values:
    /// - `READY` (default), before or after a (successful) settlement
    /// - `SETTLING`, if the flash-loan collection phase terminated and the last
    ///   phase of the settlement with flash loan has started.
    /// - The address of the borrower that is expected to call this contract
    ///   back.
    /// This variable it the main actor responsible for controlling the
    /// execution order of flash loan and final settlement.
    IBorrower internal transient pendingBorrower;
    /// @notice The router expects the borrower to send back some data verbatim.
    /// The hash of the data is stored in this variable for validation.
    bytes32 internal transient pendingDataHash;

    /// @notice Only a solver of CoW Protocol can call this function.
    modifier onlySolver() {
        require(settlementAuthentication.isSolver(msg.sender), "Not a solver");
        _;
    }

    /// @notice The router is waiting for a call back from a specific borrower,
    /// no other addresses should be calling this function.
    modifier onlyPendingBorrower() {
        require(msg.sender == address(pendingBorrower), "Not the pending borrower");
        _;
    }

    /// @param _settlementContract The settlement contract that this router will
    /// be supporting.
    constructor(ICowSettlement _settlementContract) {
        settlementContract = _settlementContract;
        settlementAuthentication = ICowAuthentication(_settlementContract.authenticator());
    }

    /// @inheritdoc IFlashLoanRouter
    /// @dev Despite this contract being expected to be a solver, there is no
    /// way for this contract to call itself at `flashLoanAndSettle`.
    function flashLoanAndSettle(Loan.Data[] calldata loans, bytes calldata settlement) external onlySolver {
        require(pendingBorrower == READY, "Another settlement in progress");
        // The event is emitted before the actual settlement is executed to
        // avoid having to carry `msg.sender` up the call stack (and related gas
        // overhead). The contract guarantees that the call reverts if no
        // settlement is executed.
        emit Settlement(msg.sender);
        bytes memory loansWithSettlement = LoansWithSettlement.encode(loans, settlement);
        borrowNextLoan(loansWithSettlement);
        // The following parameter is expected to be set before the final call
        // to `settle()` is executed. This flag being set means that no more
        // calls to `borrowerCallBack` are pending nor possible.
        require(pendingBorrower == SETTLING, "Terminated without settling");
        // We reset the borrower to make it possible to call this function again
        // in the same transaction.
        pendingBorrower = READY;
    }

    /// @inheritdoc IFlashLoanRouter
    /// @dev Note that the contract cannot call itself as a borrower because it
    /// doesn't implement the expected interface.
    function borrowerCallBack(bytes memory loansWithSettlement) external onlyPendingBorrower {
        // When the borrower is called, it's given some extra data that is
        // expected to be passed back here without changes.
        require(loansWithSettlement.hash() == pendingDataHash, "Data from borrower not matching");
        borrowNextLoan(loansWithSettlement);
    }

    /// @notice Takes the input loans with settlements; if none is available, it
    /// calls settle; otherwise, it requests the next loan from the borrower.
    /// @param loansWithSettlement List of loans with settlement to process.
    function borrowNextLoan(bytes memory loansWithSettlement) private {
        if (loansWithSettlement.loanCount() == 0) {
            // We set the borrower to some value different from `READY` or any
            // intermediate borrower address to prevent reentrancy.
            pendingBorrower = SETTLING;
            settle(loansWithSettlement.destroyToSettlement());
        } else {
            (uint256 amount, IBorrower borrower, address lender, IERC20 token) = loansWithSettlement.popLoan();
            pendingBorrower = borrower;
            pendingDataHash = loansWithSettlement.hash();
            borrower.flashLoanAndCallBack(lender, token, amount, loansWithSettlement);
        }
    }

    /// @notice Execute a CoW Protocol settlement.
    /// @param settlement The ABI-encoded call data for a call to `settle()` (as
    /// in `abi.encodeCall`).
    function settle(bytes memory settlement) private {
        require(selector(settlement) == ICowSettlement.settle.selector, "Only settle() is allowed");
        (bool result,) = address(settlementContract).call(settlement);
        require(result, "Settlement reverted");
    }

    /// @notice Extracts the Solidity ABI selector for the specified ABI-encode
    /// call data.
    /// @dev We assume that the input array is a valid bytes array as stored in
    /// memory by Solidity and its content can be read.
    /// @param callData ABI-encoded call data as per `abi.encodeCall`.
    /// @return result The 4 byte function selector of the call encoded in
    /// this interaction (or zero bytes if the data is shorter).
    function selector(bytes memory callData) internal pure returns (bytes4 result) {
        if (callData.length >= 4) {
            // NOTE: Read the first 32 bytes in the array. The value does not
            // need to be shifted since `bytesN` values are left aligned, and
            // the value does not need to be masked since masking occurs when
            // the value is accessed and not stored. The first word of the
            // memory data is the call data length, the content starts in the
            // next word.
            // <https://docs.soliditylang.org/en/v0.8.28/internals/layout_in_memory.html>
            // <https://docs.soliditylang.org/en/v0.8.28/assembly.html#access-to-external-variables-functions-and-libraries>
            // solhint-disable-next-line no-inline-assembly
            // Addition overflow can only happen if the input bytes point to a
            // memory address close to (`type(uint256).max`), which would not be
            // accessible in Solidity without the call running out of gas.
            assembly {
                result := mload(add(callData, 32))
            }
        }
    }
}
IBorrower.sol 50 lines
// 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);
}
ICowSettlement.sol 72 lines
// 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;
}
IFlashLoanRouter.sol 49 lines
// 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);
}
Loan.sol 91 lines
// 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))
        }
    }
}
LoansWithSettlement.sol 202 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8;

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

/// @title Loans-with-settlement Library
/// @author CoW DAO developers
/// @notice A library describing a settlement execution through the flash-loan
/// router and providing related utility functions.
/// @dev This library is used to manage an encoded representation of a list of
/// loans with a settlement as a bytes array. An abstract representation of it
/// as a Solidity struct would be:
///
/// struct Data {
///     Loan.Data[] loans;
///     bytes settlement;
/// }
///
/// The encoding of the bytes array for n loans is as follows:
///
/// Content: |-- number of loans, n --||-- ABI-encoded settlement --||-- n-th Loan  --||-- (n-1)-th Loan --|...|-- 1-st Loan  --|
/// Length:  |<--     32 bytes     -->||<--    arbitrary size    -->||<--size(Loan)-->||<-- size(Loan)  -->|...|<--size(Loan)-->|
///
/// Loans are stored right to left so that it's easy to pop them in order
/// without having to shift all remaining loans in memory.
///
/// This library makes strong low-level assumptions on how memory is used
/// throughout the code for the sake of gas efficiency. You should use this
/// library only if you're willing and able to guarantee that these
/// optimizations don't lead to unexpected behavior.
/// Known risks are:
/// 1. Memory arrays with a location in memory that's close to the end of memory
///    space can cause undefined behavior.
/// 2. Some functions make the original memory input inaccessible.
library LoansWithSettlement {
    using Bytes for bytes;
    using Loan for Loan.EncodedData;

    /// @notice The number of bytes reserved for the encoding of the loan count.
    uint256 private constant LOAN_COUNT_SIZE = 32;

    /// @notice The number of loans in the input.
    /// @param loansWithSettlement The list of loans with settlement.
    /// @return count Number of loans in the input.
    function loanCount(bytes memory loansWithSettlement) internal pure returns (uint256 count) {
        uint256 pointer = loansWithSettlement.unsafeMemoryPointerToContent();
        assembly ("memory-safe") {
            count := mload(pointer)
        }
    }

    /// @notice A collision-resistent identifier for the input list of loans
    /// with settlement.
    /// @param loansWithSettlement The list of loans with settlement to hash.
    /// @return A collision-resistent identifier for the input.
    function hash(bytes memory loansWithSettlement) internal pure returns (bytes32) {
        return keccak256(loansWithSettlement);
    }

    /// @notice Store the list of loans and the settlement in a format
    /// expected by this library.
    /// @param loans List of requested loans.
    /// @param settlement ABI-encoded settlement call data.
    /// @return encodedLoansWithSettlement encoded representation of the input
    /// parameters.
    function encode(Loan.Data[] calldata loans, bytes calldata settlement)
        internal
        pure
        returns (bytes memory encodedLoansWithSettlement)
    {
        uint256 encodedLength;
        unchecked {
            // Unchecked: the input values are bounded by the gas cost of
            // including the data in a transaction.
            encodedLength = LOAN_COUNT_SIZE + settlement.length + loans.length * Loan.ENCODED_LOAN_BYTE_SIZE;
        }
        encodedLoansWithSettlement = Bytes.allocate(encodedLength);

        // Keep track of the first yet-unwritten-to byte
        uint256 head = encodedLoansWithSettlement.unsafeMemoryPointerToContent();
        assembly ("memory-safe") {
            mstore(head, loans.length)
        }

        unchecked {
            // Unchecked: `head` is bounded by `encodedLength`.
            head += LOAN_COUNT_SIZE;
        }
        assembly ("memory-safe") {
            calldatacopy(head, settlement.offset, settlement.length)
        }

        unchecked {
            // Unchecked: `head` is bounded by `encodedLength`.
            head += settlement.length;
        }
        for (uint256 i = loans.length; i > 0;) {
            unchecked {
                // Unchecked: loop condition prevents underflows.
                i--;
            }
            Loan.EncodedData encodedLoan = Loan.EncodedData.wrap(head);
            encodedLoan.store(loans[i]);
            unchecked {
                // Unchecked: `head` is bounded by `encodedLength`.
                head += Loan.ENCODED_LOAN_BYTE_SIZE;
            }
        }
    }

    /// @notice Remove the next loan that is to be processed from the encoded
    /// input data and return its parameter.
    /// @dev The element are popped from the first to the last in the order they
    /// were presented *before encoding*.
    /// @param loansWithSettlement The encoded data from which to remove the
    /// next loan. It must be a valid encoding of loans with settlement of
    /// length at least one.
    /// @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 popLoan(bytes memory loansWithSettlement)
        internal
        pure
        returns (uint256 amount, IBorrower borrower, address lender, IERC20 token)
    {
        uint256 count = loanCount(loansWithSettlement);
        require(count > 0, "No loans available");

        uint256 updatedLoansWithSettlementLength;
        unchecked {
            // Unchecked: there is at least a loan.
            count = count - 1;
            // Unchecked: loansWithSettlement is properly encoded and has a
            // loan, meaning that it has at least length
            // `Loan.ENCODED_LOAN_BYTE_SIZE`
            updatedLoansWithSettlementLength = loansWithSettlement.length - Loan.ENCODED_LOAN_BYTE_SIZE;
        }

        uint256 loansWithSettlementPointer = loansWithSettlement.unsafeMemoryPointerToContent();
        uint256 loanPointer;
        unchecked {
            // Unchecked: the pointer refers to a memory location inside
            // loansWithSettlement, which is assumed to be a valid array.
            loanPointer = loansWithSettlementPointer + updatedLoansWithSettlementLength;
        }
        Loan.EncodedData encodedLoan = Loan.EncodedData.wrap(loanPointer);

        assembly ("memory-safe") {
            // Efficiently reduce the size of the bytes array.
            // The length of a dynamic array is stored at the first slot of the
            // array and followed by the array elements.
            // Memory is never freed, so the remaining unused memory won't
            // affect the compiler.
            // <https://docs.soliditylang.org/en/v0.8.28/internals/layout_in_memory.html>
            mstore(loansWithSettlement, updatedLoansWithSettlementLength)
            // Update first encoded element: the loan count.
            mstore(loansWithSettlementPointer, count)
        }

        return encodedLoan.decode();
    }

    /// @notice Takes an input value with no encoded loans, destroys its content
    /// in memory, and extracts the settlement stored as part of its encoding.
    /// @dev This function overwrites the low-level memory representation of
    /// the input value, meaning that trying to use the input after calling
    /// this function leads to broken code. This functon takes full ownership
    /// of the memory representing the input.
    /// @param loansWithSettlement The encoded data representing loans with a
    /// settlement. It must have valid encoding. This value will be destroyed
    /// by calling this function and must not be used anywhere else.
    /// @return settlement The settlement encoded in the input.
    function destroyToSettlement(bytes memory loansWithSettlement) internal pure returns (bytes memory settlement) {
        require(loanCount(loansWithSettlement) == 0, "Pending loans");
        // We assume that the input is loans with a settlement, encoded as
        // expected by this library. The settlement data is a subarray of the
        // input: if we accept to override the input data with arbitrary data,
        // we can carve out a valid ABI-encoded bytes array representing the
        // settlement.
        uint256 settlementLength;
        unchecked {
            // Unchecked: we assume `loansWithSettlement` to be valid encoded
            // loans with settlement. Since there are no loans, this means that
            // it comprises the loan count plus the settlement data, which is at
            // least zero.
            settlementLength = loansWithSettlement.length - LOAN_COUNT_SIZE;
        }

        // We rely on the fact that LOAN_COUNT_SIZE is 32, exactly the size
        // needed to store the length of a memory array.
        uint256 settlementPointer = loansWithSettlement.unsafeMemoryPointerToContent();

        assembly ("memory-safe") {
            mstore(settlementPointer, settlementLength)
            settlement := settlementPointer
        }
    }
}
ICowAuthentication.sol 17 lines
// 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);
}
Bytes.sol 57 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8;

/// @title Bytes Library
/// @author CoW DAO developers
/// @notice Helper functions to handle bytes array at a raw-memory level.
library Bytes {
    uint256 private constant BYTES_LENGTH_SIZE = 32;

    /// @notice Allocate a bytes array in memory with arbitrary data in it.
    /// This is cheaper than `new bytes(length)` because it doesn't zero the
    /// content of the array. It is supposed to be used when the newly allocated
    /// memory will be fully overwritten at a later step.
    /// @param length The length of the bytes array to create.
    /// @return array A bytes array of the specified length with unknown data in
    /// it.
    function allocate(uint256 length) internal pure returns (bytes memory array) {
        // <https://docs.soliditylang.org/en/v0.8.26/internals/layout_in_memory.html>
        uint256 freeMemoryPointer;
        assembly ("memory-safe") {
            freeMemoryPointer := mload(0x40)
        }

        // Add to the free memory pointer the size of the array and the bytes
        // for storing the array length.
        uint256 updatedFreeMemoryPointer = freeMemoryPointer + BYTES_LENGTH_SIZE + length;
        assembly ("memory-safe") {
            // The array will be located at the first free available memory.
            array := freeMemoryPointer
            // The first 32 bytes are the array length.
            mstore(array, length)
            mstore(0x40, updatedFreeMemoryPointer)
        }
    }

    /// @notice Return the location of the content of an array in memory. Note
    /// that the array length is not part of the content.
    /// @dev This function returns an incorrect pointer if the input array is
    /// located to a memory slot close to the maximum value of 2²⁵⁶.
    /// The content or length of such an array cannot be accessed without
    /// causing an out-of-gas revert. However, such an array can still be
    /// created using assembly. If you're using this function, you must make
    /// sure that the bytes array you're using doesn't trigger this edge case.
    /// @param array A bytes array.
    /// @return ref The location in memory of the content of the array.
    function unsafeMemoryPointerToContent(bytes memory array) internal pure returns (uint256 ref) {
        // Unchecked: arrays allocated by Solidity cannot cause an overflow,
        // since a transaction would run out of gas long before reaching the
        // length needed for an overflow. Arrays that were manually allocated
        // through assembly may cause an overflow, but any attempt to read from
        // or write to them would cause an out-of-gas revert.

        assembly ("memory-safe") {
            ref := add(array, BYTES_LENGTH_SIZE)
        }
    }
}

Read Contract

settlementAuthentication 0x02ebcbea → address
settlementContract 0xea42418b → address

Write Contract 2 functions

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

borrowerCallBack 0x0dae4686
bytes loansWithSettlement
flashLoanAndSettle 0xe17445d5
tuple[] loans
bytes settlement

Recent Transactions

No transactions found for this address