Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/swapper/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl ProviderType {
| SwapperProvider::Okx => SwapProviderMode::OnChain,
SwapperProvider::Mayan | SwapperProvider::Chainflip | SwapperProvider::NearIntents => SwapProviderMode::CrossChain,
SwapperProvider::Thorchain => SwapProviderMode::OmniChain(vec![Chain::Thorchain, Chain::Tron]),
SwapperProvider::Relay => SwapProviderMode::OmniChain(vec![Chain::Hyperliquid, Chain::Manta, Chain::Berachain]),
SwapperProvider::Relay => SwapProviderMode::OmniChain(vec![Chain::Hyperliquid, Chain::Berachain]),
SwapperProvider::Across => SwapProviderMode::Bridge,
SwapperProvider::Hyperliquid => SwapProviderMode::OmniChain(vec![Chain::HyperCore, Chain::Hyperliquid]),
}
Expand Down
1 change: 0 additions & 1 deletion crates/swapper/src/near_intents/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,6 @@ mod swap_integration_tests {
use primitives::{
AssetId, Chain,
asset_constants::{USDC_ARB_ASSET_ID, USDC_BASE_ASSET_ID},
swap::SwapStatus,
};
use std::sync::Arc;

Expand Down
28 changes: 2 additions & 26 deletions crates/swapper/src/proxy/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ use crate::{
asset::*,
config::{DEFAULT_SWAP_FEE_BPS, get_swap_api_url},
models::{ApprovalType, SwapperChainAsset},
relay,
};
use gem_client::{Client, ClientExt};
use gem_client::Client;
use primitives::{
Chain, ChainType, TransactionSwapMetadata,
swap::{ApprovalData, ProxyQuote, ProxyQuoteRequest, SwapQuoteData},
Expand Down Expand Up @@ -171,15 +170,6 @@ impl ProxyProvider<RpcClient> {

Self::new_with_path(SwapperProvider::Mayan, "mayan", assets, rpc_provider)
}

pub fn new_relay(rpc_provider: Arc<dyn RpcProvider>) -> Self {
Self::new_with_path(
SwapperProvider::Relay,
"relay",
vec![SwapperChainAsset::All(Chain::Hyperliquid), SwapperChainAsset::All(Chain::Berachain)],
rpc_provider,
)
}
}

#[async_trait]
Expand Down Expand Up @@ -267,14 +257,6 @@ where

Ok(SwapResult { status, metadata })
}
SwapperProvider::Relay => {
let base_url = get_swap_api_url("relay");
let client = RpcClient::new(base_url, self.rpc_provider.clone());
let path = format!("/requests/v2?hash={}", transaction_hash);
let response: relay::model::RelayRequestsResponse = ClientExt::get(&client, &path).await.map_err(SwapperError::from)?;
let request = response.requests.first().ok_or(SwapperError::InvalidRoute)?;
Ok(relay::map_swap_result(request))
}
_ => {
if self.provider.mode == SwapperProviderMode::OnChain {
Ok(SwapResult {
Expand All @@ -290,12 +272,6 @@ where

async fn get_vault_addresses(&self, _from_timestamp: Option<u64>) -> Result<Vec<String>, SwapperError> {
match self.provider.id {
SwapperProvider::Relay => {
let base_url = get_swap_api_url("relay");
let client = RpcClient::new(base_url, self.rpc_provider.clone());
let chains: relay::model::RelayChainsResponse = ClientExt::get(&client, "/chains").await.map_err(SwapperError::from)?;
Ok(chains.solver_addresses())
}
SwapperProvider::Mayan => {
let static_addresses: BTreeSet<String> = MAYAN_CONTRACTS.iter().map(|s| s.to_string()).collect();
let base_url = get_swap_api_url("mayan/price");
Expand Down Expand Up @@ -361,7 +337,7 @@ mod swap_integration_tests {
alien::reqwest_provider::NativeProvider,
{SwapperMode, SwapperQuoteAsset, asset::SUI_USDC_TOKEN_ID, models::Options},
};
use primitives::{AssetId, TransactionSwapMetadata, swap::SwapStatus};
use primitives::{AssetId, swap::SwapStatus};

#[tokio::test]
async fn test_mayan_provider_fetch_quote() -> Result<(), SwapperError> {
Expand Down
4 changes: 0 additions & 4 deletions crates/swapper/src/proxy/provider_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,3 @@ pub fn new_panora(rpc_provider: Arc<dyn RpcProvider>) -> ProxyProvider<RpcClient
pub fn new_mayan(rpc_provider: Arc<dyn RpcProvider>) -> ProxyProvider<RpcClient> {
ProxyProvider::new_mayan(rpc_provider)
}

pub fn new_relay(rpc_provider: Arc<dyn RpcProvider>) -> ProxyProvider<RpcClient> {
ProxyProvider::new_relay(rpc_provider)
}
96 changes: 94 additions & 2 deletions crates/swapper/src/relay/asset.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
use std::sync::LazyLock;

use gem_evm::address::ethereum_address_checksum;
use gem_solana::{SYSTEM_PROGRAM_ID, WSOL_TOKEN_ADDRESS};
use primitives::{AssetId, Chain, ChainType};
use primitives::{
AssetId, Chain, ChainType,
asset_constants::{
USDC_ARB_ASSET_ID, USDC_HYPEREVM_ASSET_ID, USDC_OP_ASSET_ID, USDC_POLYGON_ASSET_ID, USDT_ARB_ASSET_ID, USDT_HYPEREVM_ASSET_ID, USDT_LINEA_ASSET_ID, USDT_OP_ASSET_ID,
USDT_POLYGON_ASSET_ID, USDT_ZKSYNC_ASSET_ID,
},
};

use crate::asset::EVM_ZERO_ADDRESS;
use super::chain::RelayChain;
use crate::{SwapperChainAsset, SwapperError, asset::*};

fn is_native_currency(chain: Chain, currency: &str) -> bool {
match chain {
Expand All @@ -24,3 +33,86 @@ pub fn map_currency_to_asset_id(chain: Chain, currency: &str) -> AssetId {
}
AssetId::from_token(chain, currency)
}

pub static SUPPORTED_CHAINS: LazyLock<Vec<SwapperChainAsset>> = LazyLock::new(|| {
vec![
SwapperChainAsset::Assets(
Chain::Ethereum,
vec![
AssetId::from_chain(Chain::Ethereum),
AssetId::from_token(Chain::Ethereum, ETHEREUM_USDC_TOKEN_ID),
AssetId::from_token(Chain::Ethereum, ETHEREUM_USDT_TOKEN_ID),
],
),
SwapperChainAsset::Assets(
Chain::SmartChain,
vec![
AssetId::from_chain(Chain::SmartChain),
AssetId::from_token(Chain::SmartChain, SMARTCHAIN_USDC_TOKEN_ID),
AssetId::from_token(Chain::SmartChain, SMARTCHAIN_USDT_TOKEN_ID),
],
),
SwapperChainAsset::Assets(Chain::Base, vec![AssetId::from_chain(Chain::Base), AssetId::from_token(Chain::Base, BASE_USDC_TOKEN_ID)]),
SwapperChainAsset::Assets(
Chain::Arbitrum,
vec![AssetId::from_chain(Chain::Arbitrum), USDC_ARB_ASSET_ID.into(), USDT_ARB_ASSET_ID.into()],
),
SwapperChainAsset::Assets(
Chain::Optimism,
vec![AssetId::from_chain(Chain::Optimism), USDC_OP_ASSET_ID.into(), USDT_OP_ASSET_ID.into()],
),
SwapperChainAsset::Assets(
Chain::Polygon,
vec![AssetId::from_chain(Chain::Polygon), USDC_POLYGON_ASSET_ID.into(), USDT_POLYGON_ASSET_ID.into()],
),
SwapperChainAsset::Assets(
Chain::AvalancheC,
vec![
AssetId::from_chain(Chain::AvalancheC),
AssetId::from_token(Chain::AvalancheC, AVALANCHE_USDC_TOKEN_ID),
AssetId::from_token(Chain::AvalancheC, AVALANCHE_USDT_TOKEN_ID),
],
),
SwapperChainAsset::Assets(Chain::Linea, vec![AssetId::from_chain(Chain::Linea), USDT_LINEA_ASSET_ID.into()]),
SwapperChainAsset::Assets(Chain::ZkSync, vec![AssetId::from_chain(Chain::ZkSync), USDT_ZKSYNC_ASSET_ID.into()]),
SwapperChainAsset::Assets(
Chain::Hyperliquid,
vec![AssetId::from_chain(Chain::Hyperliquid), USDC_HYPEREVM_ASSET_ID.into(), USDT_HYPEREVM_ASSET_ID.into()],
),
SwapperChainAsset::Assets(Chain::Berachain, vec![]),
SwapperChainAsset::Assets(Chain::Abstract, vec![]),
SwapperChainAsset::Assets(Chain::Mantle, vec![]),
SwapperChainAsset::Assets(Chain::Celo, vec![]),
SwapperChainAsset::Assets(Chain::Stable, vec![]),
]
});

pub fn asset_to_currency(asset_id: &AssetId, relay_chain: &RelayChain) -> Result<String, SwapperError> {
if !relay_chain.is_evm() {
return Err(SwapperError::NotSupportedChain);
}
if asset_id.is_native() {
Ok(EVM_ZERO_ADDRESS.to_string())
} else {
asset_id.token_id.clone().ok_or(SwapperError::NotSupportedAsset)
}
}

#[cfg(test)]
mod tests {
use super::*;
use primitives::Chain;

#[test]
fn test_evm_native_asset() {
let result = asset_to_currency(&AssetId::from_chain(Chain::Ethereum), &RelayChain::from_chain(&Chain::Ethereum).unwrap()).unwrap();
assert_eq!(result, EVM_ZERO_ADDRESS);
}

#[test]
fn test_evm_token_asset() {
let token_address = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
let result = asset_to_currency(&AssetId::from_token(Chain::Ethereum, token_address), &RelayChain::from_chain(&Chain::Ethereum).unwrap()).unwrap();
assert_eq!(result, token_address);
}
}
44 changes: 40 additions & 4 deletions crates/swapper/src/relay/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,30 @@ pub enum RelayChain {
}

impl RelayChain {
pub fn chain_id(&self) -> u64 {
match self {
Self::Bitcoin => BITCOIN_CHAIN_ID,
Self::Solana => SOLANA_CHAIN_ID,
Self::Evm(evm_chain) => evm_chain.chain_id(),
}
}

pub fn from_chain(chain: &Chain) -> Option<Self> {
match chain {
Chain::Bitcoin => Some(Self::Bitcoin),
Chain::Solana => Some(Self::Solana),
_ => Some(Self::Evm(EVMChain::from_chain(*chain)?)),
}
}

pub fn to_chain(&self) -> Chain {
match self {
Self::Bitcoin => Chain::Bitcoin,
Self::Solana => Chain::Solana,
Self::Evm(evm_chain) => evm_chain.to_chain(),
}
}

pub fn from_chain_id(chain_id: u64) -> Option<Self> {
match chain_id {
BITCOIN_CHAIN_ID => Some(Self::Bitcoin),
Expand All @@ -21,11 +45,23 @@ impl RelayChain {
}
}

pub fn to_chain(&self) -> Chain {
pub fn is_evm(&self) -> bool {
match self {
Self::Bitcoin => Chain::Bitcoin,
Self::Solana => Chain::Solana,
Self::Evm(evm_chain) => evm_chain.to_chain(),
Self::Evm(_) => true,
Self::Bitcoin | Self::Solana => false,
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_from_chain() {
assert_eq!(RelayChain::from_chain(&Chain::Ethereum).unwrap().chain_id(), EVMChain::Ethereum.chain_id());
assert_eq!(RelayChain::from_chain(&Chain::SmartChain).unwrap().chain_id(), EVMChain::SmartChain.chain_id());
assert_eq!(RelayChain::from_chain(&Chain::Solana).unwrap().chain_id(), SOLANA_CHAIN_ID);
assert!(RelayChain::from_chain(&Chain::Cosmos).is_none());
}
}
37 changes: 37 additions & 0 deletions crates/swapper/src/relay/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use std::{collections::HashMap, fmt::Debug};

use gem_client::{CONTENT_TYPE, Client, ClientExt, ContentType};

use super::model::{RelayChainsResponse, RelayQuoteRequest, RelayQuoteResponse, RelayRequestsResponse};
use crate::SwapperError;

#[derive(Clone, Debug)]
pub struct RelayClient<C>
where
C: Client + Clone + Send + Sync + Debug + 'static,
{
client: C,
}

impl<C> RelayClient<C>
where
C: Client + Clone + Send + Sync + Debug + 'static,
{
pub fn new(client: C) -> Self {
Self { client }
}

pub async fn get_quote(&self, request: RelayQuoteRequest) -> Result<RelayQuoteResponse, SwapperError> {
let headers = HashMap::from([(CONTENT_TYPE.to_string(), ContentType::ApplicationJson.as_str().into())]);
self.client.post_with("/quote/v2", &request, headers).await.map_err(SwapperError::from)
}

pub async fn get_request(&self, transaction_hash: &str) -> Result<RelayRequestsResponse, SwapperError> {
let path = format!("/requests/v2?hash={}", transaction_hash);
self.client.get(&path).await.map_err(SwapperError::from)
}

pub async fn get_chains(&self) -> Result<RelayChainsResponse, SwapperError> {
self.client.get("/chains").await.map_err(SwapperError::from)
}
}
Loading
Loading