Address Contract Verified
Address
0x9da8B48441583a2b93e2eF8213aAD0EC0b392C69
Balance
0 ETH
Nonce
1
Code Size
3549 bytes
Creator
Create2 Deployer at tx 0x7f889b49...4c3d97
Indexed Transactions
0
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