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 new example token and larger sell amount.
    • Renamed and clarified signing section to show pre-sign slippage handling and adjusted amount calculations.
    • Removed inline signature example; added explicit order construction with slippage-adjusted fields.
    • Added a new end-to-end tutorial covering quote → order flow, slippage math, signing, submission, and error handling.

✏️ Tip: You can customize this high-level summary in your review settings.

@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 Jan 29, 2026 10:51pm

Request Review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 22, 2026

Warning

Rate limit exceeded

@harisang has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 3 minutes and 55 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📝 Walkthrough

Walkthrough

Introduces slippage-aware signing flow and updates the API docs (including a trades endpoint change). Adds a new Quote-to-Order tutorial describing fetching a quote, applying slippage, EIP-712 signing, and submitting signed orders to the API.

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 example token and amounts; changed trade history endpoint reference from GET /api/v1/trades to GET /api/v2/trades; introduced pre-sign slippage adjustments and moved order construction to use quoteResponse.quote with explicit buyAmount/sellAmount fields; removed inline signature/signingScheme from snippet and added links to signing guide and tutorial.
Quote-to-Order tutorial (new)
docs/cow-protocol/tutorials/quote-to-order.mdx
Added a comprehensive end-to-end tutorial: fetching a quote (POST /api/v1/quote), applying slippage for sell/buy scenarios with explicit formulas and BigInt integer math examples, constructing an Order, EIP-712 signing via @cowprotocol/contracts, and submitting to POST /api/v1/orders; includes full TypeScript flow, error handling examples, and a slippage impact table.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client (app)
  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 (quote)
  Client->>Client: apply slippage (adjust buyAmount/sellAmount)
  Client->>Signer: sign Order (EIP-712)
  Signer-->>Client: signature
  Client->>OrdersAPI: POST /api/v1/orders (order + signature)
  OrdersAPI-->>Client: order submission response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • alfetopito
  • pretf00d

Poem

🐰 I found a quote beneath a log so small,
I nudged its numbers, guarding against a fall,
With EIP-712 I stitched a hop and sign,
Then sent it on the network, neat and fine,
From quote to order — a tiny rabbit's call. 🥕✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding a new quote-to-order tutorial with slippage guidance, which aligns perfectly with the PR objectives and file changes.
Description check ✅ Passed The description covers key sections including purpose, changes list, and summary, though it lacks the detailed checklist format shown in the template and omits the Related Issues section.
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

Tip

🧪 Unit Test Generation v2 is now available!

We have significantly improved our unit test generation capabilities.

To enable: Add this to your .coderabbit.yaml configuration:

reviews:
  finishing_touches:
    unit_tests:
      enabled: true

Try it out by using the @coderabbitai generate unit tests command on your code files or under ✨ Finishing Touches on the walkthrough!

Have feedback? Share your thoughts on our Discord thread!


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.

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.

3 participants