-
Notifications
You must be signed in to change notification settings - Fork 24
docs: add quote-to-order tutorial with slippage guidance #587
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the 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. 📝 WalkthroughWalkthroughIntroduces 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
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Tip 🧪 Unit Test Generation v2 is now available!We have significantly improved our unit test generation capabilities. To enable: Add this to your reviews:
finishing_touches:
unit_tests:
enabled: trueTry it out by using the 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. Comment |
There was a problem hiding this 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.ERC20will 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/1000works, but it’s harder to generalize and less consistent with the tutorial’s BPS explanation. Consider definingSLIPPAGE_BPSandBPS_DENOMINATORhere 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
| 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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:
- 1: https://docs.cow.fi/cow-protocol/reference/sdks/cow-sdk/modules?utm_source=openai
- 2: https://app.unpkg.com/%40cowprotocol/cow-sdk%406.3.2/files/dist/utils-5a0554e7.js.map?utm_source=openai
🌐 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/contractsrepository / 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 | ||
| } | ||
| ``` | ||
|
|
There was a problem hiding this comment.
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` |
There was a problem hiding this comment.
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:
- Either you do the slippage tolerance as you did it above and then add back the feeAmount, or
- 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. |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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
There was a problem hiding this 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/v1roots, a brief note here can prevent readers from prepending/api/v1to 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`)
| // 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(), | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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=20Repository: cowprotocol/docs
Length of output: 27326
🏁 Script executed:
rg "sellAmount.*feeAmount|feeAmount.*sellAmount" docs/ -B 3 -A 3 --max-count=10Repository: 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.
Adds a new tutorial explaining the complete flow from getting a quote to placing an order, with emphasis on properly applying slippage tolerance.
Changes
Summary
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.