@ -3,7 +3,6 @@ use std::sync::Arc;
use std ::time ::Duration ;
use async_trait ::async_trait ;
use ethers ::middleware ::gas_escalator ::{ Frequency , GasEscalatorMiddleware , GeometricGasPrice } ;
use ethers ::middleware ::gas_oracle ::{
GasCategory , GasOracle , GasOracleMiddleware , Polygon , ProviderOracle ,
} ;
@ -11,8 +10,6 @@ use ethers::prelude::{
Http , JsonRpcClient , Middleware , NonceManagerMiddleware , Provider , Quorum , QuorumProvider ,
SignerMiddleware , WeightedProvider , Ws , WsClientError ,
} ;
use ethers ::types ::Address ;
use ethers_signers ::Signer ;
use hyperlane_core ::rpc_clients ::FallbackProvider ;
use reqwest ::{ Client , Url } ;
use thiserror ::Error ;
@ -213,19 +210,10 @@ pub trait BuildableWithProvider {
M : Middleware + ' static ,
{
Ok ( if let Some ( signer ) = signer {
// The signing provider is used for sending txs, which may end up stuck in the mempool due to
// gas pricing issues. We first wrap the provider in a signer middleware, to sign any new txs sent by the gas escalator middleware.
// We keep nonce manager as the outermost middleware, so that every new tx with a higher gas price reuses the same nonce.
let signing_provider = wrap_with_signer ( provider , signer . clone ( ) )
let signing_provider = wrap_with_signer ( provider , signer )
. await
. map_err ( ChainCommunicationError ::from_other ) ? ;
let gas_escalator_provider = wrap_with_gas_escalator ( signing_provider ) ;
let nonce_manager_provider =
wrap_with_nonce_manager ( gas_escalator_provider , signer . address ( ) )
. await
. map_err ( ChainCommunicationError ::from_other ) ? ;
self . build_with_provider ( nonce_manager_provider , conn , locator )
self . build_with_provider ( signing_provider , conn , locator )
} else {
self . build_with_provider ( provider , conn , locator )
}
@ -246,19 +234,15 @@ pub trait BuildableWithProvider {
async fn wrap_with_signer < M : Middleware > (
provider : M ,
signer : Signers ,
) -> Result < SignerMiddleware < M , Signers > , M ::Error > {
) -> Result < SignerMiddleware < Nonce ManagerMiddleware < M > , Signers > , M ::Error > {
let provider_chain_id = provider . get_chainid ( ) . await ? ;
let signer = ethers ::signers ::Signer ::with_chain_id ( signer , provider_chain_id . as_u64 ( ) ) ;
Ok ( SignerMiddleware ::new ( provider , signer ) )
}
let address = ethers ::prelude ::Signer ::address ( & signer ) ;
let provider = NonceManagerMiddleware ::new ( provider , address ) ;
async fn wrap_with_nonce_manager < M : Middleware > (
provider : M ,
signer_address : Address ,
) -> Result < NonceManagerMiddleware < M > , M ::Error > {
let nonce_manager_provider = NonceManagerMiddleware ::new ( provider , signer_address ) ;
Ok ( nonce_manager_provider )
let signing_provider = SignerMiddleware ::new ( provider , signer ) ;
Ok ( signing_provider )
}
fn build_polygon_gas_oracle ( chain : ethers_core ::types ::Chain ) -> ChainResult < Box < dyn GasOracle > > {
@ -290,20 +274,3 @@ where
} ;
Ok ( GasOracleMiddleware ::new ( provider , gas_oracle ) )
}
fn wrap_with_gas_escalator < M > ( provider : M ) -> GasEscalatorMiddleware < M >
where
M : Middleware + ' static ,
{
// Increase the gas price by 12.5% every 60 seconds
// (These are the default values from ethers doc comments)
const COEFFICIENT : f64 = 1.125 ;
const EVERY_SECS : u64 = 60 u64 ;
// 550 gwei is the limit we also use for polygon, so we reuse for consistency
const MAX_GAS_PRICE : u128 = 550 * 10 u128 . pow ( 9 ) ;
let escalator = GeometricGasPrice ::new ( COEFFICIENT , EVERY_SECS , MAX_GAS_PRICE . into ( ) ) ;
// Check the status of sent txs every eth block or so. The alternative is to subscribe to new blocks and check then,
// which adds unnecessary load on the provider.
const FREQUENCY : Frequency = Frequency ::Duration ( Duration ::from_secs ( 12 ) . as_millis ( ) as _ ) ;
GasEscalatorMiddleware ::new ( provider , escalator , FREQUENCY )
}