use serde::{Deserialize, Serialize};
pub type ChainId = u64;
pub mod chains {
use super::ChainId;
pub const ETHEREUM: ChainId = 1;
pub const OPTIMISM: ChainId = 10;
pub const BSC: ChainId = 56;
pub const GNOSIS: ChainId = 100;
pub const POLYGON: ChainId = 137;
pub const FANTOM: ChainId = 250;
pub const ZKSYNC: ChainId = 324;
pub const POLYGON_ZKEVM: ChainId = 1101;
pub const BASE: ChainId = 8453;
pub const ARBITRUM: ChainId = 42161;
pub const AVALANCHE: ChainId = 43114;
pub const LINEA: ChainId = 59144;
pub const BLAST: ChainId = 81457;
pub const SCROLL: ChainId = 534352;
pub const MANTLE: ChainId = 5000;
pub const MODE: ChainId = 34443;
pub const SOLANA: ChainId = 1151111081099710;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Token {
pub address: String,
pub chain_id: ChainId,
pub symbol: String,
pub decimals: u8,
pub name: String,
#[serde(default)]
pub coin_key: Option<String>,
#[serde(default)]
pub logo_uri: Option<String>,
#[serde(default)]
pub price_usd: Option<String>,
#[serde(default)]
pub tags: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TokenAmount {
#[serde(flatten)]
pub token: Token,
pub amount: String,
#[serde(default)]
pub amount_usd: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct QuoteRequest {
pub from_chain: ChainId,
pub to_chain: ChainId,
pub from_token: String,
pub to_token: String,
pub from_amount: String,
pub from_address: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub to_address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub slippage: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub integrator: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fee: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub referrer: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub allow_bridges: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deny_bridges: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub allow_exchanges: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deny_exchanges: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub order: Option<RouteOrder>,
#[serde(skip_serializing_if = "Option::is_none")]
pub allow_switch_chain: Option<bool>,
}
impl QuoteRequest {
pub fn new(
from_chain: ChainId,
to_chain: ChainId,
from_token: impl Into<String>,
to_token: impl Into<String>,
from_amount: impl Into<String>,
from_address: impl Into<String>,
) -> Self {
Self {
from_chain,
to_chain,
from_token: from_token.into(),
to_token: to_token.into(),
from_amount: from_amount.into(),
from_address: from_address.into(),
to_address: None,
slippage: None,
integrator: None,
fee: None,
referrer: None,
allow_bridges: None,
deny_bridges: None,
allow_exchanges: None,
deny_exchanges: None,
order: None,
allow_switch_chain: None,
}
}
#[must_use]
pub fn with_to_address(mut self, to_address: impl Into<String>) -> Self {
self.to_address = Some(to_address.into());
self
}
#[must_use]
pub fn with_slippage(mut self, slippage: f64) -> Self {
self.slippage = Some(slippage);
self
}
#[must_use]
pub fn with_integrator(mut self, integrator: impl Into<String>) -> Self {
self.integrator = Some(integrator.into());
self
}
#[must_use]
pub fn with_fee(mut self, fee: f64) -> Self {
self.fee = Some(fee);
self
}
#[must_use]
pub fn with_referrer(mut self, referrer: impl Into<String>) -> Self {
self.referrer = Some(referrer.into());
self
}
#[must_use]
pub fn with_allowed_bridges(mut self, bridges: Vec<String>) -> Self {
self.allow_bridges = Some(bridges);
self
}
#[must_use]
pub fn with_denied_bridges(mut self, bridges: Vec<String>) -> Self {
self.deny_bridges = Some(bridges);
self
}
#[must_use]
pub fn with_allowed_exchanges(mut self, exchanges: Vec<String>) -> Self {
self.allow_exchanges = Some(exchanges);
self
}
#[must_use]
pub fn with_denied_exchanges(mut self, exchanges: Vec<String>) -> Self {
self.deny_exchanges = Some(exchanges);
self
}
#[must_use]
pub fn with_order(mut self, order: RouteOrder) -> Self {
self.order = Some(order);
self
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum RouteOrder {
#[default]
Recommended,
Fastest,
Cheapest,
Safest,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Quote {
pub id: String,
#[serde(rename = "type")]
pub quote_type: String,
pub tool: String,
#[serde(default)]
pub tool_details: Option<ToolDetails>,
pub action: Action,
pub estimate: Estimate,
#[serde(default)]
pub transaction_request: Option<TransactionRequest>,
#[serde(default)]
pub included_steps: Vec<Step>,
#[serde(default)]
pub integrator: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RoutesRequest {
pub from_chain_id: ChainId,
pub from_token_address: String,
pub from_amount: String,
pub from_address: String,
pub to_chain_id: ChainId,
pub to_token_address: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub to_address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub options: Option<RoutesOptions>,
}
impl RoutesRequest {
pub fn new(
from_chain_id: ChainId,
from_token_address: impl Into<String>,
from_amount: impl Into<String>,
from_address: impl Into<String>,
to_chain_id: ChainId,
to_token_address: impl Into<String>,
) -> Self {
Self {
from_chain_id,
from_token_address: from_token_address.into(),
from_amount: from_amount.into(),
from_address: from_address.into(),
to_chain_id,
to_token_address: to_token_address.into(),
to_address: None,
options: None,
}
}
#[must_use]
pub fn with_to_address(mut self, to_address: impl Into<String>) -> Self {
self.to_address = Some(to_address.into());
self
}
#[must_use]
pub fn with_options(mut self, options: RoutesOptions) -> Self {
self.options = Some(options);
self
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RoutesOptions {
#[serde(skip_serializing_if = "Option::is_none")]
pub slippage: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub integrator: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fee: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub referrer: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bridges: Option<BridgeOptions>,
#[serde(skip_serializing_if = "Option::is_none")]
pub exchanges: Option<ExchangeOptions>,
#[serde(skip_serializing_if = "Option::is_none")]
pub order: Option<RouteOrder>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_price_impact: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub allow_destination_call: Option<bool>,
}
impl RoutesOptions {
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn with_slippage(mut self, slippage: f64) -> Self {
self.slippage = Some(slippage);
self
}
#[must_use]
pub fn with_integrator(mut self, integrator: impl Into<String>) -> Self {
self.integrator = Some(integrator.into());
self
}
#[must_use]
pub fn with_bridges(mut self, bridges: BridgeOptions) -> Self {
self.bridges = Some(bridges);
self
}
#[must_use]
pub fn with_exchanges(mut self, exchanges: ExchangeOptions) -> Self {
self.exchanges = Some(exchanges);
self
}
#[must_use]
pub fn with_order(mut self, order: RouteOrder) -> Self {
self.order = Some(order);
self
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BridgeOptions {
#[serde(skip_serializing_if = "Option::is_none")]
pub allow: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deny: Option<Vec<String>>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ExchangeOptions {
#[serde(skip_serializing_if = "Option::is_none")]
pub allow: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deny: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RoutesResponse {
pub routes: Vec<Route>,
#[serde(default)]
pub unavailable_routes: Option<UnavailableRoutes>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UnavailableRoutes {
#[serde(default)]
pub filtered_out: Vec<FilteredRoute>,
#[serde(default)]
pub failed: Vec<FailedRoute>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FilteredRoute {
pub tool: String,
pub reason: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FailedRoute {
pub tool: String,
pub error_message: String,
#[serde(default)]
pub error_code: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Route {
pub id: String,
pub from_chain_id: ChainId,
pub from_token: Token,
pub from_amount: String,
#[serde(default)]
pub from_amount_usd: Option<String>,
pub from_address: String,
pub to_chain_id: ChainId,
pub to_token: Token,
pub to_amount: String,
#[serde(default)]
pub to_amount_usd: Option<String>,
pub to_amount_min: String,
#[serde(default)]
pub to_address: Option<String>,
pub steps: Vec<Step>,
#[serde(default)]
pub gas_cost_usd: Option<String>,
#[serde(default)]
pub execution_duration: Option<u64>,
#[serde(default)]
pub tags: Vec<String>,
#[serde(default)]
pub insurance: Option<Insurance>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Insurance {
pub state: String,
#[serde(default)]
pub fee_amount_usd: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Step {
pub id: String,
#[serde(rename = "type")]
pub step_type: StepType,
pub tool: String,
#[serde(default)]
pub tool_details: Option<ToolDetails>,
pub action: Action,
pub estimate: Estimate,
#[serde(default)]
pub transaction_request: Option<TransactionRequest>,
#[serde(default)]
pub included_steps: Vec<Step>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum StepType {
Swap,
Cross,
Lifi,
Protocol,
Custom,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ToolDetails {
pub key: String,
pub name: String,
#[serde(default)]
pub logo_uri: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Action {
pub from_chain_id: ChainId,
pub from_token: Token,
pub from_amount: String,
pub to_chain_id: ChainId,
pub to_token: Token,
#[serde(default)]
pub slippage: Option<f64>,
#[serde(default)]
pub from_address: Option<String>,
#[serde(default)]
pub to_address: Option<String>,
#[serde(default)]
pub destination_call_data: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Estimate {
#[serde(default)]
pub tool: Option<String>,
pub from_amount: String,
#[serde(default)]
pub from_amount_usd: Option<String>,
pub to_amount: String,
#[serde(default)]
pub to_amount_usd: Option<String>,
pub to_amount_min: String,
#[serde(default)]
pub approval_address: Option<String>,
#[serde(default)]
pub execution_duration: Option<u64>,
#[serde(default)]
pub fee_costs: Option<Vec<FeeCost>>,
#[serde(default)]
pub gas_costs: Option<Vec<GasCost>>,
#[serde(default)]
pub data: Option<EstimateData>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FeeCost {
pub name: String,
#[serde(default)]
pub description: Option<String>,
pub token: Token,
pub amount: String,
#[serde(default)]
pub amount_usd: Option<String>,
#[serde(default)]
pub percentage: Option<String>,
#[serde(default)]
pub included: bool,
#[serde(default)]
pub fee_split: Option<FeeSplit>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FeeSplit {
pub integrator_fee: String,
pub lifi_fee: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GasCost {
#[serde(rename = "type")]
pub gas_type: String,
#[serde(default)]
pub estimate: Option<String>,
#[serde(default)]
pub limit: Option<String>,
pub amount: String,
#[serde(default)]
pub amount_usd: Option<String>,
#[serde(default)]
pub price: Option<String>,
pub token: Token,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EstimateData {
#[serde(default)]
pub exchange_rate: Option<String>,
#[serde(default)]
pub price_impact: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TransactionRequest {
pub to: String,
pub data: String,
pub value: String,
#[serde(default)]
pub from: Option<String>,
#[serde(default)]
pub chain_id: Option<ChainId>,
#[serde(default)]
pub gas_limit: Option<String>,
#[serde(default)]
pub gas_price: Option<String>,
#[serde(default)]
pub max_fee_per_gas: Option<String>,
#[serde(default)]
pub max_priority_fee_per_gas: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct StatusRequest {
pub tx_hash: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub bridge: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub from_chain: Option<ChainId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub to_chain: Option<ChainId>,
}
impl StatusRequest {
pub fn new(tx_hash: impl Into<String>) -> Self {
Self {
tx_hash: tx_hash.into(),
bridge: None,
from_chain: None,
to_chain: None,
}
}
#[must_use]
pub fn with_bridge(mut self, bridge: impl Into<String>) -> Self {
self.bridge = Some(bridge.into());
self
}
#[must_use]
pub fn with_from_chain(mut self, chain: ChainId) -> Self {
self.from_chain = Some(chain);
self
}
#[must_use]
pub fn with_to_chain(mut self, chain: ChainId) -> Self {
self.to_chain = Some(chain);
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct StatusResponse {
#[serde(default)]
pub transaction_id: Option<String>,
#[serde(default)]
pub sending: Option<TransactionInfo>,
#[serde(default)]
pub receiving: Option<TransactionInfo>,
#[serde(default)]
pub lifi_explorer_link: Option<String>,
#[serde(default)]
pub from_chain_id: Option<ChainId>,
#[serde(default)]
pub to_chain_id: Option<ChainId>,
#[serde(default)]
pub bridge: Option<String>,
pub status: TransactionStatus,
#[serde(default)]
pub substatus: Option<String>,
#[serde(default)]
pub substatus_message: Option<String>,
#[serde(default)]
pub metadata: Option<StatusMetadata>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TransactionInfo {
pub tx_hash: String,
#[serde(default)]
pub tx_link: Option<String>,
#[serde(default)]
pub amount: Option<String>,
#[serde(default)]
pub token: Option<Token>,
#[serde(default)]
pub chain_id: Option<ChainId>,
#[serde(default)]
pub gas_price: Option<String>,
#[serde(default)]
pub gas_used: Option<String>,
#[serde(default)]
pub gas_amount_usd: Option<String>,
#[serde(default)]
pub timestamp: Option<u64>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum TransactionStatus {
NotStarted,
Pending,
Done,
Failed,
Invalid,
NotFound,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct StatusMetadata {
#[serde(default)]
pub integrator: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Chain {
pub id: ChainId,
pub key: String,
pub name: String,
pub coin: String,
#[serde(default)]
pub chain_type: Option<String>,
#[serde(default)]
pub logo_uri: Option<String>,
#[serde(default)]
pub native_token: Option<Token>,
#[serde(default)]
pub tokens: Vec<Token>,
#[serde(default)]
pub mainnet: bool,
#[serde(default)]
pub multicall_address: Option<String>,
#[serde(default)]
pub metamask: Option<MetamaskChainInfo>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MetamaskChainInfo {
pub chain_id: String,
pub chain_name: String,
#[serde(default)]
pub native_currency: Option<NativeCurrency>,
#[serde(default)]
pub rpc_urls: Vec<String>,
#[serde(default)]
pub block_explorer_urls: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NativeCurrency {
pub name: String,
pub symbol: String,
pub decimals: u8,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ChainsResponse {
pub chains: Vec<Chain>,
}
#[derive(Debug, Clone, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ConnectionsRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub from_chain: Option<ChainId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub to_chain: Option<ChainId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub from_token: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub to_token: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub allow_bridges: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deny_bridges: Option<Vec<String>>,
}
impl ConnectionsRequest {
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn with_from_chain(mut self, chain: ChainId) -> Self {
self.from_chain = Some(chain);
self
}
#[must_use]
pub fn with_to_chain(mut self, chain: ChainId) -> Self {
self.to_chain = Some(chain);
self
}
#[must_use]
pub fn with_from_token(mut self, token: impl Into<String>) -> Self {
self.from_token = Some(token.into());
self
}
#[must_use]
pub fn with_to_token(mut self, token: impl Into<String>) -> Self {
self.to_token = Some(token.into());
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ConnectionsResponse {
pub connections: Vec<Connection>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Connection {
pub from_chain_id: ChainId,
pub to_chain_id: ChainId,
pub from_tokens: Vec<Token>,
pub to_tokens: Vec<Token>,
}
#[derive(Debug, Clone, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TokensRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub chains: Option<Vec<ChainId>>,
}
impl TokensRequest {
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn with_chains(mut self, chains: Vec<ChainId>) -> Self {
self.chains = Some(chains);
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TokensResponse {
pub tokens: std::collections::HashMap<String, Vec<Token>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Tool {
pub key: String,
pub name: String,
#[serde(rename = "type")]
pub tool_type: ToolType,
#[serde(default)]
pub logo_uri: Option<String>,
#[serde(default)]
pub supported_chains: Vec<ChainId>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ToolType {
Bridge,
Exchange,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ToolsResponse {
#[serde(default)]
pub bridges: Vec<Tool>,
#[serde(default)]
pub exchanges: Vec<Tool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GasPrice {
pub chain_id: ChainId,
#[serde(default)]
pub slow: Option<String>,
#[serde(default)]
pub average: Option<String>,
#[serde(default)]
pub fast: Option<String>,
#[serde(default)]
pub instant: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiError {
pub message: String,
#[serde(default)]
pub code: Option<String>,
}