Skip to main content

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:
ContractAddress
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

  1. Wrap ETH to WETH: Send ETH to the WETH contract (0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14) or use CoW Swap on Sepolia
  2. 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:
TokenSepolia 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

StatusWhat it meansWhat to do
openOrder is in the book, waiting for solversWait — Sepolia may take several minutes
fulfilledOrder settled on-chainSuccess — check executedBuyAmount
expiredOrder timed outSee troubleshooting below
cancelledYou cancelled itExpected 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:
TestWhat to verify
Buy orderChange kind to "buy" and use buyAmountAfterFee instead of sellAmountBeforeFee
CancellationCreate an order with long validFor, then cancel it with DELETE /api/v1/orders/{UID} or sdk.offChainCancelOrder()
Insufficient balanceTry placing an order with more tokens than you hold — should get InsufficientBalance error
Insufficient allowanceRevoke approval, then try placing an order — should get InsufficientAllowance error
Expired quoteWait for the quote to expire, then try submitting — should get a rejection
Status pollingSet up a loop that checks order status every 10 seconds until fulfilled or expired

Step 7: Graduate to Production

  1. Sepolia — verify signing, order creation, and status polling work end-to-end
  2. Barn (mainnet staging) — test with real liquidity using small amounts
  3. 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:
  • Orders create and settle correctly on Sepolia
  • Signing works with your chosen signingScheme
  • Status polling correctly detects fulfilled, expired, and cancelled
  • Error handling catches InsufficientBalance, InsufficientAllowance, InvalidSignature
  • Cancellation flow works
  • (Optional) Tested on barn with small mainnet amounts

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

  1. Use the token addresses listed above so your quote and signing examples match the guide.
  2. If a quote expires before submission, request a fresh quote and retry immediately.
  3. If an order stays open until validTo, retry with adjusted order parameters or continue testing on barn.
  4. Keep test amounts small when moving from Sepolia to barn or mainnet.

Troubleshooting

IssueCauseFix
Order expires unfilledThe order did not settle before validToRe-quote and retry, or adjust the order parameters
NoLiquidity errorThe requested pair could not be quoted on SepoliaTry a different supported pair
SellAmountDoesNotCoverFeeGas costs high relative to small test amountsIncrease the sell amount
InvalidSignature errorEIP-712 domain or struct mismatchVerify chainId: 11155111 for Sepolia, check order fields exactly match
Order shows presignaturePendingPreSign transaction not confirmedWait for Sepolia block confirmation, check tx hash
Different results than mainnetTestnet conditions differ from mainnetExpected — use barn for mainnet testing
InsufficientAllowance on barnForgot to approve on mainnetApprove the Vault Relayer on mainnet (same address)

Resources

Last modified on March 18, 2026