diff --git a/src/abi.rs b/src/abi.rs index e1de1c4..c666419 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -11,11 +11,6 @@ sol! { function deleteIdentities(uint256[8] calldata deletionProof, bytes calldata packedDeletionIndices, uint256 preRoot, uint256 postRoot) external; } - #[sol(rpc)] - interface IStateBridge { - function propogateRoot() external; - } - #[sol(rpc)] interface IBridgedWorldID { #[derive(Serialize, Deserialize)] @@ -24,6 +19,11 @@ sol! { function receiveRoot(uint256 newRoot) external; } + #[sol(rpc)] + interface IStateBridge { + function propogateRoot() external; + } + #[sol(rpc)] contract IOptimismStateBridge { function opWorldIDaddress() external returns (address); diff --git a/src/config.rs b/src/config.rs index 3f93bc0..62818d0 100644 --- a/src/config.rs +++ b/src/config.rs @@ -11,14 +11,13 @@ use url::Url; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Config { + /// The global wallet configuration + pub wallet: Option, /// The network from which roots will be propagated - pub canonical_network: NetworkConfig, + pub canonical_network: CanonicalNetworkConfig, /// The networks to which roots will be propagated #[serde(default)] - pub bridged_networks: Vec, - /// The number of blocks in the past to start scanning for new root events - #[serde(default = "default::start_scan")] - pub start_scan: u64, + pub bridged_networks: Vec, #[serde(default)] pub telemetry: Option, } @@ -47,17 +46,28 @@ impl Config { } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct NetworkConfig { +pub struct BridgedNetworkConfig { + /// The wallet configuration for the network + /// overrides the global wallet configuration + pub wallet: Option, + pub state_bridge_addr: Address, + pub world_id_addr: Address, + #[serde(rename = "type")] + pub ty: NetworkType, + pub name: String, + pub provider: ProviderConfig, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct CanonicalNetworkConfig { + pub world_id_addr: Address, + /// The number of blocks in the past to start scanning for new root events + #[serde(default = "default::start_scan")] + pub start_scan: u64, #[serde(rename = "type")] pub ty: NetworkType, pub name: String, - pub address: Address, - #[serde(default)] - pub state_bridge_address: Address, - #[serde(default)] - pub world_id_address: Address, pub provider: ProviderConfig, - pub wallet: WalletConfig, } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -71,14 +81,8 @@ pub enum NetworkType { #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "snake_case", tag = "type")] pub enum WalletConfig { - Mnemonic { - mnemonic: String, - }, - TxSitter { - url: String, - address: Address, - gas_limit: Option, - }, + Mnemonic { mnemonic: String }, + TxSitter { url: String, gas_limit: Option }, } #[derive(Debug, Clone, Deserialize, Serialize)] diff --git a/src/main.rs b/src/main.rs index 5b1c9a2..8967189 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,7 +18,7 @@ use alloy::sol_types::SolEvent; use alloy_signer_local::coins_bip39::English; use clap::Parser; use config::{NetworkType, WalletConfig}; -use eyre::eyre::{eyre, Result}; +use eyre::eyre::{eyre, OptionExt, Result}; use futures::StreamExt; use relay::signer::{AlloySigner, Signer, TxSitterSigner}; use relay::{EVMRelay, Relay, Relayer}; @@ -102,11 +102,11 @@ pub async fn run(config: Config) -> Result<()> { // Start in the past by approximately 2 hours let start_block_number = latest_block_number - .checked_sub(config.start_scan) + .checked_sub(config.canonical_network.start_scan) .unwrap_or_default(); let filter = Filter::new() - .address(config.canonical_network.address) + .address(config.canonical_network.world_id_addr) .event_signature(TreeChanged::SIGNATURE_HASH); let scanner = BlockScanner::new( @@ -160,58 +160,64 @@ pub async fn run(config: Config) -> Result<()> { } fn init_relays(cfg: Config) -> Result> { - let mut relayers = Vec::new(); - cfg.bridged_networks.iter().for_each(|n| match n.ty { - NetworkType::Evm => { - match &cfg.canonical_network.wallet { - WalletConfig::Mnemonic { mnemonic } => { - let signer = MnemonicBuilder::::default() - .phrase(mnemonic) - .index(0) - .unwrap() - .build() - .expect("Failed to build wallet"); - let wallet = EthereumWallet::new(signer); - let l1_provider = ProviderBuilder::default() - .with_recommended_fillers() - .wallet(wallet) - .on_http( - cfg.canonical_network.provider.rpc_endpoint.clone(), + cfg.bridged_networks + .iter() + .map(|bridged| { + let wallet_config = bridged + .wallet + .as_ref() + .or(cfg.wallet.as_ref()) + .ok_or_eyre("No wallet configuration found")?; + + match bridged.ty { + NetworkType::Evm => match wallet_config { + WalletConfig::Mnemonic { mnemonic } => { + let signer = MnemonicBuilder::::default() + .phrase(mnemonic) + .index(0) + .unwrap() + .build() + .expect("Failed to build wallet"); + let wallet = EthereumWallet::new(signer); + let l1_provider = ProviderBuilder::default() + .with_recommended_fillers() + .wallet(wallet) + .on_http( + cfg.canonical_network + .provider + .rpc_endpoint + .clone(), + ); + let state_bridge = IStateBridgeInstance::new( + bridged.state_bridge_addr, + l1_provider, ); - let state_bridge = IStateBridgeInstance::new( - n.state_bridge_address, - l1_provider, - ); - - let signer = AlloySigner::new(state_bridge); - - relayers.push(Relayer::Evm(EVMRelay::new( - Signer::AlloySigner(signer), - n.world_id_address, - n.provider.rpc_endpoint.clone(), - ))); - } - WalletConfig::TxSitter { - url, - address: _, - gas_limit, - } => { - let signer = TxSitterSigner::new( - url.as_str(), - n.state_bridge_address, - *gas_limit, - ); - - relayers.push(Relayer::Evm(EVMRelay::new( - Signer::TxSitterSigner(signer), - n.world_id_address, - n.provider.rpc_endpoint.clone(), - ))); - } - }; - } - _ => {} - }); - Ok(relayers) + let signer = AlloySigner::new(state_bridge); + + Ok(Relayer::Evm(EVMRelay::new( + Signer::AlloySigner(signer), + bridged.world_id_addr, + bridged.provider.rpc_endpoint.clone(), + ))) + } + WalletConfig::TxSitter { url, gas_limit } => { + let signer = TxSitterSigner::new( + url.as_str(), + bridged.state_bridge_addr, + *gas_limit, + ); + + Ok(Relayer::Evm(EVMRelay::new( + Signer::TxSitterSigner(signer), + bridged.world_id_addr, + bridged.provider.rpc_endpoint.clone(), + ))) + } + }, + NetworkType::Svm => unimplemented!(), + NetworkType::Scroll => unimplemented!(), + } + }) + .collect() } diff --git a/src/relay/signer.rs b/src/relay/signer.rs index 5cc3af8..d82202f 100644 --- a/src/relay/signer.rs +++ b/src/relay/signer.rs @@ -111,6 +111,9 @@ impl TxSitterSigner { } impl RelaySigner for TxSitterSigner { + /// Propogate a new Root to the given network. + /// + /// This is a long running operation and should probably be awaited in a background task. async fn propagate_root(&self) -> Result<()> { let ethers_selector = ethers_core::types::Bytes::from_static( PROPOGATE_ROOT_SELECTOR.as_ref(),