Skip to main content

Cross-Chain Bridging

The CoW Protocol SDK provides seamless cross-chain token transfers through integration with multiple bridge providers. This enables you to swap tokens across different blockchain networks in a single transaction.

Installation

npm install @cowprotocol/sdk-bridging

Basic Usage

Initialize the BridgingSdk

import {
  SupportedChainId,
  BridgingSdk,
  QuoteBridgeRequest,
  OrderKind,
  assertIsBridgeQuoteAndPost,
} from '@cowprotocol/sdk-bridging'
import { EthersV6Adapter } from '@cowprotocol/sdk-ethers-v6-adapter'
import { JsonRpcProvider, Wallet } from 'ethers'

// Configure the adapter
const provider = new JsonRpcProvider('YOUR_RPC_URL')
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider)
const adapter = new EthersV6Adapter({ provider, signer: wallet })

// Initialize bridging SDK
const bridging = new BridgingSdk(adapter, options)

Get a Cross-Chain Quote

const parameters: QuoteBridgeRequest = {
  // Cross-chain orders are always SELL orders (BUY not supported yet)
  kind: OrderKind.SELL,

  // Sell token (and source chain)
  sellTokenChainId: SupportedChainId.ARBITRUM_ONE,
  sellTokenAddress: '0xfff9976782d46cc05630d1f6ebab18b2324d6b14',
  sellTokenDecimals: 18,

  // Buy token (and target chain)
  buyTokenChainId: SupportedChainId.BASE,
  buyTokenAddress: '0x0625afb445c3b6b7b929342a04a22599fd5dbb59',
  buyTokenDecimals: 18,

  // Amount to sell
  amount: '120000000000000000',

  signer: adapter.signer,

  // Optional parameters
  appCode: 'YOUR_APP_CODE',
}

// Get a quote (and the post callback) for a cross-chain swap
const quoteResult = await sdk.getQuote(parameters)
// Assert that the quote result is of type BridgeQuoteAndPost
// (type for cross-chain quotes, as opposed to QuoteAndPost for single-chain quotes).
assertIsBridgeQuoteAndPost(quoteResult)
const { swap, bridge, postSwapOrderFromQuote } = quoteResult

// Display all data related to the swap (costs, amounts, appData including the bridging hook, etc.)
console.log('Swap info', swap)

// Display all data related to the bridge (costs, amounts, provider info, hook, and the bridging quote)
console.log('Bridge info', bridge)

// Get the buy amount after slippage in the target chain
const { buyAmount } = bridge.amountsAndCosts.afterSlippage

if (confirm(`You will get at least: ${buyAmount}, ok?`)) {
  const orderId = await postSwapOrderFromQuote()
  console.log('Order created, id: ', orderId)
}
Cross-chain orders are always SELL orders. BUY orders are not yet supported for cross-chain swaps.

Multi-Provider Quotes

Get Quotes from All Providers

The getMultiQuotes() method allows you to get quotes from multiple bridge providers simultaneously:
import { MultiQuoteRequest } from '@cowprotocol/sdk-bridging'

const multiQuoteRequest: MultiQuoteRequest = {
  quoteBridgeRequest: parameters, // Same parameters as above
  providerDappIds: ['provider1', 'provider2'], // Optional: specify which providers to query
  advancedSettings: {
    slippageBps: 100, // 1% slippage tolerance
  },
  options: {
    totalTimeout: 15000,        // 15 seconds total timeout
    providerTimeout: 8000, // 8 seconds per provider timeout
  }
}

// Get quotes from all providers
const results = await bridgingSdk.getMultiQuotes(multiQuoteRequest)

results.forEach((result) => {
  if (result.quote) {
    console.log(`Quote from ${result.providerDappId}:`, result.quote)
  } else {
    console.log(`Error from ${result.providerDappId}:`, result.error?.message)
  }
})

Progressive Quote Results

Receive quotes progressively as each provider responds:
const progressiveResults: MultiQuoteResult[] = []

const multiQuoteRequest: MultiQuoteRequest = {
  quoteBridgeRequest: parameters,
  options: {
    // Receive quotes as they arrive
    onQuoteResult: (result) => {
      progressiveResults.push(result)

      if (result.quote) {
        console.log(`✅ Quote received from ${result.providerDappId}`)
        // Update UI immediately with the new quote
        displayQuoteInUI(result)
      } else {
        console.log(`❌ Error from ${result.providerDappId}: ${result.error?.message}`)
      }
    },
    totalTimeout: 20000,       // 20 seconds total timeout
    providerTimeout: 5000 // 5 seconds per provider timeout
  }
}

// This will return all results once completed (or timed out)
const finalResults = await bridgingSdk.getMultiQuotes(multiQuoteRequest)

console.log(`Received ${finalResults.filter(r => r.quote).length} successful quotes out of ${finalResults.length} providers`)

Best Quote Selection

Use getBestQuote() to get only the best quote from all available providers:
// Get the best quote from all available providers
const bestQuote = await bridgingSdk.getBestQuote({
  quoteBridgeRequest: parameters,
  providerDappIds: ['provider1', 'provider2'], // Optional: specify which providers to query
  advancedSettings: {
    slippageBps: 100, // 1% slippage tolerance
  },
  options: {
    totalTimeout: 15000,       // 15 seconds total timeout
    providerTimeout: 8000,     // 8 seconds per provider timeout
  }
})

if (bestQuote?.quote) {
  console.log(`Best quote from ${bestQuote.providerDappId}:`, bestQuote.quote)
  const { buyAmount } = bestQuote.quote.bridge.amountsAndCosts.afterSlippage
  console.log(`You will receive: ${buyAmount} tokens`)
} else if (bestQuote?.error) {
  console.log('All providers failed, first error:', bestQuote.error.message)
}

Progressive Best Quote Updates

let currentBest: MultiQuoteResult | null = null

const bestQuote = await bridgingSdk.getBestQuote({
  quoteBridgeRequest: parameters,
  options: {
    // Called whenever a better quote is found
    onQuoteResult: (result) => {
      currentBest = result
      console.log(`🚀 New best quote from ${result.providerDappId}!`)

      if (result.quote) {
        const buyAmount = result.quote.bridge.amountsAndCosts.afterSlippage.buyAmount
        console.log(`Better quote found: ${buyAmount} tokens`)

        // Update UI immediately with the new best quote
        updateBestQuoteInUI(result)
      }
    },
    totalTimeout: 20000,      // 20 seconds total timeout
    providerTimeout: 5000     // 5 seconds per provider timeout
  }
})

console.log('Final best quote:', bestQuote)
Use getBestQuote() when you only need the single best quote. Use getMultiQuotes() when you need to display all available options to users.

Provider Management

Get Available Providers

// Get all active providers
const providers = bridgingSdk.getAvailableProviders()

providers.forEach((provider) => {
  console.log(`Provider: ${provider.info.name}`)
  console.log(`Dapp ID: ${provider.info.dappId}`)
  console.log(`Networks: ${provider.info.supportedChains.join(', ')}`)
})

Filter Active Providers

// Initially, all configured providers are available
const allProviders = bridgingSdk.getAvailableProviders()
console.log(`Total providers: ${allProviders.length}`)

// Filter to use only specific providers
bridgingSdk.setAvailableProviders(['across', 'hop-protocol'])

// Now only the specified providers will be used
const filteredProviders = bridgingSdk.getAvailableProviders()
console.log(`Active providers: ${filteredProviders.length}`)

// Reset to use all providers again
bridgingSdk.setAvailableProviders([])
const resetProviders = bridgingSdk.getAvailableProviders()
console.log(`Reset to all providers: ${resetProviders.length}`)

Timeout Configuration

The multi-quote methods support two types of timeouts:
const results = await bridgingSdk.getMultiQuotes({
  quoteBridgeRequest: parameters,
  options: {
    // Global timeout: Maximum time to wait for all providers to complete
    totalTimeout: 30000,        // 30 seconds (default)

    // Individual provider timeout: Maximum time each provider has to respond
    providerTimeout: 15000, // 15 seconds (default)

    onQuoteResult: (result) => {
      // Handle progressive results
      console.log(`Received result from ${result.providerDappId}`);
    }
  }
});
How timeouts work:
  • providerTimeout: Each provider has this amount of time to complete their quote request. If exceeded, that provider returns a timeout error.
  • totalTimeout: The total time to wait for all providers. After this time, any remaining providers are marked as timed out.
  • Providers that complete within their individual timeout but after the global timeout will still be included in the final results.

Comparison Table

FeaturegetBestQuote()getMultiQuotes()
ReturnsSingle best resultArray of all results
Progressive CallbacksOnly for better quotesFor all results (success & error)
Error HandlingReturns first error if all failReturns all errors in array
PerformanceOptimized for best result onlyReturns complete data set
Use CaseWhen you only need the best quoteWhen you need to compare all options

Error Handling

try {
  const quoteResult = await bridgingSdk.getQuote(parameters)
  assertIsBridgeQuoteAndPost(quoteResult)
  const { swap, bridge, postSwapOrderFromQuote } = quoteResult

  // Post the order
  const orderId = await postSwapOrderFromQuote()
  console.log('Order created:', orderId)
} catch (error) {
  if (error.message.includes('No available providers')) {
    console.error('No bridge providers available for this route')
  } else if (error.message.includes('timeout')) {
    console.error('Quote request timed out')
  } else {
    console.error('Failed to get cross-chain quote:', error)
  }
}

Next Steps

Last modified on March 4, 2026