diff --git a/omni-relayer/clippy.toml b/omni-relayer/clippy.toml new file mode 100644 index 00000000..f5522e67 --- /dev/null +++ b/omni-relayer/clippy.toml @@ -0,0 +1 @@ +too-many-lines-threshold = 200 diff --git a/omni-relayer/example-mainnet-config.toml b/omni-relayer/example-mainnet-config.toml index 0563b050..d321cce5 100644 --- a/omni-relayer/example-mainnet-config.toml +++ b/omni-relayer/example-mainnet-config.toml @@ -38,20 +38,20 @@ expected_finalization_time = 1066 rpc_http_url = "https://api.mainnet-beta.solana.com" rpc_ws_url = "wss://api.mainnet-beta.solana.com" # Program ID on Solana is an account ID whitch the bridge contract (basically bridge_token_factory_address on Solana) -program_id = "" +program_id = "dahPEoZGXfyV58JqqH85okdHmpN8U2q8owgPUXSCPxe" # This is the wormhole contract ID on Solana (can be found here https://wormhole.com/docs/build/reference/contract-addresses/#__tabbed_1_2) -wormhole_id = "" +wormhole_id = "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth" # There's a list of account keys and they are store in a strict order. We need indexes to get the right key -init_transfer_sender_index = 0 -init_transfer_token_index = 6 -init_transfer_emitter_index = 15 -init_transfer_sol_sender_index = 0 -init_transfer_sol_emitter_index = 11 +init_transfer_sender_index = 5 +init_transfer_token_index = 1 +init_transfer_emitter_index = 6 +init_transfer_sol_sender_index = 1 +init_transfer_sol_emitter_index = 3 # Discriminators are used to identify the type of the event (can be found during the building process of solana's contract) init_transfer_discriminator = [174, 50, 134, 99, 122, 243, 243, 224] init_transfer_sol_discriminator = [124, 167, 164, 191, 81, 140, 108, 30] -finalize_transfer_emitter_index = 9 -finalize_transfer_sol_emitter_index = 8 +finalize_transfer_emitter_index = 6 +finalize_transfer_sol_emitter_index = 5 finalize_transfer_discriminator = [124, 126, 103, 188, 144, 65, 135, 51] finalize_transfer_sol_discriminator = [104, 27, 121, 69, 3, 70, 217, 66] diff --git a/omni-relayer/example-testnet-config.toml b/omni-relayer/example-testnet-config.toml index 801f2b65..2bf74cb1 100644 --- a/omni-relayer/example-testnet-config.toml +++ b/omni-relayer/example-testnet-config.toml @@ -45,16 +45,16 @@ program_id = "Gy1XPwYZURfBzHiGAxnw3SYC33SfqsEpGSS5zeBge28p" # This is the wormhole contract ID on Solana (can be found here https://wormhole.com/docs/build/reference/contract-addresses/#__tabbed_1_2) wormhole_id = "3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5" # There's a list of account keys and they are store in a strict order. We need indexes to get the right key -init_transfer_sender_index = 0 -init_transfer_token_index = 6 -init_transfer_emitter_index = 15 -init_transfer_sol_sender_index = 0 -init_transfer_sol_emitter_index = 11 +init_transfer_sender_index = 5 +init_transfer_token_index = 1 +init_transfer_emitter_index = 6 +init_transfer_sol_sender_index = 1 +init_transfer_sol_emitter_index = 3 # Discriminators are used to identify the type of the event (can be found during the building process of solana's contract) init_transfer_discriminator = [174, 50, 134, 99, 122, 243, 243, 224] init_transfer_sol_discriminator = [124, 167, 164, 191, 81, 140, 108, 30] -finalize_transfer_emitter_index = 9 -finalize_transfer_sol_emitter_index = 8 +finalize_transfer_emitter_index = 6 +finalize_transfer_sol_emitter_index = 5 finalize_transfer_discriminator = [124, 126, 103, 188, 144, 65, 135, 51] finalize_transfer_sol_discriminator = [104, 27, 121, 69, 3, 70, 217, 66] diff --git a/omni-relayer/src/startup/evm.rs b/omni-relayer/src/startup/evm.rs index 14fe83a8..80f638a8 100644 --- a/omni-relayer/src/startup/evm.rs +++ b/omni-relayer/src/startup/evm.rs @@ -65,20 +65,19 @@ pub async fn start_indexer( arb.expected_finalization_time, ) } - _ => anyhow::bail!("Unsupported chain kind: {:?}", chain_kind), + _ => anyhow::bail!("Unsupported chain kind: {chain_kind:?}"), }; let http_provider = ProviderBuilder::new().on_http(rpc_http_url.parse().context(format!( - "Failed to parse {:?} rpc provider as url", - chain_kind + "Failed to parse {chain_kind:?} rpc provider as url", ))?); let ws_provider = ProviderBuilder::new() .on_ws(WsConnect::new(rpc_ws_url)) .await - .context(format!("Failed to initialize {:?} WS provider", chain_kind))?; + .context(format!("Failed to initialize {chain_kind:?} WS provider"))?; - let last_processed_block_key = utils::redis::get_last_processed_key(chain_kind).await; + let last_processed_block_key = utils::redis::get_last_processed_key(chain_kind); let latest_block = http_provider.get_block_number().await?; let from_block = match start_block { Some(block) => block, @@ -100,7 +99,9 @@ pub async fn start_indexer( .to_vec(), ); - for current_block in (from_block..latest_block).step_by(block_processing_batch_size as usize) { + for current_block in + (from_block..latest_block).step_by(usize::try_from(block_processing_batch_size)?) + { let logs = http_provider .get_logs( &filter @@ -201,7 +202,7 @@ async fn process_log( utils::redis::update_last_processed( redis_connection, - &utils::redis::get_last_processed_key(chain_kind).await, + &utils::redis::get_last_processed_key(chain_kind), block_number, ) .await; diff --git a/omni-relayer/src/startup/mod.rs b/omni-relayer/src/startup/mod.rs index 81f9fab3..34fa8f6f 100644 --- a/omni-relayer/src/startup/mod.rs +++ b/omni-relayer/src/startup/mod.rs @@ -37,10 +37,7 @@ fn build_evm_bridge_client( .private_key(Some(crate::config::get_private_key(chain_kind))) .bridge_token_factory_address(Some(evm.bridge_token_factory_address.to_string())) .build() - .context(format!( - "Failed to build EvmBridgeClient ({:?})", - chain_kind - )) + .context(format!("Failed to build EvmBridgeClient ({chain_kind:?})")) }) .transpose() } diff --git a/omni-relayer/src/startup/near.rs b/omni-relayer/src/startup/near.rs index c9343d37..fdb4f24a 100644 --- a/omni-relayer/src/startup/near.rs +++ b/omni-relayer/src/startup/near.rs @@ -74,11 +74,13 @@ async fn create_lake_config( Some(block) => block, None => utils::redis::get_last_processed::<&str, u64>( redis_connection, - &utils::redis::get_last_processed_key(ChainKind::Near).await, + &utils::redis::get_last_processed_key(ChainKind::Near), ) .await - .map(|block_height| block_height + 1) - .unwrap_or(utils::near::get_final_block(jsonrpc_client).await?), + .map_or( + utils::near::get_final_block(jsonrpc_client).await?, + |block_height| block_height + 1, + ), }; info!("NEAR Lake will start from block: {}", start_block_height); @@ -127,7 +129,7 @@ pub async fn start_indexer( utils::redis::update_last_processed( &mut redis_connection, - &utils::redis::get_last_processed_key(ChainKind::Near).await, + &utils::redis::get_last_processed_key(ChainKind::Near), streamer_message.block.header.height, ) .await; diff --git a/omni-relayer/src/startup/solana.rs b/omni-relayer/src/startup/solana.rs index bed619bf..62903f90 100644 --- a/omni-relayer/src/startup/solana.rs +++ b/omni-relayer/src/startup/solana.rs @@ -86,31 +86,28 @@ async fn process_recent_signatures( program_id: &Pubkey, start_signature: Option, ) -> Result<()> { - let from_signature = match start_signature { - Some(signature) => { - utils::redis::add_event( - redis_connection, - utils::redis::SOLANA_EVENTS, - signature.clone(), - // TODO: It's better to come up with a solution that wouldn't require storing `Null` value - serde_json::Value::Null, - ) - .await; - - Signature::from_str(&signature)? - } - None => { - let Some(signature) = utils::redis::get_last_processed::<&str, String>( - redis_connection, - &utils::redis::get_last_processed_key(ChainKind::Sol).await, - ) - .await - .and_then(|s| Signature::from_str(&s).ok()) else { - return Ok(()); - }; - - signature - } + let from_signature = if let Some(signature) = start_signature { + utils::redis::add_event( + redis_connection, + utils::redis::SOLANA_EVENTS, + signature.clone(), + // TODO: It's better to come up with a solution that wouldn't require storing `Null` value + serde_json::Value::Null, + ) + .await; + + Signature::from_str(&signature)? + } else { + let Some(signature) = utils::redis::get_last_processed::<&str, String>( + redis_connection, + &utils::redis::get_last_processed_key(ChainKind::Sol), + ) + .await + .and_then(|s| Signature::from_str(&s).ok()) else { + return Ok(()); + }; + + signature }; let signatures: Vec = http_client diff --git a/omni-relayer/src/utils/evm.rs b/omni-relayer/src/utils/evm.rs index d6597f87..66674c1b 100644 --- a/omni-relayer/src/utils/evm.rs +++ b/omni-relayer/src/utils/evm.rs @@ -143,13 +143,10 @@ pub async fn construct_prover_args( borsh::to_vec(&evm_proof_args).ok() } -pub async fn string_to_evm_omniaddress( - chain_kind: ChainKind, - address: String, -) -> Result { +pub fn string_to_evm_omniaddress(chain_kind: ChainKind, address: &str) -> Result { OmniAddress::new_from_evm_address( chain_kind, - H160::from_str(&address) + H160::from_str(address) .map_err(|err| anyhow::anyhow!("Failed to parse as H160 address: {:?}", err))?, ) .map_err(|err| anyhow::anyhow!("Failed to parse as EvmOmniAddress address: {:?}", err)) diff --git a/omni-relayer/src/utils/redis.rs b/omni-relayer/src/utils/redis.rs index c31eee25..eea9c83e 100644 --- a/omni-relayer/src/utils/redis.rs +++ b/omni-relayer/src/utils/redis.rs @@ -20,10 +20,10 @@ pub const SLEEP_TIME_AFTER_EVENTS_PROCESS_SECS: u64 = 10; const QUERY_RETRY_ATTEMPTS: u64 = 10; const QUERY_RETRY_SLEEP_SECS: u64 = 1; -pub async fn get_last_processed_key(chain_kind: ChainKind) -> String { +pub fn get_last_processed_key(chain_kind: ChainKind) -> String { match chain_kind { ChainKind::Sol => "SOLANA_LAST_PROCESSED_SIGNATURE".to_string(), - _ => format!("{:?}_LAST_PROCESSED_BLOCK", chain_kind), + _ => format!("{chain_kind:?}_LAST_PROCESSED_BLOCK"), } } diff --git a/omni-relayer/src/utils/solana.rs b/omni-relayer/src/utils/solana.rs index edfb3ba0..0aa7511d 100644 --- a/omni-relayer/src/utils/solana.rs +++ b/omni-relayer/src/utils/solana.rs @@ -27,13 +27,19 @@ pub async fn process_message( signature: Signature, ) { for instruction in message.instructions.clone() { + let account_keys = instruction + .accounts + .into_iter() + .map(|i| message.account_keys.get(usize::from(i)).cloned()) + .collect::>(); + if let Err(err) = decode_instruction( redis_connection, solana, signature, transaction, &instruction.data, - &message.account_keys, + account_keys, ) .await { @@ -48,7 +54,7 @@ async fn decode_instruction( signature: Signature, transaction: &EncodedTransactionWithStatusMeta, data: &str, - account_keys: &[String], + account_keys: Vec>, ) -> Result<()> { let decoded_data = bs58::decode(data).into_vec()?; @@ -78,21 +84,31 @@ async fn decode_instruction( let (sender, token, emitter) = if discriminator == &solana.init_transfer_discriminator { let sender = account_keys .get(solana.init_transfer_sender_index) - .context("Missing sender account key")?; + .context("Missing sender account key")? + .as_ref() + .context("Sender account key is None")?; let token = account_keys .get(solana.init_transfer_token_index) - .context("Missing token account key")?; + .context("Missing token account key")? + .as_ref() + .context("Sender account key is None")?; let emitter = account_keys .get(solana.init_transfer_emitter_index) - .context("Missing emitter account key")?; + .context("Missing emitter account key")? + .as_ref() + .context("Emitter key is None")?; (sender, token, emitter) } else { let sender = account_keys .get(solana.init_transfer_sol_sender_index) - .context("Missing SOL sender account key")?; + .context("Missing SOL sender account key")? + .as_ref() + .context("SOL sender account key is None")?; let emitter = account_keys .get(solana.init_transfer_sol_emitter_index) - .context("Missing SOL emitter account key")?; + .context("Missing SOL emitter account key")? + .as_ref() + .context("Sol emitter key is None")?; (sender, &Pubkey::default().to_string(), emitter) }; @@ -104,7 +120,7 @@ async fn decode_instruction( let Some(sequence) = log .split_ascii_whitespace() .last() - .map(|sequence| sequence.to_string()) + .map(std::string::ToString::to_string) else { warn!("Failed to parse sequence number from log: {:?}", log); continue; @@ -150,10 +166,14 @@ async fn decode_instruction( account_keys .get(solana.finalize_transfer_emitter_index) .context("Missing emitter account key")? + .as_ref() + .context("Emitter account key is None")? } else { account_keys .get(solana.finalize_transfer_sol_emitter_index) .context("Missing SOL emitter account key")? + .as_ref() + .context("SOL emitter account key is None")? }; if let Some(OptionSerializer::Some(logs)) = @@ -164,7 +184,7 @@ async fn decode_instruction( let Some(sequence) = log .split_ascii_whitespace() .last() - .map(|sequence| sequence.to_string()) + .map(std::string::ToString::to_string) else { warn!("Failed to parse sequence number from log: {:?}", log); continue; diff --git a/omni-relayer/src/utils/storage.rs b/omni-relayer/src/utils/storage.rs index 56a95ad3..f8994b52 100644 --- a/omni-relayer/src/utils/storage.rs +++ b/omni-relayer/src/utils/storage.rs @@ -17,43 +17,28 @@ async fn get_token_id( let omni_token_address = match chain_kind { ChainKind::Near => { let token = AccountId::from_str(token_address).map_err(|_| { - format!( - "Failed to parse token address as AccountId: {:?}", - token_address - ) + format!("Failed to parse token address as AccountId: {token_address:?}",) })?; Ok(OmniAddress::Near(token)) } ChainKind::Eth | ChainKind::Base | ChainKind::Arb => { - utils::evm::string_to_evm_omniaddress(chain_kind, token_address.to_string()) - .await + utils::evm::string_to_evm_omniaddress(chain_kind, token_address) .map_err(|err| err.to_string()) } ChainKind::Sol => { let token = Pubkey::from_str(token_address).map_err(|_| { - format!( - "Failed to parse token address as Pubkey: {:?}", - token_address - ) + format!("Failed to parse token address as Pubkey: {token_address:?}",) })?; OmniAddress::new_from_slice(ChainKind::Sol, &token.to_bytes()) } } - .map_err(|_| { - format!( - "Failed to convert token address to OmniAddress: {:?}", - token_address - ) - })?; + .map_err(|_| format!("Failed to convert token address to OmniAddress: {token_address:?}",))?; let token_id = connector .near_get_token_id(omni_token_address.clone()) .await .map_err(|_| { - format!( - "Failed to get token id by omni token address: {:?}", - omni_token_address - ) + format!("Failed to get token id by omni token address: {omni_token_address:?}",) })?; Ok(token_id) @@ -69,10 +54,7 @@ async fn add_storage_deposit_action( .near_get_required_storage_deposit(token_id.clone(), account_id.clone()) .await .map_err(|_| { - format!( - "Failed to get required storage deposit for account: {:?}", - account_id - ) + format!("Failed to get required storage deposit for account: {account_id:?}",) })? { amount if amount > 0 => Some(amount), _ => None, @@ -124,12 +106,7 @@ pub async fn get_storage_deposit_actions( let token_id = connector .near_get_native_token_id(chain_kind) .await - .map_err(|_| { - format!( - "Failed to get native token id by chain kind: {:?}", - chain_kind - ) - })?; + .map_err(|_| format!("Failed to get native token id by chain kind: {chain_kind:?}",))?; let relayer = connector .near_bridge_client() diff --git a/omni-relayer/src/workers/evm.rs b/omni-relayer/src/workers/evm.rs index 56a0e507..1a9608f7 100644 --- a/omni-relayer/src/workers/evm.rs +++ b/omni-relayer/src/workers/evm.rs @@ -35,20 +35,17 @@ pub async fn finalize_transfer( loop { let mut redis_connection = redis_connection.clone(); - let events = match utils::redis::get_events( + let Some(events) = utils::redis::get_events( &mut redis_connection, utils::redis::EVM_INIT_TRANSFER_EVENTS.to_string(), ) .await - { - Some(events) => events, - None => { - tokio::time::sleep(tokio::time::Duration::from_secs( - utils::redis::SLEEP_TIME_AFTER_EVENTS_PROCESS_SECS, - )) - .await; - continue; - } + else { + tokio::time::sleep(tokio::time::Duration::from_secs( + utils::redis::SLEEP_TIME_AFTER_EVENTS_PROCESS_SECS, + )) + .await; + continue; }; let mut handlers = Vec::new(); @@ -137,10 +134,8 @@ async fn handle_init_transfer_event( { let sender = match utils::evm::string_to_evm_omniaddress( init_transfer_with_timestamp.chain_kind, - init_log.inner.sender.to_string(), - ) - .await - { + &init_log.inner.sender.to_string(), + ) { Ok(sender) => sender, Err(err) => { warn!("{}", err); @@ -150,10 +145,8 @@ async fn handle_init_transfer_event( let token = match utils::evm::string_to_evm_omniaddress( init_transfer_with_timestamp.chain_kind, - init_log.inner.tokenAddress.to_string(), - ) - .await - { + &init_log.inner.tokenAddress.to_string(), + ) { Ok(token) => token, Err(err) => { warn!("{}", err); @@ -198,16 +191,12 @@ async fn handle_init_transfer_event( if vaa.is_none() { if init_transfer_with_timestamp.chain_kind == ChainKind::Eth { - let light_client_latest_block_number = - match utils::near::get_eth_light_client_last_block_number(&config, &jsonrpc_client) - .await - { - Ok(block_number) => block_number, - Err(_) => { - warn!("Failed to get eth light client last block number"); - return; - } - }; + let Ok(light_client_latest_block_number) = + utils::near::get_eth_light_client_last_block_number(&config, &jsonrpc_client).await + else { + warn!("Failed to get eth light client last block number"); + return; + }; if init_transfer_with_timestamp.block_number > light_client_latest_block_number { warn!("ETH light client is not synced yet"); @@ -227,17 +216,14 @@ async fn handle_init_transfer_event( } } - let topic = match init_transfer_with_timestamp.log.topic0() { - Some(topic) => topic, - None => { - warn!("No topic0 in log: {:?}", init_transfer_with_timestamp.log); - return; - } + let Some(topic) = init_transfer_with_timestamp.log.topic0() else { + warn!("No topic0 in log: {:?}", init_transfer_with_timestamp.log); + return; }; let tx_hash = H256::from_slice(tx_hash.as_slice()); - let prover_args = match utils::evm::construct_prover_args( + let Some(prover_args) = utils::evm::construct_prover_args( &config, vaa, tx_hash, @@ -245,12 +231,9 @@ async fn handle_init_transfer_event( ProofKind::InitTransfer, ) .await - { - Some(prover_args) => prover_args, - None => { - warn!("Failed to construct prover args"); - return; - } + else { + warn!("Failed to construct prover args"); + return; }; let storage_deposit_actions = match utils::storage::get_storage_deposit_actions( diff --git a/omni-relayer/src/workers/solana.rs b/omni-relayer/src/workers/solana.rs index 84b8fa49..463f2965 100644 --- a/omni-relayer/src/workers/solana.rs +++ b/omni-relayer/src/workers/solana.rs @@ -31,20 +31,17 @@ pub async fn process_signature(config: config::Config, redis_client: redis::Clie loop { let mut redis_connection = redis_connection.clone(); - let events = match utils::redis::get_events( + let Some(events) = utils::redis::get_events( &mut redis_connection, utils::redis::SOLANA_EVENTS.to_string(), ) .await - { - Some(events) => events, - None => { - tokio::time::sleep(tokio::time::Duration::from_secs( - utils::redis::SLEEP_TIME_AFTER_EVENTS_PROCESS_SECS, - )) - .await; - continue; - } + else { + tokio::time::sleep(tokio::time::Duration::from_secs( + utils::redis::SLEEP_TIME_AFTER_EVENTS_PROCESS_SECS, + )) + .await; + continue; }; let mut handlers = Vec::new(); @@ -81,7 +78,7 @@ pub async fn process_signature(config: config::Config, redis_client: redis::Clie raw, signature, ) - .await + .await; } } @@ -93,7 +90,7 @@ pub async fn process_signature(config: config::Config, redis_client: redis::Clie .await; utils::redis::update_last_processed( &mut redis_connection, - &utils::redis::get_last_processed_key(ChainKind::Sol).await, + &utils::redis::get_last_processed_key(ChainKind::Sol), &signature.to_string(), ) .await; @@ -139,20 +136,17 @@ pub async fn finalize_transfer( loop { let mut redis_connection = redis_connection.clone(); - let events = match utils::redis::get_events( + let Some(events) = utils::redis::get_events( &mut redis_connection, utils::redis::SOLANA_INIT_TRANSFER_EVENTS.to_string(), ) .await - { - Some(events) => events, - None => { - tokio::time::sleep(tokio::time::Duration::from_secs( - utils::redis::SLEEP_TIME_AFTER_EVENTS_PROCESS_SECS, - )) - .await; - continue; - } + else { + tokio::time::sleep(tokio::time::Duration::from_secs( + utils::redis::SLEEP_TIME_AFTER_EVENTS_PROCESS_SECS, + )) + .await; + continue; }; let mut handlers = Vec::new(); @@ -201,18 +195,15 @@ async fn handle_init_transfer_event( info!("Trying to process InitTransfer log on Solana"); - let recipient = match init_transfer_with_timestamp + let Ok(recipient) = init_transfer_with_timestamp .recipient .parse::() - { - Ok(recipient) => recipient, - Err(_) => { - warn!( - "Failed to parse recipient as OmniAddress: {:?}", - init_transfer_with_timestamp.recipient - ); - return; - } + else { + warn!( + "Failed to parse recipient as OmniAddress: {:?}", + init_transfer_with_timestamp.recipient + ); + return; }; #[cfg(not(feature = "disable_fee_check"))] @@ -251,7 +242,7 @@ async fn handle_init_transfer_event( &config, Fee { fee: init_transfer_with_timestamp.fee.into(), - native_fee: (init_transfer_with_timestamp.native_fee as u128).into(), + native_fee: u128::from(init_transfer_with_timestamp.native_fee).into(), }, &sender, &recipient, @@ -304,7 +295,7 @@ async fn handle_init_transfer_event( &recipient, &init_transfer_with_timestamp.token, init_transfer_with_timestamp.fee, - init_transfer_with_timestamp.native_fee as u128, + u128::from(init_transfer_with_timestamp.native_fee), ) .await {