Skip to main content
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:
.env
PRIVATE_KEY=0x...
RPC_URL=https://sepolia.gateway.tenderly.co
Security: Never commit your .env file to version control. Add it to .gitignore.

Step 3: Configure the Adapter

Create a file swap.ts and set up your Web3 adapter:
swap.ts
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)

Step 4: Initialize the TradingSdk

Add the SDK initialization to your swap.ts file:
swap.ts
// 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
)
The appCode parameter is used to track your integration on CoW Protocol’s Dune dashboards. Choose a unique identifier for your application.

Step 5: Define Token Addresses

Define the tokens you want to swap. For Sepolia testnet:
swap.ts
// 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:
swap.ts
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:
ts-node swap.ts
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

Make sure you have enough tokens in your wallet. Get test WETH from the Sepolia faucet.
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
Ensure your private key in .env starts with 0x and is a valid 64-character hex string.

Additional Resources

Build docs developers (and LLMs) love