Overview
This guide walks you through testing a CoW Protocol integration end-to-end. You’ll place a real order on the Sepolia testnet, verify it settles, and then move to production.
Step 1: Set Up Your Test Environment
Contract addresses
CoW Protocol is deployed on Sepolia with the same addresses as mainnet:
| Contract | Address |
|---|
| GPv2Settlement | |
| GPv2VaultRelayer | |
API endpoint
Sepolia API base URL:
SDK configuration
import { SupportedChainId, TradingSdk } from '@cowprotocol/sdk-trading'
const sdk = new TradingSdk({
chainId: SupportedChainId.SEPOLIA,
appCode: 'my-app-testing',
}, {}, adapter)
Step 2: Get Test Tokens
You need Sepolia ETH and ERC-20 tokens to test with.
Get Sepolia ETH
Use a faucet:
Get test ERC-20s
- Wrap ETH to WETH: Send ETH to the WETH contract (
0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14) or use CoW Swap on Sepolia
- Swap for test tokens: Use CoW Swap (Sepolia) or Uniswap (Sepolia) to swap WETH for COW or USDC
Example token addresses
These are the Sepolia token addresses used in the examples below:
| Token | Sepolia Address |
|---|
| WETH | |
| COW | |
Step 3: Approve the Vault Relayer
Before placing orders, approve the GPv2VaultRelayer to spend your sell token. This is a one-time step per token.
With Foundry:
cast send 0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14 \
"approve(address,uint256)" \
0xC92E8bdf79f0507f65a392b0ab4667716BFE0110 \
115792089237316195423570985008687907853269984665640564039457584007913129639935 \
--rpc-url https://rpc.sepolia.org \
--private-key $PRIVATE_KEY
With the SDK:
import { maxUint256 } from 'viem'
const txHash = await sdk.approveCowProtocol({
tokenAddress: '0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14',
amount: maxUint256,
})
Verify it worked:
cast call 0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14 \
"allowance(address,address)(uint256)" \
$YOUR_ADDRESS \
0xC92E8bdf79f0507f65a392b0ab4667716BFE0110 \
--rpc-url https://rpc.sepolia.org
The output should be a large number (max uint256 if you used infinite approval).
Step 4: Place a Test Order
Using the API
# 1. Get a quote
curl -X POST "https://api.cow.fi/sepolia/api/v1/quote" \
-H "Content-Type: application/json" \
-d '{
"sellToken": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14",
"buyToken": "0xbe72E441BF55620febc26715db68d3494213D8Cb",
"sellAmountBeforeFee": "100000000000000000",
"kind": "sell",
"from": "YOUR_ADDRESS",
"receiver": "YOUR_ADDRESS",
"validFor": 1800,
"signingScheme": "eip712",
"appData": "{}",
"appDataHash": "0xb48d38f93eaa084033fc5970bf96e559c33c4cdc07d889ab00b4d63f9590739d"
}'
The quote response includes:
quote.appData and quote.appDataHash — sign the hash, submit the JSON appData
id — pass it later as quoteId
expiration — submit before this timestamp
Then complete the happy path with Step 5: Sign the Order and Step 6: Submit the Order.
Using the SDK
import { OrderKind } from '@cowprotocol/sdk-trading'
const { orderId } = await sdk.postSwapOrder({
kind: OrderKind.SELL,
sellToken: '0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14',
sellTokenDecimals: 18,
buyToken: '0xbe72E441BF55620febc26715db68d3494213D8Cb',
buyTokenDecimals: 18,
amount: '100000000000000000', // 0.1 WETH
slippageBps: 500, // 5% — use wide slippage on testnet
validFor: 1800, // 30 minutes
})
console.log('Order UID:', orderId)
Step 5: Verify the Order
Check order status
curl "https://api.cow.fi/sepolia/api/v1/orders/ORDER_UID"
Or with the SDK:
const order = await sdk.getOrder({ orderUid: orderId })
console.log('Status:', order.status)
Check the Explorer
Open https://explorer.cow.fi/sepolia/orders/{ORDER_UID} in your browser. You should see your order with its current status.
Expected behavior
| Status | What it means | What to do |
|---|
open | Order is in the book, waiting for solvers | Wait — Sepolia may take several minutes |
fulfilled | Order settled on-chain | Success — check executedBuyAmount |
expired | Order timed out | See troubleshooting below |
cancelled | You cancelled it | Expected if you called cancel |
Verify the trade
Once status is fulfilled:
curl "https://api.cow.fi/sepolia/api/v2/trades?orderUid=ORDER_UID"
Check that txHash is present and the buyAmount is reasonable.
Step 6: Test Edge Cases
Before going to production, verify these scenarios:
| Test | What to verify |
|---|
| Buy order | Change kind to "buy" and use buyAmountAfterFee instead of sellAmountBeforeFee |
| Cancellation | Create an order with long validFor, then cancel it with DELETE /api/v1/orders/{UID} or sdk.offChainCancelOrder() |
| Insufficient balance | Try placing an order with more tokens than you hold — should get InsufficientBalance error |
| Insufficient allowance | Revoke approval, then try placing an order — should get InsufficientAllowance error |
| Expired quote | Wait for the quote to expire, then try submitting — should get a rejection |
| Status polling | Set up a loop that checks order status every 10 seconds until fulfilled or expired |
Step 7: Graduate to Production
Recommended progression
- Sepolia — verify signing, order creation, and status polling work end-to-end
- Barn (mainnet staging) — test with real liquidity using small amounts
- Production — switch to
api.cow.fi/mainnet with production amounts
Using barn (mainnet staging)
Barn is the staging endpoint for mainnet:
With the SDK:
const parameters: TradeParameters = {
env: 'staging', // Uses barn API
kind: OrderKind.SELL,
// ... rest of parameters
}
Barn targets mainnet. Orders placed there use mainnet assets and can settle on-chain if filled, so test with small amounts.
Production checklist
Before going live:
Switching to production
Change the API base URL to .
Or with the SDK, remove the env: 'staging' parameter (production is the default).
Sepolia Notes
Sepolia is useful for verifying your integration flow, but quote quality and fill behavior can differ from mainnet. If you need mainnet conditions, test on barn with small amounts.
Practical testing tips
- Use the token addresses listed above so your quote and signing examples match the guide.
- If a quote expires before submission, request a fresh quote and retry immediately.
- If an order stays
open until validTo, retry with adjusted order parameters or continue testing on barn.
- Keep test amounts small when moving from Sepolia to barn or mainnet.
Troubleshooting
| Issue | Cause | Fix |
|---|
| Order expires unfilled | The order did not settle before validTo | Re-quote and retry, or adjust the order parameters |
NoLiquidity error | The requested pair could not be quoted on Sepolia | Try a different supported pair |
SellAmountDoesNotCoverFee | Gas costs high relative to small test amounts | Increase the sell amount |
InvalidSignature error | EIP-712 domain or struct mismatch | Verify chainId: 11155111 for Sepolia, check order fields exactly match |
Order shows presignaturePending | PreSign transaction not confirmed | Wait for Sepolia block confirmation, check tx hash |
| Different results than mainnet | Testnet conditions differ from mainnet | Expected — use barn for mainnet testing |
InsufficientAllowance on barn | Forgot to approve on mainnet | Approve the Vault Relayer on mainnet (same address) |
Resources