Crate odos_sdk

Crate odos_sdk 

Source
Expand description

§Odos SDK

A production-ready Rust SDK for the Odos protocol - a decentralized exchange aggregator that provides optimal routing for token swaps across multiple EVM chains.

§Features

  • Multi-chain Support: 16+ EVM chains including Ethereum, Arbitrum, Optimism, Polygon, Base, etc.
  • Type-safe: Leverages Rust’s type system with Alloy primitives for addresses, chain IDs, and amounts
  • Production-ready: Built-in retry logic, circuit breakers, timeouts, and error handling
  • Builder Pattern: Ergonomic API using the bon crate for request building
  • Comprehensive Error Handling: Detailed error types for different failure scenarios

§Quick Start

§High-Level API with SwapBuilder

The easiest way to get started is with the SwapBuilder API:

use odos_sdk::prelude::*;
use std::str::FromStr;

// Create a client
let client = OdosClient::new()?;

// Define tokens and amount
let usdc = Address::from_str("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48")?; // USDC on Ethereum
let weth = Address::from_str("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")?; // WETH on Ethereum
let my_address = Address::from_str("0x742d35Cc6634C0532925a3b8D35f3e7a5edD29c0")?;

// Build and execute swap in one go
let transaction = client.swap()
    .chain(Chain::ethereum())
    .from_token(usdc, U256::from(1_000_000)) // 1 USDC (6 decimals)
    .to_token(weth)
    .slippage(Slippage::percent(0.5).unwrap()) // 0.5% slippage
    .signer(my_address)
    .build_transaction()
    .await?;

println!("Transaction ready: {:?}", transaction);

§Low-Level API

For more control, use the low-level API with quote() and assemble():

use odos_sdk::prelude::*;
use alloy_primitives::address;
use std::str::FromStr;

let client = OdosClient::new()?;
let usdc = Address::from_str("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48")?;
let weth = Address::from_str("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")?;

// Step 1: Get a quote
let quote_request = QuoteRequest::builder()
    .chain_id(1)
    .input_tokens(vec![(usdc, U256::from(1_000_000)).into()])
    .output_tokens(vec![(weth, 1).into()])
    .slippage_limit_percent(0.5)
    .user_addr(address!("742d35Cc6634C0532925a3b8D35f3e7a5edD29c0"))
    .compact(false)
    .simple(false)
    .referral_code(0)
    .disable_rfqs(false)
    .build();

let quote = client.quote(&quote_request).await?;
println!("Expected output: {} WETH", quote.out_amount().unwrap_or(&"0".to_string()));

// Step 2: Assemble transaction
let assembly_request = AssemblyRequest::builder()
    .chain(alloy_chains::NamedChain::Mainnet)
    .router_address(alloy_chains::NamedChain::Mainnet.v2_router_address()?)
    .signer_address(Address::from_str("0x742d35Cc6634C0532925a3b8D35f3e7a5edD29c0")?)
    .output_recipient(Address::from_str("0x742d35Cc6634C0532925a3b8D35f3e7a5edD29c0")?)
    .token_address(usdc)
    .token_amount(U256::from(1_000_000))
    .path_id(quote.path_id().to_string())
    .build();

let transaction = client.assemble(&assembly_request).await?;

§Configuration

The SDK supports extensive configuration for production use:

use odos_sdk::*;
use std::time::Duration;

// Full configuration
let config = ClientConfig {
    timeout: Duration::from_secs(30),
    connect_timeout: Duration::from_secs(10),
    retry_config: RetryConfig {
        max_retries: 3,
        initial_backoff_ms: 100,
        retry_server_errors: true,
        retry_predicate: None,
    },
    max_connections: 20,
    pool_idle_timeout: Duration::from_secs(90),
    api_key: None,
    ..Default::default()
};
let client = OdosClient::with_config(config)?;

// Or use convenience constructors
let client = OdosClient::with_retry_config(RetryConfig::conservative())?;

§Error Handling

The SDK provides comprehensive error types with strongly-typed error codes:

use odos_sdk::*;
use alloy_primitives::Address;

match client.quote(&quote_request).await {
    Ok(quote) => {
        // Handle successful quote
        println!("Got quote with path ID: {}", quote.path_id());
    }
    Err(err) => {
        // Check for specific error codes
        if let Some(code) = err.error_code() {
            if code.is_invalid_chain_id() {
                eprintln!("Invalid chain ID - check configuration");
            } else if code.is_no_viable_path() {
                eprintln!("No routing path found");
            } else if code.is_timeout() {
                eprintln!("Service timeout: {}", code);
            }
        }

        // Log trace ID for support
        if let Some(trace_id) = err.trace_id() {
            eprintln!("Trace ID: {}", trace_id);
        }

        // Handle by error type
        match err {
            OdosError::Api { status, message, .. } => {
                eprintln!("API error {}: {}", status, message);
            }
            OdosError::Timeout(msg) => {
                eprintln!("Request timed out: {}", msg);
            }
            OdosError::RateLimit { message, retry_after, .. } => {
                if let Some(duration) = retry_after {
                    eprintln!("Rate limited: {}. Retry after {} seconds", message, duration.as_secs());
                } else {
                    eprintln!("Rate limited: {}", message);
                }
            }
            _ => eprintln!("Error: {}", err),
        }
    }
}

§Strongly-Typed Error Codes

The SDK provides error codes matching the Odos API documentation:

  • General (1XXX): ApiError
  • Algo/Quote (2XXX): NoViablePath, AlgoTimeout, AlgoInternal
  • Internal Service (3XXX): TxnAssemblyTimeout, GasUnavailable
  • Validation (4XXX): InvalidChainId, BlockedUserAddr, InvalidTokenAmount
  • Internal (5XXX): InternalError, SwapUnavailable
use odos_sdk::{OdosError, error_code::OdosErrorCode};

if let Some(code) = error.error_code() {
    // Check categories
    if code.is_validation_error() {
        println!("Validation error - check request parameters");
    }

    // Check retryability
    if code.is_retryable() {
        println!("Error can be retried: {}", code);
    }
}

§Rate Limiting

The Odos API enforces rate limits to ensure fair usage. The SDK handles rate limits intelligently:

  • HTTP 429 responses are detected and classified as OdosError::RateLimit
  • Rate limit errors are NOT retried (return immediately with Retry-After header)
  • The SDK captures Retry-After headers for application-level handling
  • Applications should handle rate limits globally with proper backoff coordination

§Best Practices for Avoiding Rate Limits

  1. Share a single client across your application instead of creating new clients per request
  2. Implement application-level rate limiting if making many concurrent requests
  3. Handle rate limit errors gracefully and back off at the application level if needed

§Example: Handling Rate Limits

use odos_sdk::*;
use alloy_primitives::{Address, U256};
use std::time::Duration;

match client.quote(&quote_request).await {
    Ok(quote) => {
        println!("Got quote: {}", quote.path_id());
    }
    Err(e) if e.is_rate_limit() => {
        // Rate limit exceeded even after SDK retries
        // Consider backing off at application level
        eprintln!("Rate limited - waiting before retry");
        tokio::time::sleep(Duration::from_secs(5)).await;
        // Retry or handle accordingly
    }
    Err(e) => {
        eprintln!("Error: {}", e);
    }
}

§Configuring Retry Behavior

You can customize retry behavior for your use case:

use odos_sdk::*;

// Conservative: only retry network errors
let client = OdosClient::with_retry_config(RetryConfig::conservative())?;

// No retries: handle all errors at application level
let client = OdosClient::with_retry_config(RetryConfig::no_retries())?;

// Custom configuration
let retry_config = RetryConfig {
    max_retries: 5,
    initial_backoff_ms: 200,
    retry_server_errors: false,  // Don't retry 5xx errors
    retry_predicate: None,
};
let client = OdosClient::with_retry_config(retry_config)?;

Note: Rate limit errors (429) are never retried regardless of configuration. This prevents retry cascades that make rate limiting worse.

Modules§

IOdosRouterV3
Module containing a contract’s types and functions.
OdosRouterV2
Module containing a contract’s types and functions.
OdosV2Router
Generated by the following Solidity interface…
OdosV3Router
Generated by the following Solidity interface…
error_code
Strongly-typed Odos API error codes
prelude
Prelude module for convenient imports

Structs§

ApiKey
API key for authenticating with the Odos API
AssembleRequest
Request to the Odos Assemble API: https://docs.odos.xyz/build/api-docs
AssemblyRequest
Request for assembling a transaction from a quote
AssemblyResponse
Response from the Odos Assemble API: https://docs.odos.xyz/build/api-docs
Chain
Type-safe chain identifier with convenient constructors
ClientConfig
Configuration for the HTTP client
Endpoint
Complete API endpoint configuration combining host tier and API version
InputToken
Input token for the Odos quote API
OdosApiErrorResponse
Error response from the Odos API
OdosClient
The Odos API client
OdosHttpClient
Enhanced HTTP client with retry logic and timeouts
OutputToken
Output token for the Odos quote API
QuoteRequest
Request to the Odos quote API: https://docs.odos.xyz/build/api-docs
ReferralCode
Type-safe referral code
RetryConfig
Configuration for retry behavior
RouterAvailability
Represents which routers are available on a specific chain
Simulation
Simulation from the Odos Assemble API: https://docs.odos.xyz/build/api-docs
SimulationError
Simulation error from the Odos Assemble API: https://docs.odos.xyz/build/api-docs
SingleQuoteResponse
Single quote response from the Odos quote API: https://docs.odos.xyz/build/api-docs
Slippage
Type-safe slippage percentage with validation
SwapBuilder
High-level swap builder for common use cases
SwapInputs
Swap inputs for the Odos assemble API
TransactionData
Transaction data from the Odos Assemble API: https://docs.odos.xyz/build/api-docs
TransferRouterFunds
A transfer of a token from one address to another.
V2Router
The V2 SOR Router contract.
V3Router
The V2 SOR Router contract.

Enums§

ApiHost
API host tier for the Odos API
ApiVersion
Version of the Odos API
OdosChainError
Errors that can occur when working with Odos chains
OdosError
Comprehensive error types for the Odos SDK
RouterType
Represents the different types of Odos routers

Constants§

ODOS_LO_ARBITRUM_ROUTER
Arbitrum One - Limit Order V2 Router contract address
ODOS_LO_AVALANCHE_ROUTER
Avalanche C-Chain - Limit Order V2 Router contract address
ODOS_LO_BASE_ROUTER
Base - Limit Order V2 Router contract address
ODOS_LO_BSC_ROUTER
BNB Smart Chain - Limit Order V2 Router contract address
ODOS_LO_ETHEREUM_ROUTER
Ethereum Mainnet - Limit Order V2 Router contract address
ODOS_LO_FRAXTAL_ROUTER
Fraxtal - Limit Order V2 Router contract address
ODOS_LO_LINEA_ROUTER
Linea - Limit Order V2 Router contract address
ODOS_LO_MANTLE_ROUTER
Mantle - Limit Order V2 Router contract address
ODOS_LO_MODE_ROUTER
Mode - Limit Order V2 Router contract address
ODOS_LO_OP_ROUTER
Optimism - Limit Order V2 Router contract address
ODOS_LO_POLYGON_ROUTER
Polygon - Limit Order V2 Router contract address
ODOS_LO_SCROLL_ROUTER
Scroll - Limit Order V2 Router contract address
ODOS_LO_SONIC_ROUTER
Sonic - Limit Order V2 Router contract address
ODOS_LO_UNICHAIN_ROUTER
Unichain - Limit Order V2 Router contract address
ODOS_LO_ZKSYNC_ROUTER
zkSync Era - Limit Order V2 Router contract address
ODOS_V3
Odos V3 Router - Next-generation router contract
ODOS_V2_ARBITRUM_ROUTER
Arbitrum One - V2 Router contract address
ODOS_V2_AVALANCHE_ROUTER
Avalanche C-Chain - V2 Router contract address
ODOS_V2_BASE_ROUTER
Base - V2 Router contract address
ODOS_V2_BSC_ROUTER
BNB Smart Chain - V2 Router contract address
ODOS_V2_ETHEREUM_ROUTER
Ethereum Mainnet - V2 Router contract address
ODOS_V2_FRAXTAL_ROUTER
Fraxtal - V2 Router contract address
ODOS_V2_LINEA_ROUTER
Linea - V2 Router contract address
ODOS_V2_MANTLE_ROUTER
Mantle - V2 Router contract address
ODOS_V2_MODE_ROUTER
Mode - V2 Router contract address
ODOS_V2_OP_ROUTER
Optimism - V2 Router contract address
ODOS_V2_POLYGON_ROUTER
Polygon - V2 Router contract address
ODOS_V2_SCROLL_ROUTER
Scroll - V2 Router contract address
ODOS_V2_SONIC_ROUTER
Sonic - V2 Router contract address
ODOS_V2_UNICHAIN_ROUTER
Unichain - V2 Router contract address
ODOS_V2_ZKSYNC_ROUTER
zkSync Era - V2 Router contract address

Traits§

OdosChain
Trait for chains that support Odos protocol
OdosRouterSelection
Extension trait for easy router selection

Functions§

get_lo_router_by_chain_id
Get the Limit Order V2 router address for a specific chain ID
get_supported_chains
Get all supported chains
get_supported_lo_chains
Get all chains that support Limit Order V2 routers
get_supported_v2_chains
Get all chains that support V2 routers
get_supported_v3_chains
Get all chains that support V3 routers
get_v2_router_by_chain_id
Get the V2 router address for a specific chain ID
get_v3_router_by_chain_id
Get the V3 router address for a specific chain ID
parse_value
Parse a value string as U256, supporting both decimal and hexadecimal formats

Type Aliases§

OdosChainResult
Result type for Odos chain operations
OdosSorDeprecated
Deprecated alias for OdosClient
Result
Result type alias for Odos SDK operations
SwapContextDeprecated
Deprecated alias for AssemblyRequest