-
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.
|
📝 WalkthroughWalkthroughUpdated API integration documentation to introduce slippage handling and revised signing workflow. Modified existing quick start example with new token addresses and expanded quote-to-order process details. Added comprehensive tutorial documenting the end-to-end flow for converting quotes to orders with EIP-712 signing and API submission. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 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. 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.
|
|
||
| # From Quote to Order: Applying Slippage | ||
|
|
||
| This tutorial explains how to use the CoW Protocol API to get a quote, apply slippage tolerance, and place an order. This is the most common integration pattern for partners building on CoW Protocol. |
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 tutorial explains how to use the CoW Protocol API to get a quote, apply slippage tolerance, and place an order. This is the most common integration pattern for partners building on CoW Protocol. | |
| This tutorial explains how to use the CoW Protocol API to get a quote, apply slippage tolerance, and place an order. |
| This tutorial explains how to use the CoW Protocol API to get a quote, apply slippage tolerance, and place an order. This is the most common integration pattern for partners building on CoW Protocol. | ||
|
|
||
| :::caution Important | ||
| The quote response provides an **estimated** price. You should **not** sign and submit it directly. You must apply your desired slippage tolerance before signing the order. |
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.
| The quote response provides an **estimated** price. You should **not** sign and submit it directly. You must apply your desired slippage tolerance before signing the order. | |
| The quote response provides an **estimated** price and does not incorporate any slippage tolerance. Because of this, you should **not** sign and submit it directly, unless you want to submit an order with zero slippage tolerance. |
| "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
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.