1use std::pin::Pin;
17
18use alloy_primitives::{Address, B256};
19use alloy_signer_local::PrivateKeySigner;
20use cow_chains::SupportedChainId;
21use cow_errors::CowError;
22use cow_orderbook::types::Order;
23
24use super::types::{
25 BridgeProviderInfo, BridgeStatusResult, BridgingDepositParams, BuyTokensParams,
26 GetProviderBuyTokens, IntermediateTokenInfo, QuoteBridgeRequest, QuoteBridgeResponse,
27};
28
29#[derive(Debug, Clone)]
35pub struct BridgingParamsResult {
36 pub params: BridgingDepositParams,
38 pub status: BridgeStatusResult,
40}
41
42#[derive(Debug, Clone)]
48pub struct BridgeNetworkInfo {
49 pub chain_id: u64,
51 pub name: String,
53 pub logo_url: Option<String>,
55}
56
57macro_rules! provider_future {
64 ($name:ident, $output:ty) => {
65 #[cfg(not(target_arch = "wasm32"))]
66 #[doc = concat!("Future returned by `BridgeProvider::", stringify!($name), "`.")]
67 pub type $name<'a> =
68 Pin<Box<dyn std::future::Future<Output = Result<$output, CowError>> + Send + 'a>>;
69
70 #[cfg(target_arch = "wasm32")]
71 #[doc = concat!("Future returned by `BridgeProvider::", stringify!($name), "`.")]
72 pub type $name<'a> =
73 Pin<Box<dyn std::future::Future<Output = Result<$output, CowError>> + 'a>>;
74 };
75}
76
77provider_future!(QuoteFuture, QuoteBridgeResponse);
78provider_future!(NetworksFuture, Vec<BridgeNetworkInfo>);
79provider_future!(BuyTokensFuture, GetProviderBuyTokens);
80provider_future!(IntermediateTokensFuture, Vec<IntermediateTokenInfo>);
81provider_future!(BridgingParamsFuture, Option<BridgingParamsResult>);
82provider_future!(BridgeStatusFuture, BridgeStatusResult);
83provider_future!(UnsignedCallFuture, cow_chains::EvmCall);
84provider_future!(SignedHookFuture, crate::types::BridgeHook);
85provider_future!(ReceiverOverrideFuture, String);
86provider_future!(GasEstimationFuture, u64);
87
88#[cfg(not(target_arch = "wasm32"))]
99pub trait MaybeSendSync: Send + Sync {}
100#[cfg(not(target_arch = "wasm32"))]
101impl<T: ?Sized + Send + Sync> MaybeSendSync for T {}
102
103#[cfg(target_arch = "wasm32")]
106pub trait MaybeSendSync {}
107#[cfg(target_arch = "wasm32")]
108impl<T: ?Sized> MaybeSendSync for T {}
109
110pub trait BridgeProvider: MaybeSendSync {
127 fn info(&self) -> &BridgeProviderInfo;
131
132 fn name(&self) -> &str {
136 &self.info().name
137 }
138
139 fn supports_route(&self, sell_chain: u64, buy_chain: u64) -> bool;
146
147 fn get_networks<'a>(&'a self) -> NetworksFuture<'a>;
151
152 fn get_buy_tokens<'a>(&'a self, params: BuyTokensParams) -> BuyTokensFuture<'a>;
156
157 fn get_intermediate_tokens<'a>(
163 &'a self,
164 request: &'a QuoteBridgeRequest,
165 ) -> IntermediateTokensFuture<'a>;
166
167 fn get_quote<'a>(&'a self, req: &'a QuoteBridgeRequest) -> QuoteFuture<'a>;
173
174 fn get_bridging_params<'a>(
190 &'a self,
191 chain_id: u64,
192 order: &'a Order,
193 tx_hash: B256,
194 settlement_override: Option<Address>,
195 ) -> BridgingParamsFuture<'a>;
196
197 fn get_explorer_url(&self, bridging_id: &str) -> String;
201
202 fn get_status<'a>(
207 &'a self,
208 bridging_id: &'a str,
209 origin_chain_id: u64,
210 ) -> BridgeStatusFuture<'a>;
211
212 fn as_hook_bridge_provider(&self) -> Option<&dyn HookBridgeProvider> {
228 None
229 }
230
231 fn as_receiver_account_bridge_provider(&self) -> Option<&dyn ReceiverAccountBridgeProvider> {
241 None
242 }
243}
244
245pub trait HookBridgeProvider: BridgeProvider {
263 fn get_unsigned_bridge_call<'a>(
269 &'a self,
270 request: &'a QuoteBridgeRequest,
271 quote: &'a QuoteBridgeResponse,
272 ) -> UnsignedCallFuture<'a>;
273
274 fn get_gas_limit_estimation_for_hook<'a>(
286 &'a self,
287 proxy_deployed: bool,
288 extra_gas: Option<u64>,
289 extra_gas_proxy_creation: Option<u64>,
290 ) -> GasEstimationFuture<'a> {
291 let gas = crate::utils::get_gas_limit_estimation_for_hook(
292 proxy_deployed,
293 extra_gas,
294 extra_gas_proxy_creation,
295 );
296 Box::pin(async move { Ok(gas) })
297 }
298
299 #[allow(clippy::too_many_arguments, reason = "1:1 mirror of the TS signature")]
305 fn get_signed_hook<'a>(
306 &'a self,
307 chain_id: SupportedChainId,
308 unsigned_call: &'a cow_chains::EvmCall,
309 bridge_hook_nonce: &'a str,
310 deadline: u64,
311 hook_gas_limit: u64,
312 signer: &'a PrivateKeySigner,
313 ) -> SignedHookFuture<'a>;
314}
315
316pub trait ReceiverAccountBridgeProvider: BridgeProvider {
323 fn get_bridge_receiver_override<'a>(
329 &'a self,
330 quote_request: &'a QuoteBridgeRequest,
331 quote_result: &'a QuoteBridgeResponse,
332 ) -> ReceiverOverrideFuture<'a>;
333}
334
335#[must_use]
344pub fn is_hook_bridge_provider<P: BridgeProvider + ?Sized>(provider: &P) -> bool {
345 provider.info().is_hook_bridge_provider()
346}
347
348#[must_use]
353pub fn is_receiver_account_bridge_provider<P: BridgeProvider + ?Sized>(provider: &P) -> bool {
354 provider.info().is_receiver_account_bridge_provider()
355}
356
357#[cfg(all(test, not(target_arch = "wasm32")))]
358#[allow(clippy::tests_outside_test_module, reason = "inner module + cfg guard for WASM test skip")]
359mod tests {
360 use alloy_primitives::U256;
361
362 use crate::types::{BridgeProviderType, BridgeStatus};
363
364 use super::*;
365
366 #[test]
369 fn bridge_network_info_holds_chain_metadata() {
370 let info = BridgeNetworkInfo {
371 chain_id: 1,
372 name: "Ethereum".into(),
373 logo_url: Some("https://example.com/eth.png".into()),
374 };
375 assert_eq!(info.chain_id, 1);
376 assert_eq!(info.name, "Ethereum");
377 assert!(info.logo_url.is_some());
378 }
379
380 #[test]
381 fn bridge_network_info_logo_optional() {
382 let info = BridgeNetworkInfo { chain_id: 100, name: "Gnosis".into(), logo_url: None };
383 assert!(info.logo_url.is_none());
384 }
385
386 #[test]
389 fn bridging_params_result_bundles_params_and_status() {
390 let params = BridgingDepositParams {
391 input_token_address: Address::ZERO,
392 output_token_address: Address::ZERO,
393 input_amount: U256::from(1000u64),
394 output_amount: None,
395 owner: Address::ZERO,
396 quote_timestamp: None,
397 fill_deadline: None,
398 recipient: Address::ZERO,
399 source_chain_id: 1,
400 destination_chain_id: 10,
401 bridging_id: "abc".into(),
402 };
403 let status = BridgeStatusResult {
404 status: BridgeStatus::InProgress,
405 fill_time_in_seconds: None,
406 deposit_tx_hash: None,
407 fill_tx_hash: None,
408 };
409 let bundle = BridgingParamsResult { params, status };
410 assert_eq!(bundle.params.bridging_id, "abc");
411 assert_eq!(bundle.status.status, BridgeStatus::InProgress);
412 }
413
414 struct FakeProvider {
417 info: BridgeProviderInfo,
418 }
419
420 impl BridgeProvider for FakeProvider {
421 fn info(&self) -> &BridgeProviderInfo {
422 &self.info
423 }
424 fn supports_route(&self, _sell: u64, _buy: u64) -> bool {
425 true
426 }
427 fn get_networks<'a>(&'a self) -> NetworksFuture<'a> {
428 Box::pin(async { Ok(Vec::new()) })
429 }
430 fn get_buy_tokens<'a>(&'a self, _params: BuyTokensParams) -> BuyTokensFuture<'a> {
431 let info = self.info.clone();
432 Box::pin(
433 async move { Ok(GetProviderBuyTokens { provider_info: info, tokens: vec![] }) },
434 )
435 }
436 fn get_intermediate_tokens<'a>(
437 &'a self,
438 _request: &'a QuoteBridgeRequest,
439 ) -> IntermediateTokensFuture<'a> {
440 Box::pin(async { Ok(Vec::new()) })
441 }
442 fn get_quote<'a>(&'a self, _req: &'a QuoteBridgeRequest) -> QuoteFuture<'a> {
443 Box::pin(async {
444 Ok(QuoteBridgeResponse {
445 provider: "fake".into(),
446 sell_amount: U256::ZERO,
447 buy_amount: U256::ZERO,
448 fee_amount: U256::ZERO,
449 estimated_secs: 0,
450 bridge_hook: None,
451 })
452 })
453 }
454 fn get_bridging_params<'a>(
455 &'a self,
456 _chain_id: u64,
457 _order: &'a cow_orderbook::types::Order,
458 _tx_hash: B256,
459 _settlement_override: Option<Address>,
460 ) -> BridgingParamsFuture<'a> {
461 Box::pin(async { Ok(None) })
462 }
463 fn get_explorer_url(&self, bridging_id: &str) -> String {
464 format!("https://example.com/{bridging_id}")
465 }
466 fn get_status<'a>(
467 &'a self,
468 _bridging_id: &'a str,
469 _origin_chain_id: u64,
470 ) -> BridgeStatusFuture<'a> {
471 Box::pin(async {
472 Ok(BridgeStatusResult {
473 status: BridgeStatus::Unknown,
474 fill_time_in_seconds: None,
475 deposit_tx_hash: None,
476 fill_tx_hash: None,
477 })
478 })
479 }
480 }
481
482 fn fake_info() -> BridgeProviderInfo {
483 BridgeProviderInfo {
484 name: "fake-provider".into(),
485 logo_url: "https://example.com/logo.svg".into(),
486 dapp_id: "cow-sdk://bridging/providers/fake".into(),
487 website: "https://example.com".into(),
488 provider_type: BridgeProviderType::HookBridgeProvider,
489 }
490 }
491
492 #[test]
493 fn default_name_delegates_to_info() {
494 let provider = FakeProvider { info: fake_info() };
495 assert_eq!(provider.name(), "fake-provider");
496 assert_eq!(provider.name(), provider.info().name.as_str());
497 }
498
499 #[test]
500 fn default_explorer_url_composes_path() {
501 let provider = FakeProvider { info: fake_info() };
502 assert_eq!(provider.get_explorer_url("deposit-42"), "https://example.com/deposit-42");
503 }
504
505 #[tokio::test]
506 async fn trait_object_dispatch_works_with_dyn() {
507 let provider: Box<dyn BridgeProvider> = Box::new(FakeProvider { info: fake_info() });
508 assert!(provider.supports_route(1, 10));
509 assert_eq!(provider.info().dapp_id, "cow-sdk://bridging/providers/fake");
510 let networks = provider.get_networks().await.unwrap();
511 assert!(networks.is_empty());
512 let tokens = provider
513 .get_buy_tokens(BuyTokensParams {
514 sell_chain_id: 1,
515 buy_chain_id: 100,
516 sell_token_address: None,
517 })
518 .await
519 .unwrap();
520 assert!(tokens.tokens.is_empty());
521 assert_eq!(tokens.provider_info.name, "fake-provider");
522 }
523
524 fn sample_request() -> QuoteBridgeRequest {
525 QuoteBridgeRequest {
526 sell_chain_id: 1,
527 buy_chain_id: 10,
528 sell_token: Address::ZERO,
529 sell_token_decimals: 18,
530 buy_token: Address::ZERO.into(),
531 buy_token_decimals: 18,
532 sell_amount: U256::from(1u64),
533 account: Address::ZERO,
534 owner: None,
535 receiver: None,
536 bridge_recipient: None,
537 slippage_bps: 50,
538 bridge_slippage_bps: None,
539 kind: cow_types::OrderKind::Sell,
540 }
541 }
542
543 #[tokio::test]
544 async fn fake_provider_get_intermediate_tokens_is_callable() {
545 let provider = FakeProvider { info: fake_info() };
546 let tokens = provider.get_intermediate_tokens(&sample_request()).await.unwrap();
547 assert!(tokens.is_empty());
548 }
549
550 #[tokio::test]
551 async fn fake_provider_get_quote_returns_default_fake_response() {
552 let provider = FakeProvider { info: fake_info() };
553 let response = provider.get_quote(&sample_request()).await.unwrap();
554 assert_eq!(response.provider, "fake");
555 assert_eq!(response.sell_amount, U256::ZERO);
556 assert_eq!(response.buy_amount, U256::ZERO);
557 }
558
559 #[tokio::test]
560 async fn fake_provider_get_bridging_params_returns_none() {
561 let provider = FakeProvider { info: fake_info() };
562 let order = cow_orderbook::api::mock_get_order(&format!("0x{}", "aa".repeat(56)));
563 let result = provider.get_bridging_params(1, &order, B256::ZERO, None).await.unwrap();
564 assert!(result.is_none());
565 }
566
567 #[tokio::test]
568 async fn fake_provider_get_status_returns_unknown() {
569 let provider = FakeProvider { info: fake_info() };
570 let result = provider.get_status("deposit", 1).await.unwrap();
571 assert_eq!(result.status, BridgeStatus::Unknown);
572 assert!(result.fill_tx_hash.is_none());
573 assert!(result.deposit_tx_hash.is_none());
574 }
575
576 #[test]
579 fn is_hook_bridge_provider_matches_info_type() {
580 let hook_info = fake_info();
581 let hook_provider = FakeProvider { info: hook_info };
582 assert!(is_hook_bridge_provider(&hook_provider));
583 assert!(!is_receiver_account_bridge_provider(&hook_provider));
584 }
585
586 #[test]
587 fn is_receiver_account_bridge_provider_matches_info_type() {
588 let receiver_info = BridgeProviderInfo {
589 name: "rcv".into(),
590 logo_url: String::new(),
591 dapp_id: "cow-sdk://bridging/providers/rcv".into(),
592 website: String::new(),
593 provider_type: BridgeProviderType::ReceiverAccountBridgeProvider,
594 };
595 let provider = FakeProvider { info: receiver_info };
596 assert!(is_receiver_account_bridge_provider(&provider));
597 assert!(!is_hook_bridge_provider(&provider));
598 }
599
600 #[test]
601 fn type_guards_work_through_trait_object() {
602 let hook_provider: Box<dyn BridgeProvider> = Box::new(FakeProvider { info: fake_info() });
603 assert!(is_hook_bridge_provider(&*hook_provider));
604 assert!(!is_receiver_account_bridge_provider(&*hook_provider));
605 }
606
607 struct FakeHookProvider {
610 info: BridgeProviderInfo,
611 }
612
613 impl BridgeProvider for FakeHookProvider {
614 fn info(&self) -> &BridgeProviderInfo {
615 &self.info
616 }
617 fn supports_route(&self, _s: u64, _b: u64) -> bool {
618 true
619 }
620 fn get_networks<'a>(&'a self) -> NetworksFuture<'a> {
621 Box::pin(async { Ok(Vec::new()) })
622 }
623 fn get_buy_tokens<'a>(&'a self, _p: BuyTokensParams) -> BuyTokensFuture<'a> {
624 let info = self.info.clone();
625 Box::pin(
626 async move { Ok(GetProviderBuyTokens { provider_info: info, tokens: vec![] }) },
627 )
628 }
629 fn get_intermediate_tokens<'a>(
630 &'a self,
631 _req: &'a QuoteBridgeRequest,
632 ) -> IntermediateTokensFuture<'a> {
633 Box::pin(async { Ok(Vec::new()) })
634 }
635 fn get_quote<'a>(&'a self, _req: &'a QuoteBridgeRequest) -> QuoteFuture<'a> {
636 Box::pin(async {
637 Ok(QuoteBridgeResponse {
638 provider: "hook".into(),
639 sell_amount: U256::ZERO,
640 buy_amount: U256::ZERO,
641 fee_amount: U256::ZERO,
642 estimated_secs: 0,
643 bridge_hook: None,
644 })
645 })
646 }
647 fn get_bridging_params<'a>(
648 &'a self,
649 _c: u64,
650 _o: &'a Order,
651 _t: B256,
652 _s: Option<Address>,
653 ) -> BridgingParamsFuture<'a> {
654 Box::pin(async { Ok(None) })
655 }
656 fn get_explorer_url(&self, _id: &str) -> String {
657 String::new()
658 }
659 fn get_status<'a>(&'a self, _id: &'a str, _c: u64) -> BridgeStatusFuture<'a> {
660 Box::pin(async {
661 Ok(BridgeStatusResult {
662 status: BridgeStatus::Unknown,
663 fill_time_in_seconds: None,
664 deposit_tx_hash: None,
665 fill_tx_hash: None,
666 })
667 })
668 }
669 }
670
671 impl HookBridgeProvider for FakeHookProvider {
672 fn get_unsigned_bridge_call<'a>(
673 &'a self,
674 _req: &'a QuoteBridgeRequest,
675 _quote: &'a QuoteBridgeResponse,
676 ) -> UnsignedCallFuture<'a> {
677 Box::pin(async {
678 Ok(cow_chains::EvmCall { to: Address::ZERO, data: vec![], value: U256::ZERO })
679 })
680 }
681 fn get_signed_hook<'a>(
682 &'a self,
683 _chain: SupportedChainId,
684 _call: &'a cow_chains::EvmCall,
685 _nonce: &'a str,
686 _deadline: u64,
687 _gas: u64,
688 _signer: &'a PrivateKeySigner,
689 ) -> SignedHookFuture<'a> {
690 Box::pin(async {
691 Ok(crate::types::BridgeHook {
692 post_hook: cow_types::CowHook {
693 target: String::new(),
694 call_data: String::new(),
695 gas_limit: String::new(),
696 dapp_id: None,
697 },
698 recipient: String::new(),
699 })
700 })
701 }
702 }
703
704 #[tokio::test]
705 async fn hook_provider_default_gas_estimation_deployed() {
706 let provider = FakeHookProvider { info: fake_info() };
707 let gas = provider.get_gas_limit_estimation_for_hook(true, None, None).await.unwrap();
708 assert_eq!(gas, crate::utils::get_gas_limit_estimation_for_hook(true, None, None));
710 }
711
712 #[tokio::test]
713 async fn hook_provider_default_gas_estimation_needs_proxy_creation() {
714 let provider = FakeHookProvider { info: fake_info() };
715 let gas =
716 provider.get_gas_limit_estimation_for_hook(false, None, Some(10_000)).await.unwrap();
717 assert_eq!(gas, crate::utils::get_gas_limit_estimation_for_hook(false, None, Some(10_000)));
718 }
719
720 #[tokio::test]
721 async fn hook_provider_required_methods_callable_through_trait() {
722 let provider = FakeHookProvider { info: fake_info() };
723 let req = sample_request();
724 let quote = provider.get_quote(&req).await.unwrap();
725 let call = provider.get_unsigned_bridge_call(&req, "e).await.unwrap();
726 assert_eq!(call.to, Address::ZERO);
727 assert!(call.data.is_empty());
728
729 let signer: PrivateKeySigner =
730 "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".parse().unwrap();
731 let hook = provider
732 .get_signed_hook(SupportedChainId::Mainnet, &call, "0", 0, 0, &signer)
733 .await
734 .unwrap();
735 assert!(hook.recipient.is_empty());
736 }
737
738 #[tokio::test]
739 async fn fake_hook_provider_bridge_provider_surface_is_callable() {
740 let provider = FakeHookProvider { info: fake_info() };
741 assert!(provider.supports_route(1, 10));
742 assert_eq!(provider.info().dapp_id, "cow-sdk://bridging/providers/fake");
743 assert!(provider.get_networks().await.unwrap().is_empty());
744 let tokens = provider
745 .get_buy_tokens(BuyTokensParams {
746 sell_chain_id: 1,
747 buy_chain_id: 10,
748 sell_token_address: None,
749 })
750 .await
751 .unwrap();
752 assert!(tokens.tokens.is_empty());
753 assert!(provider.get_intermediate_tokens(&sample_request()).await.unwrap().is_empty());
754 let order = cow_orderbook::api::mock_get_order(&format!("0x{}", "aa".repeat(56)));
755 assert!(provider.get_bridging_params(1, &order, B256::ZERO, None).await.unwrap().is_none());
756 assert!(provider.get_explorer_url("x").is_empty());
757 assert_eq!(provider.get_status("x", 1).await.unwrap().status, BridgeStatus::Unknown);
758 }
759
760 struct FakeReceiverProvider {
763 info: BridgeProviderInfo,
764 }
765
766 impl BridgeProvider for FakeReceiverProvider {
767 fn info(&self) -> &BridgeProviderInfo {
768 &self.info
769 }
770 fn supports_route(&self, _s: u64, _b: u64) -> bool {
771 true
772 }
773 fn get_networks<'a>(&'a self) -> NetworksFuture<'a> {
774 Box::pin(async { Ok(Vec::new()) })
775 }
776 fn get_buy_tokens<'a>(&'a self, _p: BuyTokensParams) -> BuyTokensFuture<'a> {
777 let info = self.info.clone();
778 Box::pin(
779 async move { Ok(GetProviderBuyTokens { provider_info: info, tokens: vec![] }) },
780 )
781 }
782 fn get_intermediate_tokens<'a>(
783 &'a self,
784 _req: &'a QuoteBridgeRequest,
785 ) -> IntermediateTokensFuture<'a> {
786 Box::pin(async { Ok(Vec::new()) })
787 }
788 fn get_quote<'a>(&'a self, _req: &'a QuoteBridgeRequest) -> QuoteFuture<'a> {
789 Box::pin(async {
790 Ok(QuoteBridgeResponse {
791 provider: "rcv".into(),
792 sell_amount: U256::ZERO,
793 buy_amount: U256::ZERO,
794 fee_amount: U256::ZERO,
795 estimated_secs: 0,
796 bridge_hook: None,
797 })
798 })
799 }
800 fn get_bridging_params<'a>(
801 &'a self,
802 _c: u64,
803 _o: &'a Order,
804 _t: B256,
805 _s: Option<Address>,
806 ) -> BridgingParamsFuture<'a> {
807 Box::pin(async { Ok(None) })
808 }
809 fn get_explorer_url(&self, _id: &str) -> String {
810 String::new()
811 }
812 fn get_status<'a>(&'a self, _id: &'a str, _c: u64) -> BridgeStatusFuture<'a> {
813 Box::pin(async {
814 Ok(BridgeStatusResult {
815 status: BridgeStatus::Unknown,
816 fill_time_in_seconds: None,
817 deposit_tx_hash: None,
818 fill_tx_hash: None,
819 })
820 })
821 }
822 }
823
824 impl ReceiverAccountBridgeProvider for FakeReceiverProvider {
825 fn get_bridge_receiver_override<'a>(
826 &'a self,
827 _req: &'a QuoteBridgeRequest,
828 _result: &'a QuoteBridgeResponse,
829 ) -> ReceiverOverrideFuture<'a> {
830 Box::pin(async { Ok("near-deposit-address".to_owned()) })
831 }
832 }
833
834 fn fake_receiver_info() -> BridgeProviderInfo {
835 BridgeProviderInfo {
836 name: "rcv".into(),
837 logo_url: String::new(),
838 dapp_id: "cow-sdk://bridging/providers/rcv".into(),
839 website: String::new(),
840 provider_type: BridgeProviderType::ReceiverAccountBridgeProvider,
841 }
842 }
843
844 #[tokio::test]
845 async fn receiver_provider_returns_deposit_address() {
846 let provider = FakeReceiverProvider { info: fake_receiver_info() };
847 let req = sample_request();
848 let quote = provider.get_quote(&req).await.unwrap();
849 let addr = provider.get_bridge_receiver_override(&req, "e).await.unwrap();
850 assert_eq!(addr, "near-deposit-address");
851 }
852
853 #[tokio::test]
854 async fn fake_receiver_provider_bridge_provider_surface_is_callable() {
855 let provider = FakeReceiverProvider { info: fake_receiver_info() };
856 assert!(provider.supports_route(1, 1_000_000_000));
857 assert!(provider.info().is_receiver_account_bridge_provider());
858 assert!(provider.get_networks().await.unwrap().is_empty());
859 let tokens = provider
860 .get_buy_tokens(BuyTokensParams {
861 sell_chain_id: 1,
862 buy_chain_id: 1_000_000_000,
863 sell_token_address: None,
864 })
865 .await
866 .unwrap();
867 assert!(tokens.tokens.is_empty());
868 assert!(provider.get_intermediate_tokens(&sample_request()).await.unwrap().is_empty());
869 let order = cow_orderbook::api::mock_get_order(&format!("0x{}", "bb".repeat(56)));
870 assert!(provider.get_bridging_params(1, &order, B256::ZERO, None).await.unwrap().is_none());
871 assert!(provider.get_explorer_url("dep").is_empty());
872 assert_eq!(provider.get_status("dep", 1).await.unwrap().status, BridgeStatus::Unknown);
873 }
874}