diff --git a/Cargo.lock b/Cargo.lock
index 14af4d5dc6..0d94db7649 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1003,6 +1003,7 @@ dependencies = [
"ethkey",
"futures 0.1.29",
"futures 0.3.28",
+ "futures-ticker",
"futures-util",
"group 0.8.0",
"gstuff",
@@ -1161,6 +1162,7 @@ dependencies = [
"primitive-types",
"rand 0.7.3",
"regex",
+ "rustc-hash",
"ser_error",
"ser_error_derive",
"serde",
diff --git a/mm2src/coins/Cargo.toml b/mm2src/coins/Cargo.toml
index 4ce5597b4f..d957357ecb 100644
--- a/mm2src/coins/Cargo.toml
+++ b/mm2src/coins/Cargo.toml
@@ -49,9 +49,9 @@ ethereum-types = { version = "0.13", default-features = false, features = ["std"
ethkey = { git = "https://github.com/KomodoPlatform/mm2-parity-ethereum.git" }
# Waiting for https://github.com/rust-lang/rust/issues/54725 to use on Stable.
#enum_dispatch = "0.1"
-tokio-tungstenite-wasm = { git = "https://github.com/KomodoPlatform/tokio-tungstenite-wasm", rev = "d20abdb", features = ["rustls-tls-native-roots"]}
futures01 = { version = "0.1", package = "futures" }
futures-util = { version = "0.3", default-features = false, features = ["sink", "std"] }
+futures-ticker = "0.0.3"
# using select macro requires the crate to be named futures, compilation failed with futures03 name
futures = { version = "0.3", package = "futures", features = ["compat", "async-await"] }
group = "0.8.0"
@@ -100,6 +100,7 @@ sha3 = "0.9"
utxo_signer = { path = "utxo_signer" }
# using the same version as cosmrs
tendermint-rpc = { version = "=0.23.7", default-features = false }
+tokio-tungstenite-wasm = { git = "https://github.com/KomodoPlatform/tokio-tungstenite-wasm", rev = "d20abdb", features = ["rustls-tls-native-roots"]}
tiny-bip39 = "0.8.0"
url = { version = "2.2.2", features = ["serde"] }
uuid = { version = "1.2.2", features = ["fast-rng", "serde", "v4"] }
diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs
index 8a16949695..27f1c10c3f 100644
--- a/mm2src/coins/eth.rs
+++ b/mm2src/coins/eth.rs
@@ -21,14 +21,17 @@
// Copyright © 2023 Pampex LTD and TillyHK LTD. All rights reserved.
//
use super::eth::Action::{Call, Create};
+use crate::eth::eth_rpc::ETH_RPC_REQUEST_TIMEOUT;
+use crate::eth::web3_transport::websocket_transport::{WebsocketTransport, WebsocketTransportNode};
use crate::lp_price::get_base_price_in_rel;
use crate::nft::nft_structs::{ContractType, ConvertChain, TransactionNftDetails, WithdrawErc1155, WithdrawErc721};
-use crate::{DexFee, ValidateWatcherSpendInput, WatcherSpendType};
+use crate::{DexFee, RpcCommonOps, ValidateWatcherSpendInput, WatcherSpendType};
use async_trait::async_trait;
use bitcrypto::{dhash160, keccak256, ripemd160, sha256};
use common::custom_futures::repeatable::{Ready, Retry, RetryOnError};
use common::custom_futures::timeout::FutureTimerExt;
use common::executor::{abortable_queue::AbortableQueue, AbortableSystem, AbortedError, Timer};
+use common::executor::{AbortSettings, SpawnAbortable};
use common::log::{debug, error, info, warn};
use common::number_type_casting::SafeTypeCastingNumbers;
use common::{get_utc_timestamp, now_sec, small_rng, DEX_FEE_ADDR_RAW_PUBKEY};
@@ -47,7 +50,8 @@ use ethkey::{sign, verify_address};
use futures::compat::Future01CompatExt;
use futures::future::{join_all, select_ok, try_join_all, Either, FutureExt, TryFutureExt};
use futures01::Future;
-use http::StatusCode;
+use http::{StatusCode, Uri};
+use instant::Instant;
use mm2_core::mm_ctx::{MmArc, MmWeak};
use mm2_err_handle::prelude::*;
use mm2_event_stream::behaviour::{EventBehaviour, EventInitStatus};
@@ -69,10 +73,11 @@ use std::ops::Deref;
use std::str::FromStr;
use std::sync::atomic::{AtomicU64, Ordering as AtomicOrdering};
use std::sync::{Arc, Mutex};
+use std::time::Duration;
use web3::types::{Action as TraceAction, BlockId, BlockNumber, Bytes, CallRequest, FilterBuilder, Log, Trace,
TraceFilterBuilder, Transaction as Web3Transaction, TransactionId, U64};
use web3::{self, Web3};
-use web3_transport::{http_transport::HttpTransportNode, EthFeeHistoryNamespace, Web3Transport};
+use web3_transport::{http_transport::HttpTransportNode, Web3Transport};
cfg_wasm32! {
use crypto::MetamaskArc;
@@ -104,6 +109,7 @@ use super::{coin_conf, lp_coinfind_or_err, AsyncMutex, BalanceError, BalanceFut,
pub use rlp;
mod eth_balance_events;
+mod eth_rpc;
#[cfg(test)] mod eth_tests;
#[cfg(target_arch = "wasm32")] mod eth_wasm_tests;
mod web3_transport;
@@ -426,9 +432,7 @@ pub struct EthCoinImpl {
swap_contract_address: Address,
fallback_swap_contract: Option
,
contract_supports_watchers: bool,
- pub(crate) web3: Web3,
- /// The separate web3 instances kept to get nonce, will replace the web3 completely soon
- web3_instances: Vec,
+ web3_instances: AsyncMutex>,
decimals: u8,
gas_station_url: Option,
gas_station_decimals: u8,
@@ -487,67 +491,6 @@ async fn make_gas_station_request(url: &str) -> GasStationResult {
}
impl EthCoinImpl {
- /// Gets Transfer events from ERC20 smart contract `addr` between `from_block` and `to_block`
- fn erc20_transfer_events(
- &self,
- contract: Address,
- from_addr: Option,
- to_addr: Option,
- from_block: BlockNumber,
- to_block: BlockNumber,
- limit: Option,
- ) -> Box, Error = String> + Send> {
- let contract_event = try_fus!(ERC20_CONTRACT.event("Transfer"));
- let topic0 = Some(vec![contract_event.signature()]);
- let topic1 = from_addr.map(|addr| vec![addr.into()]);
- let topic2 = to_addr.map(|addr| vec![addr.into()]);
- let mut filter = FilterBuilder::default()
- .topics(topic0, topic1, topic2, None)
- .from_block(from_block)
- .to_block(to_block)
- .address(vec![contract]);
-
- if let Some(l) = limit {
- filter = filter.limit(l);
- }
-
- Box::new(
- self.web3
- .eth()
- .logs(filter.build())
- .compat()
- .map_err(|e| ERRL!("{}", e)),
- )
- }
-
- /// Gets ETH traces from ETH node between addresses in `from_block` and `to_block`
- fn eth_traces(
- &self,
- from_addr: Vec,
- to_addr: Vec,
- from_block: BlockNumber,
- to_block: BlockNumber,
- limit: Option,
- ) -> Box, Error = String> + Send> {
- let mut filter = TraceFilterBuilder::default()
- .from_address(from_addr)
- .to_address(to_addr)
- .from_block(from_block)
- .to_block(to_block);
-
- if let Some(l) = limit {
- filter = filter.count(l);
- }
-
- Box::new(
- self.web3
- .trace()
- .filter(filter.build())
- .compat()
- .map_err(|e| ERRL!("{}", e)),
- )
- }
-
#[cfg(not(target_arch = "wasm32"))]
fn eth_traces_path(&self, ctx: &MmArc) -> PathBuf {
ctx.dbdir()
@@ -644,24 +587,6 @@ impl EthCoinImpl {
sha256(&input).to_vec()
}
- /// Gets `SenderRefunded` events from etomic swap smart contract since `from_block`
- fn refund_events(
- &self,
- swap_contract_address: Address,
- from_block: u64,
- to_block: u64,
- ) -> Box, Error = String> + Send> {
- let contract_event = try_fus!(SWAP_CONTRACT.event("SenderRefunded"));
- let filter = FilterBuilder::default()
- .topics(Some(vec![contract_event.signature()]), None, None, None)
- .from_block(BlockNumber::Number(from_block.into()))
- .to_block(BlockNumber::Number(to_block.into()))
- .address(vec![swap_contract_address])
- .build();
-
- Box::new(self.web3.eth().logs(filter).compat().map_err(|e| ERRL!("{}", e)))
- }
-
/// Try to parse address from string.
pub fn address_from_str(&self, address: &str) -> Result {
Ok(try_s!(valid_addr_from_str(address)))
@@ -698,8 +623,6 @@ async fn get_raw_transaction_impl(coin: EthCoin, req: RawTransactionRequest) ->
async fn get_tx_hex_by_hash_impl(coin: EthCoin, tx_hash: H256) -> RawTransactionResult {
let web3_tx = coin
- .web3
- .eth()
.transaction(TransactionId::Hash(tx_hash))
.await?
.or_mm_err(|| RawTransactionError::HashNotExist(tx_hash.to_string()))?;
@@ -780,7 +703,9 @@ async fn withdraw_impl(coin: EthCoin, req: WithdrawRequest) -> WithdrawResult {
EthPrivKeyPolicy::Iguana(_) | EthPrivKeyPolicy::HDWallet { .. } => {
// Todo: nonce_lock is still global for all addresses but this needs to be per address
let _nonce_lock = coin.nonce_lock.lock().await;
- let (nonce, _) = get_addr_nonce(my_address, coin.web3_instances.clone())
+ let (nonce, _) = coin
+ .clone()
+ .get_addr_nonce(my_address)
.compat()
.timeout_secs(30.)
.await?
@@ -829,7 +754,7 @@ async fn withdraw_impl(coin: EthCoin, req: WithdrawRequest) -> WithdrawResult {
// Please note that this method may take a long time
// due to `wallet_switchEthereumChain` and `eth_sendTransaction` requests.
- let tx_hash = coin.web3.eth().send_transaction(tx_to_send).await?;
+ let tx_hash = coin.send_transaction(tx_to_send).await?;
let signed_tx = coin
.wait_for_tx_appears_on_rpc(tx_hash, wait_rpc_timeout, check_every)
@@ -934,7 +859,9 @@ pub async fn withdraw_erc1155(ctx: MmArc, withdraw_type: WithdrawErc1155) -> Wit
)
.await?;
let _nonce_lock = eth_coin.nonce_lock.lock().await;
- let (nonce, _) = get_addr_nonce(eth_coin.my_address, eth_coin.web3_instances.clone())
+ let (nonce, _) = eth_coin
+ .clone()
+ .get_addr_nonce(eth_coin.my_address)
.compat()
.timeout_secs(30.)
.await?
@@ -1018,7 +945,9 @@ pub async fn withdraw_erc721(ctx: MmArc, withdraw_type: WithdrawErc721) -> Withd
)
.await?;
let _nonce_lock = eth_coin.nonce_lock.lock().await;
- let (nonce, _) = get_addr_nonce(my_address, eth_coin.web3_instances.clone())
+ let (nonce, _) = eth_coin
+ .clone()
+ .get_addr_nonce(my_address)
.compat()
.timeout_secs(30.)
.await?
@@ -1190,8 +1119,6 @@ impl SwapOps for EthCoin {
Some(event) => {
let transaction = try_s!(
selfi
- .web3
- .eth()
.transaction(TransactionId::Hash(event.transaction_hash.unwrap()))
.await
);
@@ -1748,7 +1675,7 @@ impl WatcherOps for EthCoin {
let fallback_swap_contract = self.fallback_swap_contract;
let fut = async move {
- let tx_from_rpc = selfi.web3.eth().transaction(TransactionId::Hash(tx.hash)).await?;
+ let tx_from_rpc = selfi.transaction(TransactionId::Hash(tx.hash)).await?;
let tx_from_rpc = tx_from_rpc.as_ref().ok_or_else(|| {
ValidatePaymentError::TxDoesNotExist(format!("Didn't find provided tx {:?} on ETH node", tx))
@@ -2156,25 +2083,34 @@ impl MarketCoinOps for EthCoin {
tx = &tx[2..];
}
let bytes = try_fus!(hex::decode(tx));
- Box::new(
- self.web3
- .eth()
+
+ let coin = self.clone();
+
+ let fut = async move {
+ let result = coin
.send_raw_transaction(bytes.into())
- .compat()
+ .await
.map(|res| format!("{:02x}", res))
- .map_err(|e| ERRL!("{}", e)),
- )
+ .map_err(|e| ERRL!("{}", e));
+
+ result
+ };
+
+ Box::new(fut.boxed().compat())
}
fn send_raw_tx_bytes(&self, tx: &[u8]) -> Box + Send> {
- Box::new(
- self.web3
- .eth()
- .send_raw_transaction(tx.into())
- .compat()
+ let coin = self.clone();
+
+ let tx = tx.to_owned();
+ let fut = async move {
+ coin.send_raw_transaction(tx.into())
+ .await
.map(|res| format!("{:02x}", res))
- .map_err(|e| ERRL!("{}", e)),
- )
+ .map_err(|e| ERRL!("{}", e))
+ };
+
+ Box::new(fut.boxed().compat())
}
async fn sign_raw_tx(&self, args: &SignRawTransactionRequest) -> RawTransactionResult {
@@ -2344,7 +2280,7 @@ impl MarketCoinOps for EthCoin {
if let Some(event) = found {
if let Some(tx_hash) = event.transaction_hash {
- let transaction = match selfi.web3.eth().transaction(TransactionId::Hash(tx_hash)).await {
+ let transaction = match selfi.transaction(TransactionId::Hash(tx_hash)).await {
Ok(Some(t)) => t,
Ok(None) => {
info!("Tx {} not found yet", tx_hash);
@@ -2375,14 +2311,16 @@ impl MarketCoinOps for EthCoin {
}
fn current_block(&self) -> Box + Send> {
- Box::new(
- self.web3
- .eth()
- .block_number()
- .compat()
+ let coin = self.clone();
+
+ let fut = async move {
+ coin.block_number()
+ .await
.map(|res| res.as_u64())
- .map_err(|e| ERRL!("{}", e)),
- )
+ .map_err(|e| ERRL!("{}", e))
+ };
+
+ Box::new(fut.boxed().compat())
}
fn display_priv_key(&self) -> Result {
@@ -2439,11 +2377,8 @@ async fn sign_transaction_with_keypair(
}
let _nonce_lock = coin.nonce_lock.lock().await;
status.status(tags!(), "get_addr_nonce…");
- let (nonce, web3_instances_with_latest_nonce) = try_tx_s!(
- get_addr_nonce(coin.my_address, coin.web3_instances.clone())
- .compat()
- .await
- );
+ let (nonce, web3_instances_with_latest_nonce) =
+ try_tx_s!(coin.clone().get_addr_nonce(coin.my_address).compat().await);
status.status(tags!(), "get_gas_price…");
let gas_price = try_tx_s!(coin.get_gas_price().compat().await);
@@ -2526,7 +2461,7 @@ async fn sign_and_send_transaction_with_metamask(
// Please note that this method may take a long time
// due to `wallet_switchEthereumChain` and `eth_sendTransaction` requests.
- let tx_hash = try_tx_s!(coin.web3.eth().send_transaction(tx_to_send).await);
+ let tx_hash = try_tx_s!(coin.send_transaction(tx_to_send).await);
let maybe_signed_tx = try_tx_s!(
coin.wait_for_tx_appears_on_rpc(tx_hash, wait_rpc_timeout, check_every)
@@ -2577,7 +2512,147 @@ async fn sign_raw_eth_tx(coin: &EthCoin, args: &SignEthTransactionParams) -> Raw
}
}
+#[async_trait]
+impl RpcCommonOps for EthCoin {
+ type RpcClient = Web3Instance;
+ type Error = Web3RpcError;
+
+ async fn get_live_client(&self) -> Result {
+ let mut clients = self.web3_instances.lock().await;
+
+ // try to find first live client
+ for (i, client) in clients.clone().into_iter().enumerate() {
+ if let Web3Transport::Websocket(socket_transport) = &client.web3.transport() {
+ socket_transport.maybe_spawn_connection_loop(self.clone());
+ };
+
+ if !client.web3.transport().is_last_request_failed() {
+ // Bring the live client to the front of rpc_clients
+ clients.rotate_left(i);
+ return Ok(client);
+ }
+
+ match client
+ .web3
+ .web3()
+ .client_version()
+ .timeout(ETH_RPC_REQUEST_TIMEOUT)
+ .await
+ {
+ Ok(Ok(_)) => {
+ // Bring the live client to the front of rpc_clients
+ clients.rotate_left(i);
+ return Ok(client);
+ },
+ Ok(Err(rpc_error)) => {
+ debug!("Could not get client version on: {:?}. Error: {}", &client, rpc_error);
+
+ if let Web3Transport::Websocket(socket_transport) = client.web3.transport() {
+ socket_transport.stop_connection_loop().await;
+ };
+ },
+ Err(timeout_error) => {
+ debug!(
+ "Client version timeout exceed on: {:?}. Error: {}",
+ &client, timeout_error
+ );
+
+ if let Web3Transport::Websocket(socket_transport) = client.web3.transport() {
+ socket_transport.stop_connection_loop().await;
+ };
+ },
+ };
+ }
+
+ return Err(Web3RpcError::Transport(
+ "All the current rpc nodes are unavailable.".to_string(),
+ ));
+ }
+}
+
impl EthCoin {
+ pub(crate) async fn web3(&self) -> Result, Web3RpcError> {
+ self.get_live_client().await.map(|t| t.web3)
+ }
+
+ /// Gets `SenderRefunded` events from etomic swap smart contract since `from_block`
+ fn refund_events(
+ &self,
+ swap_contract_address: Address,
+ from_block: u64,
+ to_block: u64,
+ ) -> Box, Error = String> + Send> {
+ let contract_event = try_fus!(SWAP_CONTRACT.event("SenderRefunded"));
+ let filter = FilterBuilder::default()
+ .topics(Some(vec![contract_event.signature()]), None, None, None)
+ .from_block(BlockNumber::Number(from_block.into()))
+ .to_block(BlockNumber::Number(to_block.into()))
+ .address(vec![swap_contract_address])
+ .build();
+
+ let coin = self.clone();
+
+ let fut = async move { coin.logs(filter).await.map_err(|e| ERRL!("{}", e)) };
+
+ Box::new(fut.boxed().compat())
+ }
+
+ /// Gets ETH traces from ETH node between addresses in `from_block` and `to_block`
+ fn eth_traces(
+ &self,
+ from_addr: Vec,
+ to_addr: Vec,
+ from_block: BlockNumber,
+ to_block: BlockNumber,
+ limit: Option,
+ ) -> Box, Error = String> + Send> {
+ let mut filter = TraceFilterBuilder::default()
+ .from_address(from_addr)
+ .to_address(to_addr)
+ .from_block(from_block)
+ .to_block(to_block);
+
+ if let Some(l) = limit {
+ filter = filter.count(l);
+ }
+
+ let coin = self.clone();
+
+ let fut = async move { coin.trace_filter(filter.build()).await.map_err(|e| ERRL!("{}", e)) };
+ Box::new(fut.boxed().compat())
+ }
+
+ /// Gets Transfer events from ERC20 smart contract `addr` between `from_block` and `to_block`
+ fn erc20_transfer_events(
+ &self,
+ contract: Address,
+ from_addr: Option,
+ to_addr: Option,
+ from_block: BlockNumber,
+ to_block: BlockNumber,
+ limit: Option,
+ ) -> Box, Error = String> + Send> {
+ let contract_event = try_fus!(ERC20_CONTRACT.event("Transfer"));
+ let topic0 = Some(vec![contract_event.signature()]);
+ let topic1 = from_addr.map(|addr| vec![addr.into()]);
+ let topic2 = to_addr.map(|addr| vec![addr.into()]);
+ let mut filter = FilterBuilder::default()
+ .topics(topic0, topic1, topic2, None)
+ .from_block(from_block)
+ .to_block(to_block)
+ .address(vec![contract]);
+
+ if let Some(l) = limit {
+ filter = filter.limit(l);
+ }
+
+ let coin = self.clone();
+
+ let fut = async move { coin.logs(filter.build()).await.map_err(|e| ERRL!("{}", e)) };
+
+ Box::new(fut.boxed().compat())
+ }
+
/// Downloads and saves ETH transaction history of my_address, relies on Parity trace_filter API
/// https://wiki.parity.io/JSONRPC-trace-module#trace_filter, this requires tracing to be enabled
/// in node config. Other ETH clients (Geth, etc.) are `not` supported (yet).
@@ -2603,7 +2678,7 @@ impl EthCoin {
};
}
- let current_block = match self.web3.eth().block_number().await {
+ let current_block = match self.block_number().await {
Ok(block) => block,
Err(e) => {
ctx.log.log(
@@ -2786,8 +2861,6 @@ impl EthCoin {
mm_counter!(ctx.metrics, "tx.history.request.count", 1, "coin" => self.ticker.clone(), "method" => "tx_detail_by_hash");
let web3_tx = match self
- .web3
- .eth()
.transaction(TransactionId::Hash(trace.transaction_hash.unwrap()))
.await
{
@@ -2819,12 +2892,7 @@ impl EthCoin {
mm_counter!(ctx.metrics, "tx.history.response.count", 1, "coin" => self.ticker.clone(), "method" => "tx_detail_by_hash");
- let receipt = match self
- .web3
- .eth()
- .transaction_receipt(trace.transaction_hash.unwrap())
- .await
- {
+ let receipt = match self.transaction_receipt(trace.transaction_hash.unwrap()).await {
Ok(r) => r,
Err(e) => {
ctx.log.log(
@@ -2878,8 +2946,6 @@ impl EthCoin {
let raw = signed_tx_from_web3_tx(web3_tx).unwrap();
let block = match self
- .web3
- .eth()
.block(BlockId::Number(BlockNumber::Number(trace.block_number.into())))
.await
{
@@ -2962,7 +3028,7 @@ impl EthCoin {
};
}
- let current_block = match self.web3.eth().block_number().await {
+ let current_block = match self.block_number().await {
Ok(block) => block,
Err(e) => {
ctx.log.log(
@@ -3165,8 +3231,6 @@ impl EthCoin {
"coin" => self.ticker.clone(), "client" => "ethereum", "method" => "tx_detail_by_hash");
let web3_tx = match self
- .web3
- .eth()
.transaction(TransactionId::Hash(event.transaction_hash.unwrap()))
.await
{
@@ -3200,12 +3264,7 @@ impl EthCoin {
},
};
- let receipt = match self
- .web3
- .eth()
- .transaction_receipt(event.transaction_hash.unwrap())
- .await
- {
+ let receipt = match self.transaction_receipt(event.transaction_hash.unwrap()).await {
Ok(r) => r,
Err(e) => {
ctx.log.log(
@@ -3236,12 +3295,7 @@ impl EthCoin {
None => None,
};
let block_number = event.block_number.unwrap();
- let block = match self
- .web3
- .eth()
- .block(BlockId::Number(BlockNumber::Number(block_number)))
- .await
- {
+ let block = match self.block(BlockId::Number(BlockNumber::Number(block_number))).await {
Ok(Some(b)) => b,
Ok(None) => {
ctx.log.log(
@@ -3983,7 +4037,7 @@ impl EthCoin {
let coin = self.clone();
let fut = async move {
match coin.coin_type {
- EthCoinType::Eth => Ok(coin.web3.eth().balance(address, Some(BlockNumber::Latest)).await?),
+ EthCoinType::Eth => Ok(coin.balance(address, Some(BlockNumber::Latest)).await?),
EthCoinType::Erc20 { ref token_addr, .. } => {
let function = ERC20_CONTRACT.function("balanceOf")?;
let data = function.encode_input(&[Token::Address(address)])?;
@@ -4090,9 +4144,13 @@ impl EthCoin {
Ok(owner_address)
}
- fn estimate_gas(&self, req: CallRequest) -> Box + Send> {
+ fn estimate_gas_wrapper(&self, req: CallRequest) -> Box + Send> {
+ let coin = self.clone();
+
// always using None block number as old Geth version accept only single argument in this RPC
- Box::new(self.web3.eth().estimate_gas(req, None).compat())
+ let fut = async move { coin.estimate_gas(req, None).await };
+
+ Box::new(fut.boxed().compat())
}
/// Estimates how much gas is necessary to allow the contract call to complete.
@@ -4120,18 +4178,16 @@ impl EthCoin {
gas_price: Some(gas_price),
..CallRequest::default()
};
- coin.estimate_gas(estimate_gas_req).map_to_mm_fut(Web3RpcError::from)
+ coin.estimate_gas_wrapper(estimate_gas_req)
+ .map_to_mm_fut(Web3RpcError::from)
}))
}
fn eth_balance(&self) -> BalanceFut {
- Box::new(
- self.web3
- .eth()
- .balance(self.my_address, Some(BlockNumber::Latest))
- .compat()
- .map_to_mm_fut(BalanceError::from),
- )
+ let coin = self.clone();
+
+ let fut = async move { coin.balance(coin.my_address, Some(BlockNumber::Latest)).await };
+ Box::new(fut.boxed().compat().map_to_mm_fut(BalanceError::from))
}
async fn call_request(&self, to: Address, value: Option, data: Option) -> Result {
@@ -4145,10 +4201,7 @@ impl EthCoin {
..CallRequest::default()
};
- self.web3
- .eth()
- .call(request, Some(BlockId::Number(BlockNumber::Latest)))
- .await
+ self.call(request, Some(BlockId::Number(BlockNumber::Latest))).await
}
fn allowance(&self, spender: Address) -> Web3RpcFut {
@@ -4250,7 +4303,10 @@ impl EthCoin {
.address(vec![swap_contract_address])
.build();
- Box::new(self.web3.eth().logs(filter).compat().map_err(|e| ERRL!("{}", e)))
+ let coin = self.clone();
+
+ let fut = async move { coin.logs(filter).await.map_err(|e| ERRL!("{}", e)) };
+ Box::new(fut.boxed().compat())
}
/// Gets `ReceiverSpent` events from etomic swap smart contract since `from_block`
@@ -4268,7 +4324,10 @@ impl EthCoin {
.address(vec![swap_contract_address])
.build();
- Box::new(self.web3.eth().logs(filter).compat().map_err(|e| ERRL!("{}", e)))
+ let coin = self.clone();
+
+ let fut = async move { coin.logs(filter).await.map_err(|e| ERRL!("{}", e)) };
+ Box::new(fut.boxed().compat())
}
fn validate_payment(&self, input: ValidatePaymentInput) -> ValidatePaymentFut<()> {
@@ -4309,7 +4368,7 @@ impl EthCoin {
)));
}
- let tx_from_rpc = selfi.web3.eth().transaction(TransactionId::Hash(tx.hash)).await?;
+ let tx_from_rpc = selfi.transaction(TransactionId::Hash(tx.hash)).await?;
let tx_from_rpc = tx_from_rpc.as_ref().ok_or_else(|| {
ValidatePaymentError::TxDoesNotExist(format!("Didn't find provided tx {:?} on ETH node", tx.hash))
})?;
@@ -4623,8 +4682,7 @@ impl EthCoin {
if let Some(event) = found {
match event.transaction_hash {
Some(tx_hash) => {
- let transaction = match try_s!(self.web3.eth().transaction(TransactionId::Hash(tx_hash)).await)
- {
+ let transaction = match try_s!(self.transaction(TransactionId::Hash(tx_hash)).await) {
Some(t) => t,
None => {
return ERR!("Found ReceiverSpent event, but transaction {:02x} is missing", tx_hash)
@@ -4649,8 +4707,7 @@ impl EthCoin {
if let Some(event) = found {
match event.transaction_hash {
Some(tx_hash) => {
- let transaction = match try_s!(self.web3.eth().transaction(TransactionId::Hash(tx_hash)).await)
- {
+ let transaction = match try_s!(self.transaction(TransactionId::Hash(tx_hash)).await) {
Some(t) => t,
None => {
return ERR!("Found SenderRefunded event, but transaction {:02x} is missing", tx_hash)
@@ -4708,7 +4765,7 @@ impl EthCoin {
None => None,
};
- let eth_gas_price = match coin.web3.eth().gas_price().await {
+ let eth_gas_price = match coin.gas_price().await {
Ok(eth_gas) => Some(eth_gas),
Err(e) => {
error!("Error {} on eth_gasPrice request", e);
@@ -4716,11 +4773,7 @@ impl EthCoin {
},
};
- let fee_history_namespace: EthFeeHistoryNamespace<_> = coin.web3.api();
- let eth_fee_history_price = match fee_history_namespace
- .eth_fee_history(U256::from(1u64), BlockNumber::Latest, &[])
- .await
- {
+ let eth_fee_history_price = match coin.eth_fee_history(U256::from(1u64), BlockNumber::Latest, &[]).await {
Ok(res) => res
.base_fee_per_gas
.first()
@@ -4753,7 +4806,7 @@ impl EthCoin {
/// The function is endless, we just keep looping in case of a transport error hoping it will go away.
async fn wait_for_addr_nonce_increase(&self, addr: Address, prev_nonce: U256) {
repeatable!(async {
- match get_addr_nonce(addr, self.web3_instances.clone()).compat().await {
+ match self.clone().get_addr_nonce(addr).compat().await {
Ok((new_nonce, _)) if new_nonce > prev_nonce => Ready(()),
Ok((_nonce, _)) => Retry(()),
Err(e) => {
@@ -4778,7 +4831,7 @@ impl EthCoin {
) -> Web3RpcResult