Skip to main content

Node.js Usage

This guide shows you how to use the CoW Protocol SDK in Node.js environments, including backend services, scripts, and automation tools.

Installation

Choose your preferred Ethereum library:
npm install @cowprotocol/cow-sdk @cowprotocol/sdk-ethers-v6-adapter ethers dotenv

Environment Setup

Create a .env file to store your configuration:
.env
RPC_URL=https://sepolia.gateway.tenderly.co
PRIVATE_KEY=0x...
CHAIN_ID=11155111

Basic Script

import 'dotenv/config'
import { JsonRpcProvider, Wallet } from 'ethers'
import {
  setGlobalAdapter,
  SupportedChainId,
  TradingSdk,
  OrderKind,
  WRAPPED_NATIVE_CURRENCIES,
} from '@cowprotocol/cow-sdk'
import { EthersV6Adapter } from '@cowprotocol/sdk-ethers-v6-adapter'

const RPC_URL = process.env.RPC_URL || 'https://sepolia.gateway.tenderly.co'
const PRIVATE_KEY = process.env.PRIVATE_KEY
const DEFAULT_SELL_AMOUNT = '0.1'

async function main() {
  if (!PRIVATE_KEY) {
    throw new Error('PRIVATE_KEY environment variable is required')
  }

  const chainId = SupportedChainId.SEPOLIA

  // Setup provider and wallet
  const provider = new JsonRpcProvider(RPC_URL, chainId)
  const wallet = new Wallet(PRIVATE_KEY, provider)

  // Setup CoW Protocol adapter
  const adapter = new EthersV6Adapter({ provider, signer: wallet })
  setGlobalAdapter(adapter)

  // Initialize SDK
  const sdk = new TradingSdk({
    chainId,
    appCode: 'NodeScript',
    signer: wallet,
  })

  // Define tokens
  const WETH = WRAPPED_NATIVE_CURRENCIES[chainId]
  const USDC = {
    address: '0xbe72E441BF55620febc26715db68d3494213D8Cb',
    decimals: 18,
  }

  const owner = (await wallet.getAddress()) as `0x${string}`
  const amount = Math.round(
    Number(DEFAULT_SELL_AMOUNT) * 10 ** WETH.decimals
  ).toString()
  const slippageBps = 50

  console.log('Owner:', owner)
  console.log('Getting quote...')

  // Get quote
  const quoteAndPost = await sdk.getQuote({
    chainId,
    kind: OrderKind.SELL,
    owner,
    amount,
    sellToken: WETH.address,
    sellTokenDecimals: WETH.decimals,
    buyToken: USDC.address,
    buyTokenDecimals: USDC.decimals,
    slippageBps,
  })

  console.log('Quote received')
  console.log('Buy amount:', quoteAndPost.quoteResults.amountsAndCosts.afterNetworkCosts.buyAmount)

  // Post order
  console.log('Posting order...')
  const result = await quoteAndPost.postSwapOrderFromQuote({})
  console.log('Order posted successfully!')
  console.log('Order ID:', result.orderId)
  console.log('Explorer:', `https://explorer.cow.fi/sepolia/orders/${result.orderId}`)
}

main().catch((error) => {
  console.error('Error:', error)
  process.exit(1)
})

Run the Script

ts-node index.ts
# or with tsx
npx tsx index.ts

Advanced Patterns

Automated Trading Bot

Create a simple trading bot that monitors prices:
bot.ts
import { TradingSdk, OrderKind } from '@cowprotocol/cow-sdk'

class TradingBot {
  constructor(private sdk: TradingSdk) {}

  async monitorAndTrade() {
    setInterval(async () => {
      try {
        const quote = await this.getQuote()
        const price = this.calculatePrice(quote)

        if (this.shouldTrade(price)) {
          await this.executeTrade(quote)
        }
      } catch (error) {
        console.error('Error in trading loop:', error)
      }
    }, 60000) // Check every minute
  }

  private async getQuote() {
    return this.sdk.getQuote({
      // ... quote parameters
    })
  }

  private calculatePrice(quote: any): number {
    const buyAmount = Number(quote.quoteResults.amountsAndCosts.afterNetworkCosts.buyAmount)
    const sellAmount = Number(quote.quoteResults.orderToSign.sellAmount)
    return buyAmount / sellAmount
  }

  private shouldTrade(price: number): boolean {
    // Implement your trading logic
    const targetPrice = 2000 // Example: WETH to USDC price
    return price >= targetPrice
  }

  private async executeTrade(quote: any) {
    const result = await quote.postSwapOrderFromQuote({})
    console.log('Trade executed:', result.orderId)
  }
}

// Usage
const bot = new TradingBot(sdk)
bot.monitorAndTrade()

Batch Order Processing

Process multiple orders efficiently:
batch.ts
import { TradingSdk, OrderKind } from '@cowprotocol/cow-sdk'

interface OrderRequest {
  sellToken: string
  buyToken: string
  sellAmount: string
  slippageBps: number
}

async function processBatchOrders(
  sdk: TradingSdk,
  orders: OrderRequest[],
  chainId: number,
  owner: string
) {
  const results = await Promise.allSettled(
    orders.map(async (order) => {
      const quote = await sdk.getQuote({
        chainId,
        kind: OrderKind.SELL,
        owner,
        amount: order.sellAmount,
        sellToken: order.sellToken,
        sellTokenDecimals: 18,
        buyToken: order.buyToken,
        buyTokenDecimals: 18,
        slippageBps: order.slippageBps,
      })

      return quote.postSwapOrderFromQuote({})
    })
  )

  results.forEach((result, index) => {
    if (result.status === 'fulfilled') {
      console.log(`Order ${index} posted:`, result.value.orderId)
    } else {
      console.error(`Order ${index} failed:`, result.reason)
    }
  })
}

Order Monitoring

Monitor order status until fulfillment:
monitor.ts
import { OrderBookApi } from '@cowprotocol/sdk-order-book'

async function waitForOrderFulfillment(
  orderUid: string,
  chainId: number,
  maxWaitTime = 300000 // 5 minutes
) {
  const orderBookApi = new OrderBookApi({ chainId })
  const startTime = Date.now()

  while (Date.now() - startTime < maxWaitTime) {
    const order = await orderBookApi.getOrder(orderUid)

    console.log(`Order status: ${order.status}`)

    if (order.status === 'fulfilled') {
      console.log('Order fulfilled!')
      console.log('Executed buy amount:', order.executedBuyAmount)
      console.log('Executed sell amount:', order.executedSellAmount)
      return order
    }

    if (order.status === 'cancelled' || order.status === 'expired') {
      throw new Error(`Order ${order.status}`)
    }

    // Wait 10 seconds before checking again
    await new Promise(resolve => setTimeout(resolve, 10000))
  }

  throw new Error('Order fulfillment timeout')
}

// Usage
const result = await quoteAndPost.postSwapOrderFromQuote({})
await waitForOrderFulfillment(result.orderId, chainId)

Error Handling and Retries

Implement robust error handling:
retry.ts
async function postOrderWithRetry(
  sdk: TradingSdk,
  params: any,
  maxRetries = 3
) {
  let lastError: Error

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      console.log(`Attempt ${attempt} of ${maxRetries}`)

      const quote = await sdk.getQuote(params)
      const result = await quote.postSwapOrderFromQuote({})

      console.log('Order posted successfully')
      return result
    } catch (error) {
      lastError = error as Error
      console.error(`Attempt ${attempt} failed:`, error.message)

      if (attempt < maxRetries) {
        const delay = Math.pow(2, attempt) * 1000 // Exponential backoff
        console.log(`Retrying in ${delay}ms...`)
        await new Promise(resolve => setTimeout(resolve, delay))
      }
    }
  }

  throw new Error(`Failed after ${maxRetries} attempts: ${lastError.message}`)
}

Logging and Monitoring

Add comprehensive logging:
logging.ts
import { enableLogging } from '@cowprotocol/sdk-common'

// Enable SDK logging
enableLogging(true)

const sdk = new TradingSdk(
  {
    chainId,
    appCode: 'NodeScript',
    signer: wallet,
  },
  {
    enableLogging: true,
  }
)

// Custom logger
function logOrderDetails(order: any) {
  console.log('\n=== Order Details ===')
  console.log('Sell Token:', order.sellToken)
  console.log('Buy Token:', order.buyToken)
  console.log('Sell Amount:', order.sellAmount)
  console.log('Buy Amount:', order.buyAmount)
  console.log('Slippage:', order.slippageBps / 100, '%')
  console.log('=====================\n')
}

Testing

Test your Node.js scripts:
test.ts
import { describe, it, expect } from 'vitest'
import { TradingSdk } from '@cowprotocol/cow-sdk'

describe('Trading Bot', () => {
  it('should create a valid quote', async () => {
    const sdk = new TradingSdk({
      chainId: 11155111,
      appCode: 'Test',
    })

    const quote = await sdk.getQuoteOnly({
      owner: '0x...',
      kind: OrderKind.SELL,
      // ... other params
    })

    expect(quote.amountsAndCosts.afterNetworkCosts.buyAmount).toBeDefined()
  })
})

Production Considerations

  1. Use Environment Variables: Never hardcode private keys
  2. Implement Rate Limiting: Avoid API rate limits
  3. Add Health Checks: Monitor your bot’s health
  4. Use Proper Logging: Log all important events
  5. Handle Errors Gracefully: Implement retry logic
  6. Monitor Gas Prices: Optimize for network conditions
  7. Secure Private Keys: Use secure key management systems

Next Steps

Last modified on March 4, 2026