diff --git a/crates/bindings/src/lib.rs b/crates/bindings/src/lib.rs index b3d232009c..1298ab67e3 100644 --- a/crates/bindings/src/lib.rs +++ b/crates/bindings/src/lib.rs @@ -18,7 +18,7 @@ sol!( ); sol!( - #![sol(all_derives = true)] + #![sol(all_derives = true, rpc)] ERC20, "../../out/ERC20.sol/ERC20.json" ); diff --git a/crates/bindings/src/provider.rs b/crates/bindings/src/provider.rs index 3f6d593337..3992ff1c77 100644 --- a/crates/bindings/src/provider.rs +++ b/crates/bindings/src/provider.rs @@ -22,10 +22,17 @@ pub enum ReadProviderError { } pub fn mk_read_provider(rpcs: &[Url]) -> Result { - let size = rpcs.len(); + if rpcs.is_empty() { + return Err(ReadProviderError::NoRpcs); + } + // Use one active transport per request: alloy's FallbackLayer health-routes + // to the best-scored transport and falls back to others on error/429. With + // `active_transport_count = rpcs.len()` it would dispatch every request to + // ALL transports in parallel (request amplification), defeating the purpose + // of providing multiple RPCs for load sharing. let fallback_layer = FallbackLayer::default() - .with_active_transport_count(NonZeroUsize::new(size).ok_or(ReadProviderError::NoRpcs)?); + .with_active_transport_count(NonZeroUsize::new(1).expect("1 is non-zero")); let transports = rpcs .iter() diff --git a/crates/common/src/deposit.rs b/crates/common/src/deposit.rs index abd395f938..9caa74d86e 100644 --- a/crates/common/src/deposit.rs +++ b/crates/common/src/deposit.rs @@ -96,7 +96,7 @@ impl DepositArgs { if !current_allowance_float.eq(self.amount)? { let approve_call = approveCall { spender: transaction_args.orderbook_address, - amount: self.amount.to_fixed_decimal(self.decimals)?, + value: self.amount.to_fixed_decimal(self.decimals)?, }; let params = transaction_args.try_into_write_contract_parameters(approve_call, self.token)?; @@ -232,7 +232,7 @@ mod tests { }; let approve_call = approveCall { spender: Address::ZERO, - amount: U256::from(100), + value: U256::from(100), }; let params = args .try_into_write_contract_parameters(approve_call.clone(), Address::ZERO) diff --git a/crates/common/src/erc20.rs b/crates/common/src/erc20.rs index bf32ca8aa6..65bbeea718 100644 --- a/crates/common/src/erc20.rs +++ b/crates/common/src/erc20.rs @@ -5,7 +5,7 @@ use alloy_ethers_typecast::ReadContractParametersBuilderError; use rain_error_decoding::{AbiDecodeFailedErrors, AbiDecodedErrorType}; use rain_orderbook_app_settings::token::TokenCfg; use rain_orderbook_bindings::provider::{mk_read_provider, ReadProvider, ReadProviderError}; -use rain_orderbook_bindings::IERC20::IERC20Instance; +use rain_orderbook_bindings::ERC20::ERC20Instance; use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::HashMap; @@ -87,9 +87,9 @@ impl ERC20 { Self { rpcs, address } } - fn get_instance(&self) -> Result, Error> { + fn get_instance(&self) -> Result, Error> { let provider = mk_read_provider(&self.rpcs)?; - let erc20 = IERC20Instance::new(self.address, provider); + let erc20 = ERC20Instance::new(self.address, provider); Ok(erc20) } diff --git a/crates/common/src/fuzz/impls.rs b/crates/common/src/fuzz/impls.rs index 7aca970328..54c1f93615 100644 --- a/crates/common/src/fuzz/impls.rs +++ b/crates/common/src/fuzz/impls.rs @@ -28,7 +28,7 @@ use rain_orderbook_app_settings::{ order::OrderIOCfg, yaml::{dotrain::DotrainYaml, YamlError, YamlParsable}, }; -use rain_orderbook_bindings::IERC20; +use rain_orderbook_bindings::ERC20; use std::collections::HashMap; use std::sync::Arc; use thiserror::Error; @@ -417,7 +417,7 @@ impl FuzzRunner { .alloy_call( deployer.address, input_token.address, - IERC20::symbolCall {}, + ERC20::symbolCall {}, false, ) .await?; @@ -426,7 +426,7 @@ impl FuzzRunner { .alloy_call( deployer.address, output_token.address, - IERC20::symbolCall {}, + ERC20::symbolCall {}, false, ) .await?; diff --git a/crates/common/src/local_db/executor.rs b/crates/common/src/local_db/executor.rs index 182e4164e1..aeb8d29d6e 100644 --- a/crates/common/src/local_db/executor.rs +++ b/crates/common/src/local_db/executor.rs @@ -56,7 +56,7 @@ fn open_connection(db_path: &Path) -> Result { .map_err(|e| LocalDbQueryError::database(format!("Failed to open database: {e}")))?; conn.pragma_update(None, "journal_mode", "wal") .map_err(|e| LocalDbQueryError::database(format!("Failed to set WAL journal mode: {e}")))?; - conn.busy_timeout(Duration::from_millis(500)) + conn.busy_timeout(Duration::from_secs(10)) .map_err(|e| LocalDbQueryError::database(format!("Failed to set busy_timeout: {e}")))?; functions::register_all(&conn).map_err(|e| { LocalDbQueryError::database(format!("Failed to register sqlite functions: {e}")) diff --git a/crates/common/src/raindex_client/order_quotes.rs b/crates/common/src/raindex_client/order_quotes.rs index 9c4ae6d891..85814c5e48 100644 --- a/crates/common/src/raindex_client/order_quotes.rs +++ b/crates/common/src/raindex_client/order_quotes.rs @@ -2,7 +2,7 @@ use super::*; use crate::raindex_client::orders::RaindexOrder; use crate::raindex_client::orders_list::RaindexOrders; use rain_math_float::Float; -use rain_orderbook_bindings::IOrderBookV6::OrderV4; +use rain_orderbook_bindings::IOrderBookV6::{OrderV4, SignedContextV1}; use rain_orderbook_quote::{get_order_quotes, BatchOrderQuotesResponse, OrderQuoteValue, Pair}; use rain_orderbook_subgraph_client::utils::float::{F0, F1}; use std::ops::{Div, Mul}; @@ -127,6 +127,7 @@ impl RaindexOrder { block_number, rpcs.iter().map(|s| s.to_string()).collect(), chunk_size.map(|v| v as usize), + None, ) .await?; @@ -184,7 +185,7 @@ impl RaindexClient { )] chunk_size: Option, ) -> Result>, RaindexError> { - get_order_quotes_batch(orders.inner(), block_number, chunk_size).await + get_order_quotes_batch(orders.inner(), block_number, chunk_size, None).await } } @@ -192,6 +193,7 @@ pub async fn get_order_quotes_batch( orders: &[RaindexOrder], block_number: Option, chunk_size: Option, + signed_contexts: Option<&[Vec]>, ) -> Result>, RaindexError> { if orders.is_empty() { return Ok(vec![]); @@ -240,6 +242,7 @@ pub async fn get_order_quotes_batch( block_number, rpcs, chunk_size.map(|v| v as usize), + signed_contexts, ) .await?; @@ -446,7 +449,7 @@ mod tests { #[tokio::test] async fn test_get_order_quotes_batch_empty() { - let result = get_order_quotes_batch(&[], None, None).await; + let result = get_order_quotes_batch(&[], None, None, None).await; assert!(result.is_ok()); assert!(result.unwrap().is_empty()); } @@ -583,7 +586,7 @@ mod tests { .await .unwrap(); - let result = get_order_quotes_batch(&[order], None, None).await.unwrap(); + let result = get_order_quotes_batch(&[order], None, None, None).await.unwrap(); assert_eq!(result.len(), 1); assert_eq!(result[0].len(), 1); @@ -677,7 +680,7 @@ mod tests { .unwrap(); let orders = vec![order.clone(), order]; - let result = get_order_quotes_batch(&orders, None, None).await.unwrap(); + let result = get_order_quotes_batch(&orders, None, None, None).await.unwrap(); assert_eq!(result.len(), 2); assert_eq!(result[0].len(), 1); diff --git a/crates/common/src/raindex_client/take_orders/result.rs b/crates/common/src/raindex_client/take_orders/result.rs index 04b083f3b2..7b4724b87f 100644 --- a/crates/common/src/raindex_client/take_orders/result.rs +++ b/crates/common/src/raindex_client/take_orders/result.rs @@ -672,7 +672,7 @@ mod tests { .expect("Should decode approval calldata"); let expected_truncated = U256::from(22_446_685u64); assert_eq!( - decoded.amount, expected_truncated, + decoded.value, expected_truncated, "Approved amount should be 22.446685 truncated to 6 decimals = 22446685" ); diff --git a/crates/common/src/raindex_client/vaults.rs b/crates/common/src/raindex_client/vaults.rs index d96da88958..ce369901e8 100644 --- a/crates/common/src/raindex_client/vaults.rs +++ b/crates/common/src/raindex_client/vaults.rs @@ -517,7 +517,7 @@ impl RaindexVault { let calldata = approveCall { spender: transaction_args.orderbook_address, - amount: amount.to_fixed_decimal(self.token.decimals)?, + value: amount.to_fixed_decimal(self.token.decimals)?, } .abi_encode(); @@ -2154,7 +2154,7 @@ mod tests { use alloy::primitives::{address, b256}; use alloy::sol_types::SolCall; use httpmock::MockServer; - use rain_orderbook_bindings::IERC20::decimalsCall; + use rain_orderbook_bindings::ERC20::decimalsCall; use rain_orderbook_bindings::{ IOrderBookV6::{deposit4Call, withdraw4Call}, IERC20::approveCall, @@ -3160,7 +3160,7 @@ mod tests { Bytes::copy_from_slice( &approveCall { spender: Address::from_str(CHAIN_ID_1_ORDERBOOK_ADDRESS).unwrap(), - amount: U256::from(600000000000000000000u128), + value: U256::from(600000000000000000000u128), } .abi_encode(), ) diff --git a/crates/common/src/take_orders/candidates.rs b/crates/common/src/take_orders/candidates.rs index 62796bc6d0..ccff27f569 100644 --- a/crates/common/src/take_orders/candidates.rs +++ b/crates/common/src/take_orders/candidates.rs @@ -74,7 +74,7 @@ pub async fn build_take_order_candidates_for_pair( block_number: Option, chunk_size: Option, ) -> Result, RaindexError> { - let all_quotes = get_order_quotes_batch(orders, block_number, chunk_size).await?; + let all_quotes = get_order_quotes_batch(orders, block_number, chunk_size, None).await?; orders .iter() diff --git a/crates/common/src/take_orders/preflight.rs b/crates/common/src/take_orders/preflight.rs index c824d6373e..03ac03bcc0 100644 --- a/crates/common/src/take_orders/preflight.rs +++ b/crates/common/src/take_orders/preflight.rs @@ -140,7 +140,10 @@ pub async fn check_taker_balance_and_allowance( } pub fn build_approval_calldata(spender: Address, amount: U256) -> Bytes { - let call = approveCall { spender, amount }; + let call = approveCall { + spender, + value: amount, + }; Bytes::from(call.abi_encode()) } @@ -286,7 +289,7 @@ mod tests { assert!(decoded.is_ok()); let decoded = decoded.unwrap(); assert_eq!(decoded.spender, spender); - assert_eq!(decoded.amount, amount); + assert_eq!(decoded.value, amount); } } diff --git a/crates/js_api/src/gui/order_operations.rs b/crates/js_api/src/gui/order_operations.rs index 3f92008fa3..0452e32137 100644 --- a/crates/js_api/src/gui/order_operations.rs +++ b/crates/js_api/src/gui/order_operations.rs @@ -357,7 +357,7 @@ impl DotrainOrderGui { if !allowance_float.eq(*deposit_amount)? { let calldata = approveCall { spender: tx_args.orderbook_address, - amount: deposit_amount.to_fixed_decimal(decimals)?, + value: deposit_amount.to_fixed_decimal(decimals)?, } .abi_encode(); diff --git a/crates/quote/src/order_quotes.rs b/crates/quote/src/order_quotes.rs index 8aa70534f4..92a6d68245 100644 --- a/crates/quote/src/order_quotes.rs +++ b/crates/quote/src/order_quotes.rs @@ -5,7 +5,7 @@ use crate::{ }; use alloy::primitives::{Address, U256}; use alloy_ethers_typecast::ReadableClient; -use rain_orderbook_bindings::IOrderBookV6::{OrderV4, QuoteV2}; +use rain_orderbook_bindings::IOrderBookV6::{OrderV4, QuoteV2, SignedContextV1}; use rain_orderbook_subgraph_client::types::common::SgOrder; use serde::{Deserialize, Serialize}; use std::str::FromStr; @@ -43,6 +43,7 @@ pub async fn get_order_quotes( block_number: Option, rpcs: Vec, chunk_size: Option, + signed_contexts: Option<&[Vec]>, ) -> Result, Error> { let req_block_number = match block_number { Some(block) => block, @@ -56,9 +57,13 @@ pub async fn get_order_quotes( let mut all_pairs: Vec = Vec::new(); let mut all_quote_targets: Vec = Vec::new(); - for order in &orders { + for (order_idx, order) in orders.iter().enumerate() { let order_struct: OrderV4 = order.clone().try_into()?; let orderbook = Address::from_str(&order.orderbook.id.0)?; + let order_signed_context = signed_contexts + .and_then(|ctxs| ctxs.get(order_idx)) + .cloned() + .unwrap_or_default(); for (input_index, input) in order_struct.validInputs.iter().enumerate() { for (output_index, output) in order_struct.validOutputs.iter().enumerate() { @@ -103,7 +108,7 @@ pub async fn get_order_quotes( order: order_struct.clone(), inputIOIndex: U256::from(input_index), outputIOIndex: U256::from(output_index), - signedContext: vec![], + signedContext: order_signed_context.clone(), }, }); } @@ -389,7 +394,7 @@ amount price: context<3 0>() context<4 0>(); let order = create_sg_order(&setup, order, inputs, outputs); - let result = get_order_quotes(vec![order], None, vec![setup.local_evm.url()], None) + let result = get_order_quotes(vec![order], None, vec![setup.local_evm.url()], None, None) .await .unwrap(); @@ -466,7 +471,7 @@ amount price: context<3 0>() context<4 0>(); let mut invalid_order = create_sg_order(&setup, order.clone(), vec![], vec![]); invalid_order.orderbook.id = SgBytes("invalid_address".to_string()); - let err = get_order_quotes(vec![invalid_order], None, vec![setup.local_evm.url()], None) + let err = get_order_quotes(vec![invalid_order], None, vec![setup.local_evm.url()], None, None) .await .unwrap_err(); @@ -475,7 +480,7 @@ amount price: context<3 0>() context<4 0>(); // Test invalid order bytes let invalid_order = create_sg_order(&setup, B256::random().to_string(), vec![], vec![]); - let err = get_order_quotes(vec![invalid_order], None, vec![setup.local_evm.url()], None) + let err = get_order_quotes(vec![invalid_order], None, vec![setup.local_evm.url()], None, None) .await .unwrap_err(); @@ -492,6 +497,7 @@ amount price: context<3 0>() context<4 0>(); None, vec!["invalid_rpc_url".to_string()], None, + None, ) .await .unwrap_err();