This quickstart guide will walk you through creating a complete swap from setup to execution using the CoW Protocol SDK.
Prerequisites
Before you begin, make sure you have:
Node.js 16 or higher installed
A wallet with a private key for signing transactions
An RPC endpoint URL (e.g., from Alchemy, Infura, or Tenderly)
Test tokens on Sepolia testnet
Testnet First : This guide uses Sepolia testnet. Always test on testnets before using mainnet.
Step 1: Install Dependencies
Install the CoW Protocol SDK and a Web3 adapter:
npm install @cowprotocol/cow-sdk @cowprotocol/sdk-viem-adapter viem dotenv
Step 2: Set Up Environment Variables
Create a .env file in your project root:
PRIVATE_KEY = 0x...
RPC_URL = https://sepolia.gateway.tenderly.co
Security : Never commit your .env file to version control. Add it to .gitignore.
Create a file swap.ts and set up your Web3 adapter:
import 'dotenv/config'
import { createPublicClient , http , privateKeyToAccount } from 'viem'
import { sepolia } from 'viem/chains'
import { ViemAdapter } from '@cowprotocol/sdk-viem-adapter'
import {
SupportedChainId ,
TradingSdk ,
OrderKind ,
setGlobalAdapter
} from '@cowprotocol/cow-sdk'
// Create a public client (provider)
const publicClient = createPublicClient ({
chain: sepolia ,
transport: http ( process . env . RPC_URL )
})
// Create account from private key
const account = privateKeyToAccount ( process . env . PRIVATE_KEY as `0x ${ string } ` )
// Create the adapter
const adapter = new ViemAdapter ({
provider: publicClient ,
signer: account
})
// Set global adapter (optional but recommended)
setGlobalAdapter ( adapter )
import 'dotenv/config'
import { JsonRpcProvider , Wallet } from 'ethers'
import { EthersV6Adapter } from '@cowprotocol/sdk-ethers-v6-adapter'
import {
SupportedChainId ,
TradingSdk ,
OrderKind ,
setGlobalAdapter
} from '@cowprotocol/cow-sdk'
// Create provider
const provider = new JsonRpcProvider ( process . env . RPC_URL )
// Create wallet
const wallet = new Wallet ( process . env . PRIVATE_KEY , provider )
// Create the adapter
const adapter = new EthersV6Adapter ({
provider ,
signer: wallet
})
// Set global adapter (optional but recommended)
setGlobalAdapter ( adapter )
import 'dotenv/config'
import { ethers } from 'ethers'
import { EthersV5Adapter } from '@cowprotocol/sdk-ethers-v5-adapter'
import {
SupportedChainId ,
TradingSdk ,
OrderKind ,
setGlobalAdapter
} from '@cowprotocol/cow-sdk'
// Create provider
const provider = new ethers . providers . JsonRpcProvider ( process . env . RPC_URL )
// Create wallet
const wallet = new ethers . Wallet ( process . env . PRIVATE_KEY , provider )
// Create the adapter
const adapter = new EthersV5Adapter ({
provider ,
signer: wallet
})
// Set global adapter (optional but recommended)
setGlobalAdapter ( adapter )
Step 4: Initialize the TradingSdk
Add the SDK initialization to your swap.ts file:
// Initialize the Trading SDK
const sdk = new TradingSdk (
{
chainId: SupportedChainId . SEPOLIA ,
appCode: 'MyFirstCoWSwap' , // Your app identifier
},
{}, // Options (can be empty)
adapter // The adapter we created
)
Step 5: Define Token Addresses
Define the tokens you want to swap. For Sepolia testnet:
// Token addresses on Sepolia
const WETH_SEPOLIA = '0xfff9976782d46cc05630d1f6ebab18b2324d6b14'
const USDC_SEPOLIA = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'
// Decimals
const WETH_DECIMALS = 18
const USDC_DECIMALS = 6
These are real Sepolia testnet token addresses. Get test WETH from the Sepolia faucet .
Step 6: Create Your First Swap
Now let’s create a complete swap function:
async function executeSwap () {
try {
console . log ( '🔍 Getting quote...' )
// Step 1: Get a quote
const { quoteResults , postSwapOrderFromQuote } = await sdk . getQuote ({
kind: OrderKind . SELL , // We're selling a specific amount
sellToken: WETH_SEPOLIA ,
sellTokenDecimals: WETH_DECIMALS ,
buyToken: USDC_SEPOLIA ,
buyTokenDecimals: USDC_DECIMALS ,
amount: '100000000000000' , // 0.0001 WETH in wei
slippageBps: 50 // 0.5% slippage tolerance
})
// Step 2: Check the quote
const buyAmount = quoteResults . amountsAndCosts . afterSlippage . buyAmount
const sellAmount = quoteResults . amountsAndCosts . afterSlippage . sellAmount
console . log ( '📊 Quote received:' )
console . log ( ` Selling: ${ sellAmount } WETH` )
console . log ( ` Buying (minimum): ${ buyAmount } USDC` )
console . log ( ` Valid for: ${ quoteResults . quoteResponse . quote . validTo } seconds` )
// Step 3: Sign and post the order
console . log ( '✍️ Signing and posting order...' )
const orderId = await postSwapOrderFromQuote ()
console . log ( '✅ Order created successfully!' )
console . log ( ` Order ID: ${ orderId } ` )
console . log ( ` View on Explorer: https://explorer.cow.fi/sepolia/orders/ ${ orderId } ` )
return orderId
} catch ( error ) {
console . error ( '❌ Error executing swap:' , error )
throw error
}
}
// Execute the swap
executeSwap ()
. then (() => {
console . log ( ' \n 🎉 Swap completed!' )
process . exit ( 0 )
})
. catch (( error ) => {
console . error ( ' \n 💥 Swap failed:' , error )
process . exit ( 1 )
})
Step 7: Run Your Swap
Execute your script:
You should see output similar to:
🔍 Getting quote...
📊 Quote received:
Selling: 100000000000000 WETH
Buying (minimum): 250000 USDC
Valid for: 300 seconds
✍️ Signing and posting order...
✅ Order created successfully!
Order ID: 0x7d4389693b6cf89ad6c140a113b10df08073e5ef3063d05a02f3f42e1a42f0ad...
View on Explorer: https://explorer.cow.fi/sepolia/orders/0x7d4389693b6cf89...
🎉 Swap completed!
Complete Example
Here’s the complete swap.ts file:
import 'dotenv/config'
import { createPublicClient , http , privateKeyToAccount } from 'viem'
import { sepolia } from 'viem/chains'
import { ViemAdapter } from '@cowprotocol/sdk-viem-adapter'
import {
SupportedChainId ,
TradingSdk ,
OrderKind ,
setGlobalAdapter
} from '@cowprotocol/cow-sdk'
// Setup adapter
const publicClient = createPublicClient ({
chain: sepolia ,
transport: http ( process . env . RPC_URL )
})
const account = privateKeyToAccount ( process . env . PRIVATE_KEY as `0x ${ string } ` )
const adapter = new ViemAdapter ({ provider: publicClient , signer: account })
setGlobalAdapter ( adapter )
// Initialize SDK
const sdk = new TradingSdk (
{
chainId: SupportedChainId . SEPOLIA ,
appCode: 'MyFirstCoWSwap' ,
},
{},
adapter
)
// Token configuration
const WETH_SEPOLIA = '0xfff9976782d46cc05630d1f6ebab18b2324d6b14'
const USDC_SEPOLIA = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'
async function executeSwap () {
console . log ( '🔍 Getting quote...' )
const { quoteResults , postSwapOrderFromQuote } = await sdk . getQuote ({
kind: OrderKind . SELL ,
sellToken: WETH_SEPOLIA ,
sellTokenDecimals: 18 ,
buyToken: USDC_SEPOLIA ,
buyTokenDecimals: 6 ,
amount: '100000000000000' , // 0.0001 WETH
slippageBps: 50
})
const buyAmount = quoteResults . amountsAndCosts . afterSlippage . buyAmount
console . log ( `📊 You will receive at least: ${ buyAmount } USDC` )
console . log ( '✍️ Signing and posting order...' )
const orderId = await postSwapOrderFromQuote ()
console . log ( '✅ Order created:' , orderId )
console . log ( ` https://explorer.cow.fi/sepolia/orders/ ${ orderId } ` )
return orderId
}
executeSwap ()
. then (() => process . exit ( 0 ))
. catch (( error ) => {
console . error ( error )
process . exit ( 1 )
})
Understanding the Code
Let’s break down the key components:
Order Types
OrderKind . SELL // Sell exact amount, buy at least minimum
OrderKind . BUY // Buy exact amount, sell at most maximum
Use SELL when you want to sell a specific amount of tokens. Use BUY when you want to receive a specific amount of tokens.
Slippage Tolerance
slippageBps : 50 // 0.5% = 50 basis points
slippageBps : 100 // 1% = 100 basis points
slippageBps : 200 // 2% = 200 basis points
Slippage protects you from price movements between quote and execution.
Quote Results
The quote returns detailed information:
quoteResults . amountsAndCosts . afterSlippage . buyAmount // Minimum buy amount
quoteResults . amountsAndCosts . afterSlippage . sellAmount // Maximum sell amount
quoteResults . quoteResponse . quote . validTo // Quote expiration
quoteResults . quoteResponse . quote . feeAmount // Network fee
Token Approval
Before your first swap, you need to approve the CoW Protocol to spend your tokens:
// Check current allowance
const allowance = await sdk . getCowProtocolAllowance ({
tokenAddress: WETH_SEPOLIA ,
owner: account . address
})
console . log ( 'Current allowance:' , allowance )
// Approve if needed
if ( allowance < BigInt ( '100000000000000' )) {
console . log ( 'Approving token...' )
const txHash = await sdk . approveCowProtocol ({
tokenAddress: WETH_SEPOLIA ,
amount: BigInt ( '1000000000000000000' ) // 1 WETH
})
console . log ( 'Approval tx:' , txHash )
}
See the Token Approvals Guide for more details.
Advanced Options
Custom Receiver
Send tokens to a different address:
const { quoteResults , postSwapOrderFromQuote } = await sdk . getQuote ({
kind: OrderKind . SELL ,
sellToken: WETH_SEPOLIA ,
sellTokenDecimals: 18 ,
buyToken: USDC_SEPOLIA ,
buyTokenDecimals: 6 ,
amount: '100000000000000' ,
receiver: '0x...' // Different recipient address
})
Order Validity Period
Control how long the order is valid:
const { quoteResults , postSwapOrderFromQuote } = await sdk . getQuote ({
kind: OrderKind . SELL ,
sellToken: WETH_SEPOLIA ,
sellTokenDecimals: 18 ,
buyToken: USDC_SEPOLIA ,
buyTokenDecimals: 6 ,
amount: '100000000000000' ,
validFor: 600 // Valid for 10 minutes (600 seconds)
})
Partially Fillable Orders
Allow partial order fills:
const { quoteResults , postSwapOrderFromQuote } = await sdk . getQuote ({
kind: OrderKind . SELL ,
sellToken: WETH_SEPOLIA ,
sellTokenDecimals: 18 ,
buyToken: USDC_SEPOLIA ,
buyTokenDecimals: 6 ,
amount: '1000000000000000000' , // 1 WETH
partiallyFillable: true // Allow partial fills
})
Monitoring Your Order
After posting an order, you can track its status:
// Get order details
const order = await sdk . getOrder ({ orderUid: orderId })
console . log ( 'Order status:' , order . status )
console . log ( 'Executed amount:' , order . executedSellAmount )
Order statuses:
open - Order is waiting to be filled
fulfilled - Order is completely filled
expired - Order expired before being filled
cancelled - Order was cancelled
Next Steps
Creating Swap Orders Learn advanced swap order configuration
Creating Limit Orders Create limit orders with specific prices
Token Approvals Manage token approvals efficiently
Order Management Query, monitor, and cancel orders
Troubleshooting
Insufficient balance error
Make sure you have enough tokens in your wallet. Get test WETH from the Sepolia faucet .
Insufficient allowance error
You need to approve the CoW Protocol to spend your tokens first. See the Token Approval section above.
Quotes are only valid for a limited time (default 5 minutes). Get a new quote if yours expired.
Verify your RPC URL is correct in the .env file. Try using a different RPC provider like:
https://sepolia.gateway.tenderly.co
https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY
https://sepolia.infura.io/v3/YOUR_KEY
Invalid private key error
Ensure your private key in .env starts with 0x and is a valid 64-character hex string.
Additional Resources