Skip to content

Conversation

@data-cowwboy
Copy link
Contributor

@data-cowwboy data-cowwboy commented Jan 22, 2026

Adds a new tutorial explaining the complete flow from getting a quote to placing an order, with emphasis on properly applying slippage tolerance.

Changes

  • New tutorial: docs/cow-protocol/tutorials/quote-to-order.mdx
  • Updated API integration docs

Summary

  • Explains quote → slippage → sign → submit flow
  • Provides TypeScript examples using @cowprotocol/contracts
  • Documents the basis points formula for sell/buy order slippage
  • Common integration pattern for partners

Summary by CodeRabbit

  • Documentation
    • Updated API docs: trade history endpoint version bumped.
    • Quick Start examples updated with a new example token and larger sell amount.
    • Clarified signing section: pre-sign slippage handling, adjusted amount calculations, and receiver/fee guidance.
    • Removed inline signature snippet; added explicit order construction and submission payload guidance.
    • Added a new end-to-end tutorial covering quote→order flow, slippage math, signing, submission, and examples.

@data-cowwboy data-cowwboy requested a review from a team as a code owner January 22, 2026 21:59
@vercel
Copy link

vercel bot commented Jan 22, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview Feb 2, 2026 6:44pm

Request Review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 22, 2026

📝 Walkthrough

Walkthrough

Updates docs to introduce a slippage-aware signing flow: quotes must be adjusted (slippage + fees) before EIP-712 signing; quickstart examples and a trades endpoint reference updated; adds a new Quote-to-Order tutorial detailing the full adjustment, signing, and submission flow.

Changes

Cohort / File(s) Summary
API integration & quick start
docs/cow-protocol/integrate/api.mdx
Renamed "Sign and Submit Order" to "Apply Slippage and Sign Order"; updated quick start token address and sellAmountBeforeFee; changed trade history reference from GET /api/v1/trades to GET /api/v2/trades; refactored signing flow to build order from quoteResponse.quote, apply slippage to buyAmount, add feeAmount back to sellAmount, set feeAmount to 0, include receiver, sign the adjusted order, and submit with signature, signingScheme, and from merged into the POST body.
Quote-to-Order tutorial (new)
docs/cow-protocol/tutorials/quote-to-order.mdx
New comprehensive tutorial: obtaining a quote (POST /api/v1/quote), explicit formulas and BigInt examples for applying slippage and partner fees for sell/buy scenarios, step-by-step adjustment sequence (add fee back → apply slippage → apply partner fee), constructing the Order, EIP-712 signing via @cowprotocol/contracts, and submitting to POST /api/v1/orders with example requests/responses and a slippage table.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client (integrator)
  participant QuoteAPI as Quote API
  participant Signer as Local Signer (EIP-712)
  participant OrdersAPI as Orders API

  Client->>QuoteAPI: POST /api/v1/quote (request quote)
  QuoteAPI-->>Client: quoteResponse.quote
  Client->>Client: adjust amounts (add fee, apply slippage, apply partner fee)
  Client->>Signer: sign adjusted Order (EIP-712)
  Signer-->>Client: signature
  Client->>OrdersAPI: POST /api/v1/orders (order + signature + signingScheme + from)
  OrdersAPI-->>Client: submission response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • alfetopito
  • pretf00d

Poem

🐰 I found a quote upon a log one night,
I nudged the numbers gently, snug and tight,
I added fees, trimmed slippage, then I signed,
Hopped the order onward, neatly aligned,
A rabbit's ledger hop — small, swift delight. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding a quote-to-order tutorial with slippage guidance, which is the primary contribution of this pull request.
Description check ✅ Passed The description covers the main changes (new tutorial, API docs updates) and key content areas, but lacks detail on specific adjustments to existing files and implementation rationale.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch docs/quote-to-order-tutorial

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@docs/cow-protocol/tutorials/quote-to-order.mdx`:
- Around line 222-244: The payload is sending signature.data but signOrder
returns a hex string; update the API body to send the signature string itself by
replacing signature: signature.data with signature: signature (reference the
signOrder call and the signature variable used when building the fetch body) so
the POST uses the raw ECDSA signature string expected by the API.
🧹 Nitpick comments (2)
docs/cow-protocol/tutorials/quote-to-order.mdx (1)

206-219: Avoid hard‑coding ERC20 balances in the order object.

If a partner requests non‑ERC20 balances in the quote, hard‑coding OrderBalance.ERC20 will make the signed order diverge from the quote. Either propagate the balances from the quote or explicitly call out that this example assumes ERC20 balances only.

docs/cow-protocol/integrate/api.mdx (1)

51-58: Prefer basis‑points constants over magic numbers for slippage.

Using 995/1000 works, but it’s harder to generalize and less consistent with the tutorial’s BPS explanation. Consider defining SLIPPAGE_BPS and BPS_DENOMINATOR here as well.

♻️ Suggested tweak
-// For sell orders: reduce buyAmount by slippage (e.g., 0.5%)
-const buyAmountWithSlippage = BigInt(quoteResponse.quote.buyAmount) * 995n / 1000n
+// For sell orders: reduce buyAmount by slippage (e.g., 0.5%)
+const SLIPPAGE_BPS = 50n
+const BPS_DENOMINATOR = 10_000n
+const buyAmountWithSlippage =
+  (BigInt(quoteResponse.quote.buyAmount) * (BPS_DENOMINATOR - SLIPPAGE_BPS)) /
+  BPS_DENOMINATOR

Comment on lines 222 to 244
const orderDomain = domain(chainId, settlementContract);
const signature = await signOrder(orderDomain, order, signer, SigningScheme.EIP712);

// 4. Submit the signed order to the API
const response = await fetch('https://api.cow.fi/mainnet/api/v1/orders', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
sellToken: order.sellToken,
buyToken: order.buyToken,
receiver: order.receiver,
sellAmount: order.sellAmount,
buyAmount: order.buyAmount,
validTo: order.validTo,
appData: order.appData,
feeAmount: order.feeAmount,
kind: quoteResponse.quote.kind, // API expects string: "sell" or "buy"
partiallyFillable: order.partiallyFillable,
sellTokenBalance: 'erc20', // API expects string
buyTokenBalance: 'erc20', // API expects string
signature: signature.data,
signingScheme: 'eip712',
from: quoteResponse.from
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

@cowprotocol/contracts signOrder function return type signature shape

💡 Result:

The signOrder function (in @cowprotocol/contracts) returns a Signature type — which is either:

  • an EcdsaSignature: a 65-byte hex string (0x r||s||v), or
  • a PreSignature: an empty-signature bytes string for presign. (docs.cow.fi)

(When used via the SDK OrderSigningUtils, the SDK wraps that into a SigningResult: { signature: string, signingScheme: EcdsaSigningScheme }.) (app.unpkg.com)

Citations:


🌐 Web query:

CoW Protocol API orders endpoint signature submission format

💡 Result:

Summary — how to submit a signed order to CoW Protocol /api/v1/orders

  • Endpoint: POST https://api.cow.fi/{network}/api/v1/orders. Body: JSON containing the signed order object (the quote/order fields plus signature and signingScheme). [1]

  • Required top-level fields (common): sellToken, buyToken, sellAmountBeforeFee / buyAmount, kind (sell|buy), from, receiver (opt), appData, validTo, feeAmount, signingScheme, signature (bytes hex). Use the full quote/order struct returned by the quote endpoint and add the signing result. Example submission from docs: body = JSON.stringify({ ...quoteResponse, signature: "<0x...>", signingScheme: "eip712" }). [1][2]

  • signingScheme values and signature expectations:

    • "eth_sign" — EOA eth_sign of order digest (standard prefixed message ECDSA). signature = ECDSA bytes. [2]
    • "eip712" (or "EIP-712") — typed-data (recommended). signature = ECDSA bytes of EIP‑712 digest. [2]
    • "erc1271" — for smart-contract wallets: signature is contract-specific bytes; set from field to the contract address. [2]
    • "presign" (PreSign) — on-chain presign; signature must be empty bytes "0x" and the order must be pre-signed on-chain via setPreSignature. [2]
  • Minimal JSON example:
    {
    "sellToken":"0x...","buyToken":"0x...","sellAmountBeforeFee":"1000000000000000000",
    "kind":"sell","from":"0xYourAddr","receiver":"0xYourAddr",
    "validTo":1700000000,"appData":"0x...","feeAmount":"0",
    "signingScheme":"eip712",
    "signature":"0x98ac143a... (ECDSA signature)"
    }
    (Submit with Content-Type: application/json). [1][2]

Sources: CoW docs — API integration / order submission and signing-schemes. [1] [2]

References
[1] CoW Protocol — API Integration / Order Book API (POST /api/v1/orders).
[2] CoW Protocol — Signing schemes (eth_sign, EIP‑712, ERC‑1271, PreSign).


🌐 Web query:

signOrder method @cowprotocol/contracts documentation

💡 Result:

The @cowprotocol/contracts package exposes a signOrder helper to EIP‑712 / eth_sign order signing. Usage (TypeScript):

  • Signature: signOrder(domain, order, signer, signingScheme) → Signature (encoded ECDSA signature + signing scheme). [example in SDK wrapper and mapping]. [1][2]

  • Related helpers: hashOrder, domain, packOrderUidParams, signOrderCancellation, etc.; see the CoW Protocol signing docs for the EIP‑712 types and examples. [1][3]

Sources:

  • CoW Protocol signing docs (hashOrder / domain examples). [1]
  • SDK / package references showing signOrder mapping and usage (unpkg / SDK code). [2]
  • @cowprotocol/contracts repository / package (package & repo). [3]

Remove .data access from signature submission.

The signOrder function returns a hex string (ECDSA signature), not an object with a .data property. The signature should be submitted directly: use signature instead of signature.data in the API payload.

Current (incorrect) code
signature: signature.data,

Correct form:

signature: signature,
🤖 Prompt for AI Agents
In `@docs/cow-protocol/tutorials/quote-to-order.mdx` around lines 222 - 244, The
payload is sending signature.data but signOrder returns a hex string; update the
API body to send the signature string itself by replacing signature:
signature.data with signature: signature (reference the signOrder call and the
signature variable used when building the fetch body) so the POST uses the raw
ECDSA signature string expected by the API.

"verified": true
}
```

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add some explanation here about the decomposition of sellAmountBeforeFee in the request as

sellAmount + feeAmount

in the response.

And what this feeAmount means. And we should stress this fee is just an estimation, and is not used for signing, i.e., what the user will end up signing is always a fee=0 order, which means that the fee needs to be added back to the sellAmount

- Quote `sellAmount`: `294554318` (≈294.55 USDC)
- Slippage: 50 bps (0.5%)
- Calculation: `294554318 × (10000 + 50) / 10000 = 296027089`
- Actual `sellAmount`: `296027089`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is wrong. for buy orders, as i mentioned in the comment above, you need to add back the feeAmount returned in the quote response. And there are 2 ways of doing it:

  1. Either you do the slippage tolerance as you did it above and then add back the feeAmount, or
  2. First add back the feeAmount and then apply the slippage tolerance.

I would suggest we go with the (2) to give a bit more room to the limit price

- Calculation: `294554318 × (10000 + 50) / 10000 = 296027089`
- Actual `sellAmount`: `296027089`

This means you're willing to pay at most ~296.03 USDC instead of the quoted ~294.55 USDC.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs fixing


After applying slippage, create the order object with the adjusted amounts and sign it.

### TypeScript Example
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wouldn't really add script/code here

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@docs/cow-protocol/integrate/api.mdx`:
- Around line 49-59: The code has a syntax error in the signature assignment and
incorrectly mutates sellAmount by adding feeAmount; fix by removing the addition
of feeAmount to sellAmount (keep feeAmount as its own field on the order built
from quoteResponse.quote) and ensure buyAmountWithSlippage and sellAmount are
converted to strings when creating the order object (refer to
buyAmountWithSlippage, sellAmount, quoteResponse.quote, order). Then correct the
signature line to use a proper assignment calling signOrder and awaiting the
result (refer to signOrder and signature) so it reads like a normal await
assignment rather than a duplicate operator.
🧹 Nitpick comments (1)
docs/cow-protocol/integrate/api.mdx (1)

24-24: Clarify the v2 trades endpoint in the list.
Since the Network Endpoints section still highlights /api/v1 roots, a brief note here can prevent readers from prepending /api/v1 to the trades path. Please also confirm the v2 endpoint is correct for all networks.

Proposed doc tweak
-- `GET /api/v2/trades` - Get trade history
+- `GET /api/v2/trades` - Get trade history (v2 endpoint; not under `/api/v1`)

Comment on lines 49 to 59
// Apply slippage to the quote before signing
// For sell orders: reduce buyAmount by slippage (e.g., 0.5%)
const buyAmountWithSlippage = BigInt(quoteResponse.quote.buyAmount) * 995n / 1000n
const sellAmount = BigInt(quoteResponse.quote.sellAmount) + BigInt(quoteResponse.quote.feeAmount)

// Build order for signing
const order = {
...quoteResponse,
signature: await signOrder(quoteResponse, signer),
signingScheme: "eip712"
...quoteResponse.quote,
sellAmount: sellAmount.toString(),
buyAmount: buyAmountWithSlippage.toString(),
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cat -n docs/cow-protocol/integrate/api.mdx | sed -n '40,70p'

Repository: cowprotocol/docs

Length of output: 1243


🏁 Script executed:

rg -i "feeAmount|fee.*amount" docs/ -A 2 -B 2 --max-count=20

Repository: cowprotocol/docs

Length of output: 27326


🏁 Script executed:

rg "sellAmount.*feeAmount|feeAmount.*sellAmount" docs/ -B 3 -A 3 --max-count=10

Repository: cowprotocol/docs

Length of output: 644


Fix syntax error on line 61 and correct feeAmount handling.

The code on line 61 has a syntax error (const signature = signature: await signOrder(...)) with a duplicate assignment operator. Additionally, line 52 incorrectly adds feeAmount to sellAmount; feeAmount should remain as a separate field in the order object, as defined in the CoW Protocol order schema. Remove the feeAmount addition and pass it as a distinct field:

Corrected code
const buyAmountWithSlippage = BigInt(quoteResponse.quote.buyAmount) * 995n / 1000n
-const sellAmount = BigInt(quoteResponse.quote.sellAmount) + BigInt(quoteResponse.quote.feeAmount)

// Build order for signing
const order = {
  ...quoteResponse.quote,
-  sellAmount: sellAmount.toString(),
+  sellAmount: quoteResponse.quote.sellAmount,
   buyAmount: buyAmountWithSlippage.toString()
 }

-const signature = signature: await signOrder(quoteResponse, signer)
+const signature = await signOrder(order, signer)

const signedOrder = {
   ...order,
   signature: signature,
   signingScheme: "eip712"
 }
🤖 Prompt for AI Agents
In `@docs/cow-protocol/integrate/api.mdx` around lines 49 - 59, The code has a
syntax error in the signature assignment and incorrectly mutates sellAmount by
adding feeAmount; fix by removing the addition of feeAmount to sellAmount (keep
feeAmount as its own field on the order built from quoteResponse.quote) and
ensure buyAmountWithSlippage and sellAmount are converted to strings when
creating the order object (refer to buyAmountWithSlippage, sellAmount,
quoteResponse.quote, order). Then correct the signature line to use a proper
assignment calling signOrder and awaiting the result (refer to signOrder and
signature) so it reads like a normal await assignment rather than a duplicate
operator.

Copy link
Contributor

@pretf00d pretf00d left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

approved - as long as changes have been made.

- Add fee decomposition explanation (sellAmountBeforeFee = sellAmount + feeAmount)
- Clarify fee=0 signing requirement for all order types
- Fix buy order slippage example (add feeAmount first, then apply slippage)
- Add partner fee section with formulas for sell/buy orders
- Add summary table showing what API handles vs what integrators must apply
- Remove TypeScript code examples per review feedback
- Update api.mdx with consistent fee=0 handling
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants