Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/cowprotocol/flash-loan-router/llms.txt

Use this file to discover all available pages before exploring further.

Security Principles

The Flash-Loan Router is designed with security as the primary concern. The architecture ensures that solvers maintain complete control over settlement execution while preventing unauthorized access and malicious interference.

Solver Control

Only registered solvers can execute settlements

Data Integrity

Settlement data cannot be tampered with during execution

Execution Guarantees

One call results in exactly one settlement

Reentrancy Protection

State management prevents concurrent execution

Router Security

Solver Authentication

Only registered CoW Protocol solvers can use the router:
src/FlashLoanRouter.sol
modifier onlySolver() {
    require(
        settlementAuthentication.isSolver(msg.sender),
        "Not a solver"
    );
    _;
}

function flashLoanAndSettle(
    Loan.Data[] calldata loans,
    bytes calldata settlement
) external onlySolver {
    // ...
}
Authentication Source: The router queries the same authentication contract used by the CoW Settlement contract, ensuring consistency across the protocol.

Authentication Properties

Solver registry is managed by CoW Protocol governance
Router cannot authenticate itself as a solver
Authentication is checked before any state changes
Failed authentication reverts immediately

Execution Control

The router guarantees strict execution properties:
src/FlashLoanRouter.sol
function flashLoanAndSettle(
    Loan.Data[] calldata loans,
    bytes calldata settlement
) external onlySolver {
    require(pendingBorrower == READY, "Another settlement in progress");
    emit Settlement(msg.sender);
    bytes memory loansWithSettlement = LoansWithSettlement.encode(loans, settlement);
    borrowNextLoan(loansWithSettlement);
    require(pendingBorrower == SETTLING, "Terminated without settling");
    pendingBorrower = READY;
}

Key Guarantees

Each call to flashLoanAndSettle results in exactly one call to settle():
// State transitions enforce single settlement
READY → Borrower1 → Borrower2 → SETTLING → READY
//                                    ↑
//                            settle() called here
The SETTLING state is only reachable through the settlement path, and the final check verifies it was reached.
Settlement call data cannot be modified after flashLoanAndSettle is called:
src/FlashLoanRouter.sol
// Data is hashed and verified at each callback
pendingDataHash = loansWithSettlement.hash();

// Later, in borrowerCallBack:
require(
    loansWithSettlement.hash() == pendingDataHash,
    "Data from borrower not matching"
);
Any tampering causes immediate revert.
Loans are processed in the exact order specified:
src/FlashLoanRouter.sol
// Only the expected borrower can call back
modifier onlyPendingBorrower() {
    require(
        msg.sender == address(pendingBorrower),
        "Not the pending borrower"
    );
    _;
}
Out-of-order execution is impossible and causes transaction revert.
Only the settle() function can be called:
src/FlashLoanRouter.sol
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");
}
Attempts to call other functions are rejected.

Reentrancy Protection

The router uses state-based reentrancy protection:
src/FlashLoanRouter.sol
// State transitions prevent reentrancy
require(pendingBorrower == READY, "Another settlement in progress");

// During execution, pendingBorrower is never READY:
// READY → Borrower → ... → Borrower → SETTLING → READY
Reentrancy Prevention: The pendingBorrower variable ensures that:
  • No nested calls to flashLoanAndSettle can succeed
  • State is consistent throughout execution
  • Multiple borrowers cannot call back simultaneously

Protection Mechanism

Borrower Security

Access Control

Borrowers enforce strict access control:
modifier onlyRouter() {
    require(msg.sender == address(router), "Not the router");
    _;
}

// Only router can trigger loans
function flashLoanAndCallBack(...) external onlyRouter {
    triggerFlashLoan(...);
}

Fund Protection

Borrowers protect borrowed funds through controlled access:
src/mixin/Borrower.sol
function approve(
    IERC20 token,
    address target,
    uint256 amount
) external onlySettlementContract {
    token.forceApprove(target, amount);
}
Fund Security: The only way to access funds in a borrower is through ERC-20 approvals, which can only be set by the settlement contract during authorized execution.

Security Properties

External callers cannot set approvals
Funds cannot be transferred without settlement approval
Approvals can only be set during active settlement
Unused approvals don’t pose security risks

Unauthorized Access Impact

Borrowers are designed to be resilient against unauthorized access:

No Impact on Adapter Functionality

Unauthorized external calls to borrowers cannot:
  • Impair their ability to act as adapters
  • Modify expected contract behavior
  • Access or steal borrowed funds
  • Disrupt the router’s execution flow

Threat Model

Protected Against

The system provides strong protection against:
Threat: Non-solvers attempting to execute settlementsProtection: onlySolver modifier checks authentication before any operationsResult: Transaction reverts immediately for non-solvers
Threat: Malicious borrowers or lenders modifying settlement dataProtection: Hash verification at each callbackResult: Any data modification causes transaction revert
Threat: Malicious contracts attempting nested settlementsProtection: State-based execution control via pendingBorrowerResult: Reentrancy attempts fail the READY check
Threat: Borrowers calling back in wrong orderProtection: onlyPendingBorrower modifierResult: Only expected borrower can call back at each step
Threat: External callers attempting to access borrowed fundsProtection: onlySettlementContract modifier on approveResult: Only settlement can authorize fund transfers
Threat: Single call attempting multiple settlementsProtection: State transitions and final state verificationResult: Exactly one settlement per call, enforced by state machine

Risk Factors

While user funds remain secure, solvers face risks from malicious participants:
Chain State Manipulation: A malicious token, lender, or borrower can modify chain state before the settle() call, potentially:
  • Triggering transaction revert
  • Exploiting slippage tolerance
  • Causing settlement to execute at unfavorable prices
Impact: Does not affect user fund security, but increases solver execution risk
Risk Mitigation: Assuming trusted tokens, lenders, and borrowers, risks are comparable to normal settlement execution. Solvers should:
  • Only use reputable flash loan providers
  • Verify borrower contract implementations
  • Use appropriate slippage protections
  • Monitor for abnormal provider behavior

Trust Assumptions

The security model makes explicit trust assumptions:

Trusted Components

CoW Protocol

  • Settlement contract
  • Authentication contract
  • Solver registry

Router System

  • FlashLoanRouter contract
  • Borrower adapter contracts
  • Deployment addresses

External Components

The following are external and require solver due diligence:
Flash Loan Providers: Lenders (Aave, Maker, etc.) are external contracts not controlled by the protocol. Solvers should:
  • Verify provider contract addresses
  • Understand fee structures
  • Monitor for upgrades or changes
  • Have contingency plans for provider issues
ERC-20 Tokens: Tokens borrowed and traded are external contracts. Solvers should:
  • Only use well-audited token contracts
  • Understand token-specific behaviors (fees, rebasing, etc.)
  • Be aware of token upgrade mechanisms
  • Monitor for malicious token behavior

Security Best Practices

For solvers using the router:
1

Verify Contract Addresses

Always use official deployment addresses:
  • FlashLoanRouter: 0x9da8B48441583a2b93e2eF8213aAD0EC0b392C69
  • AaveBorrower: 0x7d9C4DeE56933151Bc5C909cfe09DEf0d315CB4A
  • ERC3156Borrower: 0x47d71b4B3336AB2729436186C216955F3C27cD04
2

Use Reputable Providers

Only request flash loans from well-known, audited providers like Aave and Maker
3

Implement Slippage Protection

Include appropriate slippage checks in settlement logic to protect against state manipulation
4

Monitor Execution

Track settlement execution for anomalies or unexpected behavior
5

Maintain Approvals

Set unlimited approvals once for settlement contract to borrowers, reducing per-transaction gas costs
6

Handle Failures Gracefully

Implement fallback logic for flash loan failures or settlement reverts

Audit Status

The Flash-Loan Router contracts have been designed with security as the primary focus:
For the latest audit reports and security updates, refer to the CoW Protocol documentation and GitHub repository.

Next Steps

Router Design

Understand the execution flow

Quick Start

Start building with the router

Build docs developers (and LLMs) love