use alloy_network::AnyNetwork;
use alloy_node_bindings::{Anvil, AnvilInstance};
use alloy_primitives::{Address, Bytes, address, hex};
use alloy_provider::{Provider, ProviderBuilder, WalletProvider};
use alloy_signer_local::PrivateKeySigner;
pub(crate) const WETH9_ADDRESS: Address = address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2");
pub(crate) const MULTICALL3_ADDRESS: Address = address!("cA11bde05977b3631167028862bE2a173976CA11");
pub(crate) const ARACHNID_CREATE2: Address = address!("4e59b44847b379578588920cA78FbF26c0B4956C");
const MULTICALL3_RUNTIME_HEX: &str = include_str!("../testdata/multicall3.hex");
const WETH9_RUNTIME_HEX: &str = include_str!("../testdata/weth9.hex");
const ARACHNID_PROXY_RUNTIME: [u8; 69] = hex!(
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3"
);
alloy_sol_types::sol! {
#[sol(rpc)]
interface IWETH9 {
function deposit() external payable;
function transfer(address to, uint256 amount) external returns (bool);
function balanceOf(address owner) external view returns (uint256);
}
}
pub(crate) struct TestSetup {
pub(crate) anvil: AnvilInstance,
pub(crate) signer: PrivateKeySigner,
}
impl TestSetup {
pub(crate) async fn new() -> Self {
let anvil = Anvil::new().prague().spawn();
let signer: PrivateKeySigner = anvil.keys()[0].clone().into();
let this = Self { anvil, signer };
let p = this.provider();
set_code(
&p,
MULTICALL3_ADDRESS,
decode_hex_str(MULTICALL3_RUNTIME_HEX),
)
.await;
set_code(&p, WETH9_ADDRESS, decode_hex_str(WETH9_RUNTIME_HEX)).await;
set_code(
&p,
ARACHNID_CREATE2,
Bytes::copy_from_slice(&ARACHNID_PROXY_RUNTIME),
)
.await;
this
}
pub(crate) fn provider(
&self,
) -> impl Provider<AnyNetwork> + WalletProvider<AnyNetwork> + Clone + use<> {
let wallet = self.anvil.wallet().expect("anvil wallet");
ProviderBuilder::new()
.network::<AnyNetwork>()
.with_simple_nonce_management()
.wallet(wallet)
.connect_http(self.anvil.endpoint_url())
}
}
pub(crate) async fn set_code<P: Provider<AnyNetwork>>(provider: &P, address: Address, code: Bytes) {
provider
.client()
.request::<_, ()>("anvil_setCode", (address, code))
.await
.expect("anvil_setCode");
}
fn decode_hex_str(s: &str) -> Bytes {
hex::decode(s.trim()).expect("decode hex").into()
}