> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cow.bleu.builders/llms.txt
> Use this file to discover all available pages before exploring further.

# Flash Loans

> Understanding flash loans and how they enable atomic settlements in CoW Protocol

export const InlineResource = ({value, copyValue, href, chain, explorerHref, explorerType = "address", explorerSuffix = "", showCopy = true, showExplorer = false, openInNewTab}) => {
  const explorerBases = {
    arbitrum: "https://arbiscan.io",
    arbitrum_one: "https://arbiscan.io",
    avalanche: "https://snowscan.xyz",
    base: "https://basescan.org",
    bnb: "https://bscscan.com",
    ethereum: "https://etherscan.io",
    gnosis: "https://gnosisscan.io",
    ink: "https://explorer.inkonchain.com",
    linea: "https://lineascan.build",
    mainnet: "https://etherscan.io",
    optimism: "https://optimistic.etherscan.io",
    plasma: "https://plasmascan.to",
    polygon: "https://polygonscan.com",
    sepolia: "https://sepolia.etherscan.io",
    xdai: "https://gnosisscan.io"
  };
  const isExternalUrl = (candidate = "") => (/^https?:\/\//i).test(candidate);
  const isHexAddress = (candidate = "") => (/^0x[a-fA-F0-9]{40}$/).test(candidate);
  const normalizeUrl = (candidate = "") => {
    if (!candidate) {
      return "";
    }
    if (candidate.startsWith("/") || candidate.startsWith("#") || isExternalUrl(candidate)) {
      return candidate;
    }
    return `https://${candidate}`;
  };
  const compactUrl = (candidate = "") => {
    const withoutProtocol = candidate.replace(/^https?:\/\//i, "");
    if (withoutProtocol.length <= 40) {
      return withoutProtocol;
    }
    const [host, ...segments] = withoutProtocol.split("/");
    if (!segments.length) {
      return `${withoutProtocol.slice(0, 20)}...${withoutProtocol.slice(-12)}`;
    }
    const tail = segments.length >= 2 ? `${segments[segments.length - 2]}/${segments[segments.length - 1]}` : segments[segments.length - 1];
    return `${host}/.../${tail}`;
  };
  const resolvedExplorerHref = (() => {
    if (explorerHref) {
      return explorerHref;
    }
    if (!chain || !value) {
      return "";
    }
    const base = explorerBases[chain];
    if (!base) {
      return "";
    }
    return `${base}/${explorerType}/${value}${explorerSuffix}`;
  })();
  const resolvedHref = normalizeUrl(href || "");
  const primaryHref = resolvedHref || (showExplorer ? resolvedExplorerHref : "");
  const primaryTarget = openInNewTab ?? (primaryHref ? isExternalUrl(primaryHref) : false);
  const shouldCompactValue = isExternalUrl(value || "") || isExternalUrl(primaryHref);
  const displayValue = shouldCompactValue ? compactUrl(value) : value;
  const contentClassName = ["inline-resource__value", shouldCompactValue ? "inline-resource__value--compact" : "", isHexAddress(value || "") ? "inline-resource__value--address" : ""].filter(Boolean).join(" ");
  const setButtonState = (button, state, label) => {
    if (!button) {
      return;
    }
    button.dataset.state = state;
    button.setAttribute("aria-label", label);
    button.title = label;
    if (button.__copyTimer) {
      window.clearTimeout(button.__copyTimer);
      button.__copyTimer = null;
    }
    if (state === "idle") {
      return;
    }
    button.__copyTimer = window.setTimeout(() => {
      button.dataset.state = "idle";
      button.setAttribute("aria-label", "Copy value");
      button.title = "Copy value";
    }, 1200);
  };
  const fallbackCopy = text => {
    if (typeof document === "undefined") {
      return false;
    }
    const input = document.createElement("textarea");
    input.value = text;
    input.setAttribute("readonly", "");
    input.style.left = "-9999px";
    input.style.position = "absolute";
    document.body.appendChild(input);
    input.select();
    let copied = false;
    try {
      copied = document.execCommand("copy");
    } catch {
      copied = false;
    }
    document.body.removeChild(input);
    return copied;
  };
  const copyText = async (text, button) => {
    if (!text) {
      setButtonState(button, "copied", "Nothing to copy");
      return;
    }
    try {
      if (typeof navigator !== "undefined" && navigator.clipboard?.writeText) {
        await navigator.clipboard.writeText(text);
        setButtonState(button, "copied", "Copied");
        return;
      }
    } catch {}
    const copied = fallbackCopy(text);
    setButtonState(button, copied ? "copied" : "idle", copied ? "Copied" : "Copy failed");
  };
  const content = <code className={contentClassName} title={value}>
      {displayValue}
    </code>;
  return <span className="inline-resource">
      {primaryHref ? <a className="inline-resource__link" href={primaryHref} rel={primaryTarget ? "noreferrer noopener" : undefined} target={primaryTarget ? "_blank" : undefined} title={value}>
          {content}
        </a> : content}

      {showCopy || showExplorer && resolvedExplorerHref && resolvedExplorerHref !== primaryHref ? <span className="inline-resource__actions">
          {showCopy ? <button aria-label="Copy value" className="inline-resource__action" data-state="idle" onClick={event => copyText(copyValue || value, event.currentTarget)} title="Copy value" type="button">
              <span className="inline-resource__icon inline-resource__icon--copy">
                <CopyIcon />
              </span>
              <span className="inline-resource__icon inline-resource__icon--check">
                <CheckIcon />
              </span>
            </button> : null}

          {showExplorer && resolvedExplorerHref && resolvedExplorerHref !== primaryHref ? <a aria-label="Open in explorer" className="inline-resource__action" href={resolvedExplorerHref} rel="noreferrer noopener" target="_blank" title="Open in explorer">
              <span className="inline-resource__icon">
                <ExternalLinkIcon />
              </span>
            </a> : null}
        </span> : null}
    </span>;
};

## What are Flash Loans?

Flash loans are uncollateralized loans that must be borrowed and repaid within a single transaction. They enable solvers to access large amounts of capital without upfront collateral, provided the loan is fully repaid by the end of the transaction execution.

The Flash-Loan Router allows CoW Protocol solvers to execute settlements with the ability to use funds from one or more flash loans, enabling more capital-efficient trading strategies.

## Supported Providers

The router currently supports two types of flash loan providers:

<CardGroup cols={2}>
  <Card title="ERC-3156" icon="file-contract">
    Any lender compatible with the [ERC-3156](https://eips.ethereum.org/EIPS/eip-3156) standard interface, including Maker's Flash Mint Module.
  </Card>

  <Card title="Aave" icon="coins">
    [Aave Protocol](https://aave.com/docs/developers/flash-loans#overview) flash loans with native integration.
  </Card>
</CardGroup>

### Provider Addresses

All contracts are deployed deterministically with CREATE2 and share the same addresses across supported networks:

* `FlashLoanRouter`: <InlineResource value="0x9da8B48441583a2b93e2eF8213aAD0EC0b392C69" chain="ethereum" showExplorer />
* `AaveBorrower`: <InlineResource value="0x7d9C4DeE56933151Bc5C909cfe09DEf0d315CB4A" chain="ethereum" showExplorer />
* `ERC3156Borrower`: <InlineResource value="0x47d71b4B3336AB2729436186C216955F3C27cD04" chain="ethereum" showExplorer />

See the [networks.json](https://github.com/cowprotocol/flash-loan-router/blob/main/networks.json) file for deployment details.

## How Flash Loans Work

The flash loan lifecycle follows this sequence:

1. **Request**: Solver calls `flashLoanAndSettle()` with loan specifications
2. **Borrow**: Router requests loans from specified providers via borrower adapters
3. **Execute**: Settlement executes with access to borrowed funds
4. **Repay**: Settlement returns borrowed funds plus fees to lenders
5. **Verify**: Transaction reverts if any loan cannot be repaid

<Accordion title="Example: Settlement with Two Loans (Aave + Maker)">
  ```mermaid theme={null}
  sequenceDiagram
    CoW-Protocol solver ->> flash-loan router: flashLoanAndSettle()
    flash-loan router ->> Aave borrower: flashLoanAndCallBack()
    Aave borrower ->> Aave lender contract: Aave-specific flash loan request
    Aave lender contract ->> Aave borrower: Aave-specific flash loan callback
    Aave borrower ->> flash-loan router: borrowerCallBack()
    flash-loan router ->> Maker borrower: flashLoanAndCallBack()
    Maker borrower ->> Maker lender contract: Maker-specific flash loan request
    Maker lender contract ->> Maker borrower: Maker-specific flash loan callback
    Maker borrower ->> flash-loan router: borrowerCallBack()
    flash-loan router ->> CoW Settlement: settle()
  ```

  Each flash loan is processed sequentially, with the settlement executing only after all loans are obtained.
</Accordion>

## Loan Specification

Each flash loan request requires the following parameters:

<ParamField path="amount" type="uint256" required>
  The amount of tokens to borrow
</ParamField>

<ParamField path="token" type="address" required>
  The ERC-20 token contract address to borrow
</ParamField>

<ParamField path="lender" type="address" required>
  The flash loan provider contract (e.g., Balancer, Aave, Maker)
</ParamField>

<ParamField path="borrower" type="address" required>
  The adapter contract that makes the specific lender implementation compatible with the router
</ParamField>

## Fund Management

### Accessing Loaned Funds

The only way to move funds out of a borrower is through ERC-20 approvals:

```solidity theme={null}
// Called during settlement to approve fund transfers
borrower.approve(token, spender, amount);
```

<Info>
  **Best Practice**: Set unlimited approvals once for the settlement contract and reuse them across multiple settlements to save gas.
</Info>

### Repayment Process

Repayment mechanisms vary by provider:

1. **Transfer**: Settlement transfers borrowed funds back to the borrower
2. **Approve**: Settlement sets an approval for the lender to spend borrower's funds
3. **Pull**: Lender pulls funds back using `transferFrom` after settlement completes

<Warning>
  Inability to repay a flash loan will cause the entire transaction to revert. Ensure your settlement logic accounts for:

  * Loan principal amounts
  * Provider-specific fees
  * Sufficient token balances in borrower contracts
</Warning>

## Adding New Providers

Support for additional flash loan providers can be added by implementing a new borrower adapter. See [Borrower Adapters](/flash-loan-router/concepts/borrower-adapters) for implementation details.

## Next Steps

<CardGroup cols={2}>
  <Card title="Router Design" icon="route" href="/flash-loan-router/concepts/router-design">
    Learn about the router's execution flow
  </Card>

  <Card title="Borrower Adapters" icon="plug" href="/flash-loan-router/concepts/borrower-adapters">
    Understand the adapter architecture
  </Card>
</CardGroup>
