#![cfg(all(not(target_arch = "wasm32"), not(feature = "celo")))] use ethers_core::{rand::thread_rng, types::TransactionRequest, utils::Anvil}; use ethers_middleware::{ gas_escalator::{Frequency, GasEscalatorMiddleware, GeometricGasPrice}, gas_oracle::{GasCategory, GasNow, GasOracleMiddleware}, nonce_manager::NonceManagerMiddleware, signer::SignerMiddleware, }; use ethers_providers::{Http, Middleware, Provider}; use ethers_signers::{LocalWallet, Signer}; use std::convert::TryFrom; #[tokio::test] async fn mock_with_middleware() { let (provider, mock) = Provider::mocked(); // add a bunch of middlewares let gas_oracle = GasNow::new().category(GasCategory::SafeLow); let signer = LocalWallet::new(&mut thread_rng()); let address = signer.address(); let escalator = GeometricGasPrice::new(1.125, 60u64, None::); let provider = GasEscalatorMiddleware::new(provider, escalator, Frequency::PerBlock); let provider = GasOracleMiddleware::new(provider, gas_oracle); let provider = SignerMiddleware::new(provider, signer); let provider = NonceManagerMiddleware::new(provider, address); // push a response use ethers_core::types::U64; mock.push(U64::from(12u64)).unwrap(); let blk = provider.get_block_number().await.unwrap(); assert_eq!(blk.as_u64(), 12); // now that the response is gone, there's nothing left // TODO: This returns: // MiddlewareError( // MiddlewareError( // MiddlewareError( // MiddlewareError( // JsonRpcClientError(EmptyResponses) // )))) // Can we flatten it in any way? Maybe inherent to the middleware // infrastructure provider.get_block_number().await.unwrap_err(); // 2 calls were made mock.assert_request("eth_blockNumber", ()).unwrap(); mock.assert_request("eth_blockNumber", ()).unwrap(); mock.assert_request("eth_blockNumber", ()).unwrap_err(); } #[tokio::test] async fn can_stack_middlewares() { let anvil = Anvil::new().block_time(5u64).spawn(); let gas_oracle = GasNow::new().category(GasCategory::SafeLow); let signer: LocalWallet = anvil.keys()[0].clone().into(); let address = signer.address(); // the base provider let provider = Arc::new(Provider::::try_from(anvil.endpoint()).unwrap()); let chain_id = provider.get_chainid().await.unwrap().as_u64(); let signer = signer.with_chain_id(chain_id); // the Gas Price escalator middleware is the first middleware above the provider, // so that it receives the transaction last, after all the other middleware // have modified it accordingly let escalator = GeometricGasPrice::new(1.125, 60u64, None::); let provider = GasEscalatorMiddleware::new(provider, escalator, Frequency::PerBlock); // The gas price middleware MUST be below the signing middleware for things to work let provider = GasOracleMiddleware::new(provider, gas_oracle); // The signing middleware signs txs use std::sync::Arc; let provider = Arc::new(SignerMiddleware::new(provider, signer)); // The nonce manager middleware MUST be above the signing middleware so that it overrides // the nonce and the signer does not make any eth_getTransaction count calls let provider = NonceManagerMiddleware::new(provider, address); let tx = TransactionRequest::new(); let mut pending_txs = Vec::new(); for _ in 0..10 { let pending = provider.send_transaction(tx.clone(), None).await.unwrap(); let hash = *pending; let gas_price = provider.get_transaction(hash).await.unwrap().unwrap().gas_price; dbg!(gas_price); pending_txs.push(pending); } let receipts = futures_util::future::join_all(pending_txs); dbg!(receipts.await); }