From 9d2475fed3f982b1024fcb638c48b5eb3d255787 Mon Sep 17 00:00:00 2001 From: Josh Stevens Date: Sun, 21 Jul 2024 17:30:01 +0100 Subject: [PATCH] - fix: fix rust project not being able to run due to borrower check - fix: fix typings generations to parse the object values correctly --- cli/Makefile | 2 +- core/src/generator/events_bindings.rs | 6 +- core/src/helpers/mod.rs | 26 +- core/src/indexer/fetch_logs.rs | 8 +- documentation/docs/pages/docs/changelog.mdx | 4 + rindexer_rust_playground/abis/world.abi.json | 33 ++ rindexer_rust_playground/rindexer.yaml | 14 +- rindexer_rust_playground/src/main.rs | 1 + .../src/rindexer_lib/indexers/all_handlers.rs | 6 +- .../{erc20_filter.rs => erc_20_filter.rs} | 8 +- .../indexers/rindexer_playground/mod.rs | 3 +- .../indexers/rindexer_playground/world.rs | 97 ++++++ .../src/rindexer_lib/typings/networks.rs | 18 + .../{erc20_filter.rs => erc_20_filter.rs} | 4 +- ...er_abi_gen.rs => erc_20_filter_abi_gen.rs} | 0 .../typings/rindexer_playground/events/mod.rs | 6 +- .../rindexer_playground/events/world.rs | 315 ++++++++++++++++++ .../events/world_abi_gen.rs | 140 ++++++++ 18 files changed, 669 insertions(+), 22 deletions(-) create mode 100644 rindexer_rust_playground/abis/world.abi.json rename rindexer_rust_playground/src/rindexer_lib/indexers/rindexer_playground/{erc20_filter.rs => erc_20_filter.rs} (95%) create mode 100644 rindexer_rust_playground/src/rindexer_lib/indexers/rindexer_playground/world.rs rename rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/{erc20_filter.rs => erc_20_filter.rs} (98%) rename rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/{erc20_filter_abi_gen.rs => erc_20_filter_abi_gen.rs} (100%) create mode 100644 rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/world.rs create mode 100644 rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/world_abi_gen.rs diff --git a/cli/Makefile b/cli/Makefile index c1433de7..5764b074 100644 --- a/cli/Makefile +++ b/cli/Makefile @@ -21,7 +21,7 @@ start_graphql: start_indexer_uniswap_v3_factory: RUSTFLAGS='-C target-cpu=native' cargo run --release --features jemalloc -- start --path /Users/joshstevens/code/rindexer/examples/uniswap_v3_factory all codegen: - RUSTFLAGS='-C target-cpu=native' cargo run --release --features jemalloc -- codegen --path /Users/joshstevens/code/rust typings + RUSTFLAGS='-C target-cpu=native' cargo run --release --features jemalloc -- codegen --path /Users/joshstevens/code/kami typings codegen_typings: cargo run -- codegen typings codegen_indexer: diff --git a/core/src/generator/events_bindings.rs b/core/src/generator/events_bindings.rs index a204c692..51456937 100644 --- a/core/src/generator/events_bindings.rs +++ b/core/src/generator/events_bindings.rs @@ -11,7 +11,7 @@ use crate::{ database::postgres::generate::{ generate_column_names_only_with_base_properties, generate_event_table_full_name, }, - helpers::{camel_to_snake, get_full_path}, + helpers::{camel_to_snake, camel_to_snake_advanced, get_full_path}, manifest::{ contract::{Contract, ContractDetails}, storage::{CsvDetails, Storage}, @@ -24,7 +24,7 @@ pub fn abigen_contract_name(contract: &Contract) -> String { } fn abigen_contract_mod_name(contract: &Contract) -> String { - camel_to_snake(&abigen_contract_name(contract)) + camel_to_snake_advanced(&abigen_contract_name(contract), true) } pub fn abigen_contract_file_name(contract: &Contract) -> String { @@ -799,7 +799,7 @@ pub fn generate_event_handlers( if !static_bytes.is_empty() { ".into()" } else { - "" + ".clone()" } } else { "" diff --git a/core/src/helpers/mod.rs b/core/src/helpers/mod.rs index 9af89587..8053e5cd 100644 --- a/core/src/helpers/mod.rs +++ b/core/src/helpers/mod.rs @@ -20,14 +20,17 @@ pub use file::{ use rand::{distributions::Alphanumeric, Rng}; pub fn camel_to_snake(s: &str) -> String { + camel_to_snake_advanced(s, false) +} + +pub fn camel_to_snake_advanced(s: &str, numbers_attach_to_last_word: bool) -> String { let mut snake_case = String::new(); let mut previous_was_uppercase = false; + let mut previous_was_digit = false; for (i, c) in s.chars().enumerate() { if c.is_alphanumeric() || c == '_' { if c.is_uppercase() { - // Insert an underscore if it's not the first character and the previous character - // wasn't uppercase if i > 0 && (!previous_was_uppercase || (i + 1 < s.len() && @@ -40,9 +43,22 @@ pub fn camel_to_snake(s: &str) -> String { } snake_case.push(c.to_ascii_lowercase()); previous_was_uppercase = true; + previous_was_digit = false; + } else if c.is_ascii_digit() { + if !numbers_attach_to_last_word && + i > 0 && + !previous_was_digit && + !snake_case.ends_with('_') + { + snake_case.push('_'); + } + snake_case.push(c); + previous_was_uppercase = false; + previous_was_digit = true; } else { snake_case.push(c); previous_was_uppercase = false; + previous_was_digit = false; } } } @@ -109,6 +125,10 @@ mod tests { assert_eq!(camel_to_snake("Camel"), "camel"); assert_eq!(camel_to_snake("camel"), "camel"); assert_eq!(camel_to_snake("collectNFTId"), "collect_nft_id"); - assert_eq!(camel_to_snake("ERC20"), "erc20"); + assert_eq!(camel_to_snake("ERC20"), "erc_20"); + assert_eq!(camel_to_snake("arg1"), "arg_1"); + + assert_eq!(camel_to_snake_advanced("ERC20", false), "erc_20"); + assert_eq!(camel_to_snake_advanced("ERC20", true), "erc20"); } } diff --git a/core/src/indexer/fetch_logs.rs b/core/src/indexer/fetch_logs.rs index b0dbbac3..5fd7fd5b 100644 --- a/core/src/indexer/fetch_logs.rs +++ b/core/src/indexer/fetch_logs.rs @@ -487,9 +487,11 @@ fn retry_with_block_range( ) -> Option { let error_message = &error.message; // some providers put the data in the data field - let error_data = match &error.data { - Some(data) => &data.to_string(), - None => &String::from(""), + let error_data_binding = error.data.as_ref().map(|data| data.to_string()); + let empty_string = String::from(""); + let error_data = match &error_data_binding { + Some(data) => data, + None => &empty_string, }; fn compile_regex(pattern: &str) -> Result { diff --git a/documentation/docs/pages/docs/changelog.mdx b/documentation/docs/pages/docs/changelog.mdx index 2048767c..387d97e4 100644 --- a/documentation/docs/pages/docs/changelog.mdx +++ b/documentation/docs/pages/docs/changelog.mdx @@ -8,9 +8,13 @@ ### Bug fixes ------------------------------------------------- + - fix: fixing the query of implemntation ABI for proxy contracts - fix: add request timeouts to adapt to different verifier's rate limits - fix: make chain_id u64 instead of u32 - https://github.com/joshstevens19/rindexer/issues/53 +- fix: fix rust project not being able to run due to borrower check +- fix: fix typings generations to parse the object values correctly + ### Breaking changes ------------------------------------------------- diff --git a/rindexer_rust_playground/abis/world.abi.json b/rindexer_rust_playground/abis/world.abi.json new file mode 100644 index 00000000..137a47b4 --- /dev/null +++ b/rindexer_rust_playground/abis/world.abi.json @@ -0,0 +1,33 @@ +[ + { + "type": "event", + "name": "ComponentValueSet", + "inputs": [ + { + "name": "arg0", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "arg1", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "arg2", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "arg3", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + } +] \ No newline at end of file diff --git a/rindexer_rust_playground/rindexer.yaml b/rindexer_rust_playground/rindexer.yaml index 0993b0da..fbaae099 100644 --- a/rindexer_rust_playground/rindexer.yaml +++ b/rindexer_rust_playground/rindexer.yaml @@ -4,6 +4,9 @@ networks: - name: ethereum chain_id: 1 rpc: https://mainnet.gateway.tenderly.co + - name: yominet + chain_id: 5264468217 + rpc: https://yominet.rpc.caldera.xyz/http storage: postgres: enabled: true @@ -28,4 +31,13 @@ contracts: network: ethereum #start_block: 56399431 abi: ./abis/erc20-abi.json - generate_csv: true \ No newline at end of file + generate_csv: true + - name: World + details: + - network: yominet + address: 0x441e13a25caecad50028e7623a39b91a507bca02 + start_block: '1077466' + end_block: '1650276' + abi: ./abis/world.abi.json + include_events: + - ComponentValueSet \ No newline at end of file diff --git a/rindexer_rust_playground/src/main.rs b/rindexer_rust_playground/src/main.rs index 66bc3054..155e5050 100644 --- a/rindexer_rust_playground/src/main.rs +++ b/rindexer_rust_playground/src/main.rs @@ -46,6 +46,7 @@ async fn main() { let result = start_rindexer(StartDetails { manifest_path: &manifest_path, indexing_details: if enable_indexer { + // EventCallbackRegistry { events: vec![] } Some(IndexingDetails { registry: register_all_handlers(&manifest_path).await }) } else { None diff --git a/rindexer_rust_playground/src/rindexer_lib/indexers/all_handlers.rs b/rindexer_rust_playground/src/rindexer_lib/indexers/all_handlers.rs index 2c09466b..d2e28fdb 100644 --- a/rindexer_rust_playground/src/rindexer_lib/indexers/all_handlers.rs +++ b/rindexer_rust_playground/src/rindexer_lib/indexers/all_handlers.rs @@ -3,12 +3,14 @@ use std::path::PathBuf; use rindexer::event::callback_registry::EventCallbackRegistry; use super::rindexer_playground::{ - erc20_filter::erc20_filter_handlers, rocket_pool_eth::rocket_pool_eth_handlers, + erc_20_filter::erc_20_filter_handlers, rocket_pool_eth::rocket_pool_eth_handlers, + world::world_handlers, }; pub async fn register_all_handlers(manifest_path: &PathBuf) -> EventCallbackRegistry { let mut registry = EventCallbackRegistry::new(); rocket_pool_eth_handlers(manifest_path, &mut registry).await; - erc20_filter_handlers(manifest_path, &mut registry).await; + erc_20_filter_handlers(manifest_path, &mut registry).await; + world_handlers(manifest_path, &mut registry).await; registry } diff --git a/rindexer_rust_playground/src/rindexer_lib/indexers/rindexer_playground/erc20_filter.rs b/rindexer_rust_playground/src/rindexer_lib/indexers/rindexer_playground/erc_20_filter.rs similarity index 95% rename from rindexer_rust_playground/src/rindexer_lib/indexers/rindexer_playground/erc20_filter.rs rename to rindexer_rust_playground/src/rindexer_lib/indexers/rindexer_playground/erc_20_filter.rs index 866619f4..b674832f 100644 --- a/rindexer_rust_playground/src/rindexer_lib/indexers/rindexer_playground/erc20_filter.rs +++ b/rindexer_rust_playground/src/rindexer_lib/indexers/rindexer_playground/erc_20_filter.rs @@ -5,7 +5,7 @@ use rindexer::{ EthereumSqlTypeWrapper, PgType, RindexerColorize, }; -use super::super::super::typings::rindexer_playground::events::erc20_filter::{ +use super::super::super::typings::rindexer_playground::events::erc_20_filter::{ no_extensions, ERC20FilterEventType, TransferEvent, }; @@ -66,7 +66,7 @@ async fn transfer_handler(manifest_path: &PathBuf, registry: &mut EventCallbackR let result = context .database .bulk_insert_via_copy( - "rindexer_playground_erc20_filter.transfer", + "rindexer_playground_erc_20_filter.transfer", &[ "contract_address".to_string(), "from".to_string(), @@ -100,7 +100,7 @@ async fn transfer_handler(manifest_path: &PathBuf, registry: &mut EventCallbackR let result = context .database .bulk_insert( - "rindexer_playground_erc20_filter.transfer", + "rindexer_playground_erc_20_filter.transfer", &[ "contract_address".to_string(), "from".to_string(), @@ -140,6 +140,6 @@ async fn transfer_handler(manifest_path: &PathBuf, registry: &mut EventCallbackR ) .register(manifest_path, registry); } -pub async fn erc20_filter_handlers(manifest_path: &PathBuf, registry: &mut EventCallbackRegistry) { +pub async fn erc_20_filter_handlers(manifest_path: &PathBuf, registry: &mut EventCallbackRegistry) { transfer_handler(manifest_path, registry).await; } diff --git a/rindexer_rust_playground/src/rindexer_lib/indexers/rindexer_playground/mod.rs b/rindexer_rust_playground/src/rindexer_lib/indexers/rindexer_playground/mod.rs index 1ae2953f..33a6aadd 100644 --- a/rindexer_rust_playground/src/rindexer_lib/indexers/rindexer_playground/mod.rs +++ b/rindexer_rust_playground/src/rindexer_lib/indexers/rindexer_playground/mod.rs @@ -1,3 +1,4 @@ #![allow(dead_code, unused)] -pub mod erc20_filter; +pub mod erc_20_filter; pub mod rocket_pool_eth; +pub mod world; diff --git a/rindexer_rust_playground/src/rindexer_lib/indexers/rindexer_playground/world.rs b/rindexer_rust_playground/src/rindexer_lib/indexers/rindexer_playground/world.rs new file mode 100644 index 00000000..cfa6b8b5 --- /dev/null +++ b/rindexer_rust_playground/src/rindexer_lib/indexers/rindexer_playground/world.rs @@ -0,0 +1,97 @@ +use std::{path::PathBuf, sync::Arc}; + +use rindexer::{ + event::callback_registry::EventCallbackRegistry, rindexer_error, rindexer_info, + EthereumSqlTypeWrapper, PgType, RindexerColorize, +}; + +use super::super::super::typings::rindexer_playground::events::world::{ + no_extensions, ComponentValueSetEvent, WorldEventType, +}; + +async fn component_value_set_handler( + manifest_path: &PathBuf, + registry: &mut EventCallbackRegistry, +) { + WorldEventType::ComponentValueSet( + ComponentValueSetEvent::handler(|results, context| async move { + if results.is_empty() { + return Ok(()); + } + + + + let mut postgres_bulk_data: Vec> = vec![]; + let mut csv_bulk_data: Vec> = vec![]; + for result in results.iter() { + csv_bulk_data.push(vec![format!("{:?}", result.tx_information.address),result.event_data.arg_0.to_string(),format!("{:?}", result.event_data.arg_1,),result.event_data.arg_2.to_string(),result.event_data.arg_3.iter().map(|byte| format!("{:02x}", byte)).collect::>().join(""),format!("{:?}", result.tx_information.transaction_hash),result.tx_information.block_number.to_string(),result.tx_information.block_hash.to_string(),result.tx_information.network.to_string(),result.tx_information.transaction_index.to_string(),result.tx_information.log_index.to_string()]); + let data = vec![EthereumSqlTypeWrapper::Address(result.tx_information.address),EthereumSqlTypeWrapper::U256(result.event_data.arg_0),EthereumSqlTypeWrapper::Address(result.event_data.arg_1),EthereumSqlTypeWrapper::U256(result.event_data.arg_2),EthereumSqlTypeWrapper::Bytes(result.event_data.arg_3.clone()),EthereumSqlTypeWrapper::H256(result.tx_information.transaction_hash),EthereumSqlTypeWrapper::U64(result.tx_information.block_number),EthereumSqlTypeWrapper::H256(result.tx_information.block_hash),EthereumSqlTypeWrapper::String(result.tx_information.network.to_string()),EthereumSqlTypeWrapper::U64(result.tx_information.transaction_index),EthereumSqlTypeWrapper::U256(result.tx_information.log_index)];; + postgres_bulk_data.push(data); + } + + if !csv_bulk_data.is_empty() { + let csv_result = context.csv.append_bulk(csv_bulk_data).await; + if let Err(e) = csv_result { + rindexer_error!("WorldEventType::ComponentValueSet inserting csv data: {:?}", e); + return Err(e.to_string()); + } + } + + if postgres_bulk_data.is_empty() { + return Ok(()); + } + + if postgres_bulk_data.len() > 100 { + let result = context + .database + .bulk_insert_via_copy( + "rindexer_playground_world.component_value_set", + &["contract_address".to_string(), "arg_0".to_string(), "arg_1".to_string(), "arg_2".to_string(), "arg_3".to_string(), "tx_hash".to_string(), "block_number".to_string(), "block_hash".to_string(), "network".to_string(), "tx_index".to_string(), "log_index".to_string()], + &postgres_bulk_data + .first() + .ok_or("No first element in bulk data, impossible")? + .iter() + .map(|param| param.to_type()) + .collect::>(), + &postgres_bulk_data, + ) + .await; + + if let Err(e) = result { + rindexer_error!("WorldEventType::ComponentValueSet inserting bulk data via COPY: {:?}", e); + return Err(e.to_string()); + } + } else { + let result = context + .database + .bulk_insert( + "rindexer_playground_world.component_value_set", + &["contract_address".to_string(), "arg_0".to_string(), "arg_1".to_string(), "arg_2".to_string(), "arg_3".to_string(), "tx_hash".to_string(), "block_number".to_string(), "block_hash".to_string(), "network".to_string(), "tx_index".to_string(), "log_index".to_string()], + &postgres_bulk_data, + ) + .await; + + if let Err(e) = result { + rindexer_error!("WorldEventType::ComponentValueSet inserting bulk data via INSERT: {:?}", e); + return Err(e.to_string()); + } + } + + + rindexer_info!( + "World::ComponentValueSet - {} - {} events", + "INDEXED".green(), + results.len(), + ); + + Ok(()) + }, + no_extensions(), + ) + .await, + ) + .register(manifest_path, registry); +} +pub async fn world_handlers(manifest_path: &PathBuf, registry: &mut EventCallbackRegistry) { + component_value_set_handler(manifest_path, registry).await; +} diff --git a/rindexer_rust_playground/src/rindexer_lib/typings/networks.rs b/rindexer_rust_playground/src/rindexer_lib/typings/networks.rs index 038c3402..9b1e0552 100644 --- a/rindexer_rust_playground/src/rindexer_lib/typings/networks.rs +++ b/rindexer_rust_playground/src/rindexer_lib/typings/networks.rs @@ -18,6 +18,12 @@ lazy_static! { None ) .expect("Error creating provider"); + static ref YOMINET_PROVIDER: Arc = create_client( + &public_read_env_value("https://yominet.rpc.caldera.xyz/http") + .unwrap_or("https://yominet.rpc.caldera.xyz/http".to_string()), + None + ) + .expect("Error creating provider"); } pub fn get_ethereum_provider_cache() -> Arc { Arc::clone(ÐEREUM_PROVIDER) @@ -27,9 +33,21 @@ pub fn get_ethereum_provider() -> Arc>> { ETHEREUM_PROVIDER.get_inner_provider() } +pub fn get_yominet_provider_cache() -> Arc { + Arc::clone(&YOMINET_PROVIDER) +} + +pub fn get_yominet_provider() -> Arc>> { + YOMINET_PROVIDER.get_inner_provider() +} + pub fn get_provider_cache_for_network(network: &str) -> Arc { if network == "ethereum" { return get_ethereum_provider_cache(); } + + if network == "yominet" { + return get_yominet_provider_cache(); + } panic!("Network not supported") } diff --git a/rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/erc20_filter.rs b/rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/erc_20_filter.rs similarity index 98% rename from rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/erc20_filter.rs rename to rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/erc_20_filter.rs index 1568c2b5..98a59345 100644 --- a/rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/erc20_filter.rs +++ b/rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/erc_20_filter.rs @@ -35,7 +35,7 @@ use super::super::super::super::typings::networks::get_provider_cache_for_networ /// /// This file was auto generated by rindexer - https://github.com/joshstevens19/rindexer. /// Any manual changes to this file will be overwritten. -use super::erc20_filter_abi_gen::rindexer_erc20_filter_gen::{self, RindexerERC20FilterGen}; +use super::erc_20_filter_abi_gen::rindexer_erc20_filter_gen::{self, RindexerERC20FilterGen}; pub type ApprovalData = rindexer_erc20_filter_gen::ApprovalFilter; @@ -180,7 +180,7 @@ where Transfer(TransferEvent), } -pub fn erc20_filter_contract( +pub fn erc_20_filter_contract( network: &str, address: Address, ) -> RindexerERC20FilterGen>>> { diff --git a/rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/erc20_filter_abi_gen.rs b/rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/erc_20_filter_abi_gen.rs similarity index 100% rename from rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/erc20_filter_abi_gen.rs rename to rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/erc_20_filter_abi_gen.rs diff --git a/rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/mod.rs b/rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/mod.rs index 6749a057..68cc25a8 100644 --- a/rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/mod.rs +++ b/rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/mod.rs @@ -1,5 +1,7 @@ #![allow(dead_code, unused)] -pub mod erc20_filter; -mod erc20_filter_abi_gen; +pub mod erc_20_filter; +mod erc_20_filter_abi_gen; pub mod rocket_pool_eth; mod rocket_pool_eth_abi_gen; +pub mod world; +mod world_abi_gen; diff --git a/rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/world.rs b/rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/world.rs new file mode 100644 index 00000000..70275144 --- /dev/null +++ b/rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/world.rs @@ -0,0 +1,315 @@ +use std::{ + any::Any, + error::Error, + future::Future, + path::{Path, PathBuf}, + pin::Pin, + sync::Arc, +}; + +use ethers::{ + abi::Address, + providers::{Http, Provider, RetryClient}, + types::{Bytes, H256}, +}; +use rindexer::{ + async_trait, + event::{ + callback_registry::{ + EventCallbackRegistry, EventCallbackRegistryInformation, EventCallbackResult, + EventResult, TxInformation, + }, + contract_setup::{ContractInformation, NetworkContract}, + }, + generate_random_id, + manifest::{ + contract::{Contract, ContractDetails}, + yaml::read_manifest, + }, + provider::JsonRpcCachedProvider, + AsyncCsvAppender, FutureExt, PostgresClient, +}; + +use super::super::super::super::typings::networks::get_provider_cache_for_network; +/// THIS IS A GENERATED FILE. DO NOT MODIFY MANUALLY. +/// +/// This file was auto generated by rindexer - https://github.com/joshstevens19/rindexer. +/// Any manual changes to this file will be overwritten. +use super::world_abi_gen::rindexer_world_gen::{self, RindexerWorldGen}; + +pub type ComponentValueSetData = rindexer_world_gen::ComponentValueSetFilter; + +#[derive(Debug, Clone)] +pub struct ComponentValueSetResult { + pub event_data: ComponentValueSetData, + pub tx_information: TxInformation, +} + +type BoxFuture<'a, T> = Pin + Send + 'a>>; + +#[async_trait] +trait EventCallback { + async fn call(&self, events: Vec) -> EventCallbackResult<()>; +} + +pub struct EventContext +where + TExtensions: Send + Sync, +{ + pub database: Arc, + pub csv: Arc, + pub extensions: Arc, +} + +// didn't want to use option or none made harder DX +// so a blank struct makes interface nice +pub struct NoExtensions {} +pub fn no_extensions() -> NoExtensions { + NoExtensions {} +} + +pub fn componentvalueset_handler( + custom_logic: F, +) -> ComponentValueSetEventCallbackType +where + ComponentValueSetResult: Clone + 'static, + F: for<'a> Fn(Vec, Arc>) -> Fut + + Send + + Sync + + 'static + + Clone, + Fut: Future> + Send + 'static, + TExtensions: Send + Sync + 'static, +{ + Arc::new(move |results, context| { + let custom_logic = custom_logic.clone(); + let results = results.clone(); + let context = Arc::clone(&context); + async move { (custom_logic)(results, context).await }.boxed() + }) +} + +type ComponentValueSetEventCallbackType = Arc< + dyn for<'a> Fn( + &'a Vec, + Arc>, + ) -> BoxFuture<'a, EventCallbackResult<()>> + + Send + + Sync, +>; + +pub struct ComponentValueSetEvent +where + TExtensions: Send + Sync + 'static, +{ + callback: ComponentValueSetEventCallbackType, + context: Arc>, +} + +impl ComponentValueSetEvent +where + TExtensions: Send + Sync + 'static, +{ + pub async fn handler(closure: F, extensions: TExtensions) -> Self + where + ComponentValueSetResult: Clone + 'static, + F: for<'a> Fn(Vec, Arc>) -> Fut + + Send + + Sync + + 'static + + Clone, + Fut: Future> + Send + 'static, + { + let csv = AsyncCsvAppender::new("/Users/joshstevens/code/rindexer/rindexer_rust_playground/./generated_csv/World/world-componentvalueset.csv"); + if !Path::new("/Users/joshstevens/code/rindexer/rindexer_rust_playground/./generated_csv/World/world-componentvalueset.csv").exists() { + csv.append_header(vec!["contract_address".into(), "arg_0".into(), "arg_1".into(), "arg_2".into(), "arg_3".into(), "tx_hash".into(), "block_number".into(), "block_hash".into(), "network".into(), "tx_index".into(), "log_index".into()]) + .await + .expect("Failed to write CSV header"); + } + + Self { + callback: componentvalueset_handler(closure), + context: Arc::new(EventContext { + database: Arc::new( + PostgresClient::new().await.expect("Failed to connect to Postgres"), + ), + csv: Arc::new(csv), + extensions: Arc::new(extensions), + }), + } + } +} + +#[async_trait] +impl EventCallback for ComponentValueSetEvent +where + TExtensions: Send + Sync, +{ + async fn call(&self, events: Vec) -> EventCallbackResult<()> { + let events_len = events.len(); + + // note some can not downcast because it cant decode + // this happens on events which failed decoding due to + // not having the right abi for example + // transfer events with 2 indexed topics cant decode + // transfer events with 3 indexed topics + let result: Vec = events + .into_iter() + .filter_map(|item| { + item.decoded_data.downcast::().ok().map(|arc| { + ComponentValueSetResult { + event_data: (*arc).clone(), + tx_information: item.tx_information, + } + }) + }) + .collect(); + + if result.len() == events_len { + (self.callback)(&result, Arc::clone(&self.context)).await + } else { + panic!("ComponentValueSetEvent: Unexpected data type - expected: ComponentValueSetData") + } + } +} + +pub enum WorldEventType +where + TExtensions: 'static + Send + Sync, +{ + ComponentValueSet(ComponentValueSetEvent), +} + +pub fn world_contract(network: &str) -> RindexerWorldGen>>> { + let address: Address = "0x441e…ca02".parse().expect("Invalid address"); + RindexerWorldGen::new( + address, + Arc::new(get_provider_cache_for_network(network).get_inner_provider()), + ) +} + +pub fn decoder_contract(network: &str) -> RindexerWorldGen>>> { + if network == "yominet" { + RindexerWorldGen::new( + // do not care about address here its decoding makes it easier to handle ValueOrArray + Address::zero(), + Arc::new(get_provider_cache_for_network(network).get_inner_provider()), + ) + } else { + panic!("Network not supported"); + } +} + +impl WorldEventType +where + TExtensions: 'static + Send + Sync, +{ + pub fn topic_id(&self) -> &'static str { + match self { + WorldEventType::ComponentValueSet(_) => { + "0x6ac31c38682e0128240cf68316d7ae751020d8f74c614e2a30278afcec8a6073" + } + } + } + + pub fn event_name(&self) -> &'static str { + match self { + WorldEventType::ComponentValueSet(_) => "ComponentValueSet", + } + } + + pub fn contract_name(&self) -> String { + "World".to_string() + } + + fn get_provider(&self, network: &str) -> Arc { + get_provider_cache_for_network(network) + } + + fn decoder( + &self, + network: &str, + ) -> Arc, Bytes) -> Arc + Send + Sync> { + let decoder_contract = decoder_contract(network); + + match self { + WorldEventType::ComponentValueSet(_) => { + Arc::new(move |topics: Vec, data: Bytes| { + match decoder_contract.decode_event::( + "ComponentValueSet", + topics, + data, + ) { + Ok(filter) => Arc::new(filter) as Arc, + Err(error) => Arc::new(error) as Arc, + } + }) + } + } + } + + pub fn register(self, manifest_path: &PathBuf, registry: &mut EventCallbackRegistry) { + let rindexer_yaml = read_manifest(manifest_path).expect("Failed to read rindexer.yaml"); + let topic_id = self.topic_id(); + let contract_name = self.contract_name(); + let event_name = self.event_name(); + + let contract_details = rindexer_yaml + .contracts + .iter() + .find(|c| c.name == contract_name) + .unwrap_or_else(|| { + panic!( + "Contract {} not found please make sure its defined in the rindexer.yaml", + contract_name + ) + }) + .clone(); + + let index_event_in_order = contract_details + .index_event_in_order + .as_ref() + .map_or(false, |vec| vec.contains(&event_name.to_string())); + + let contract = ContractInformation { + name: contract_details.before_modify_name_if_filter_readonly().into_owned(), + details: contract_details + .details + .iter() + .map(|c| NetworkContract { + id: generate_random_id(10), + network: c.network.clone(), + cached_provider: self.get_provider(&c.network), + decoder: self.decoder(&c.network), + indexing_contract_setup: c.indexing_contract_setup(), + start_block: c.start_block, + end_block: c.end_block, + }) + .collect(), + abi: contract_details.abi, + reorg_safe_distance: contract_details.reorg_safe_distance.unwrap_or_default(), + }; + + let callback: Arc< + dyn Fn(Vec) -> BoxFuture<'static, EventCallbackResult<()>> + Send + Sync, + > = match self { + WorldEventType::ComponentValueSet(event) => { + let event = Arc::new(event); + Arc::new(move |result| { + let event = Arc::clone(&event); + async move { event.call(result).await }.boxed() + }) + } + }; + + registry.register_event(EventCallbackRegistryInformation { + id: generate_random_id(10), + indexer_name: "RindexerPlayground".to_string(), + event_name: event_name.to_string(), + index_event_in_order, + topic_id: topic_id.parse::().unwrap(), + contract, + callback, + }); + } +} diff --git a/rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/world_abi_gen.rs b/rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/world_abi_gen.rs new file mode 100644 index 00000000..a045208c --- /dev/null +++ b/rindexer_rust_playground/src/rindexer_lib/typings/rindexer_playground/events/world_abi_gen.rs @@ -0,0 +1,140 @@ +pub use rindexer_world_gen::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod rindexer_world_gen { + const _: () = { + ::core::include_bytes!( + "/Users/joshstevens/code/rindexer/rindexer_rust_playground/abis/world.abi.json", + ); + }; + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::std::collections::BTreeMap::new(), + events: ::core::convert::From::from([( + ::std::borrow::ToOwned::to_owned("ComponentValueSet"), + ::std::vec![::ethers::core::abi::ethabi::Event { + name: ::std::borrow::ToOwned::to_owned("ComponentValueSet"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::EventParam { + name: ::std::borrow::ToOwned::to_owned("arg0"), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(256usize,), + indexed: true, + }, + ::ethers::core::abi::ethabi::EventParam { + name: ::std::borrow::ToOwned::to_owned("arg1"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + indexed: true, + }, + ::ethers::core::abi::ethabi::EventParam { + name: ::std::borrow::ToOwned::to_owned("arg2"), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(256usize,), + indexed: true, + }, + ::ethers::core::abi::ethabi::EventParam { + name: ::std::borrow::ToOwned::to_owned("arg3"), + kind: ::ethers::core::abi::ethabi::ParamType::Bytes, + indexed: false, + }, + ], + anonymous: false, + },], + )]), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static RINDEXERWORLDGEN_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = + ::ethers::contract::Lazy::new(__abi); + pub struct RindexerWorldGen(::ethers::contract::Contract); + impl ::core::clone::Clone for RindexerWorldGen { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for RindexerWorldGen { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for RindexerWorldGen { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for RindexerWorldGen { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(RindexerWorldGen)).field(&self.address()).finish() + } + } + impl RindexerWorldGen { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + RINDEXERWORLDGEN_ABI.clone(), + client, + )) + } + ///Gets the contract's `ComponentValueSet` event + pub fn component_value_set_filter( + &self, + ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, ComponentValueSetFilter> + { + self.0.event() + } + /// Returns an `Event` builder for all the events of this contract. + pub fn events( + &self, + ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, ComponentValueSetFilter> + { + self.0.event_with_filter(::core::default::Default::default()) + } + } + impl From<::ethers::contract::Contract> + for RindexerWorldGen + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + #[derive( + Clone, + ::ethers::contract::EthEvent, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethevent( + name = "ComponentValueSet", + abi = "ComponentValueSet(uint256,address,uint256,bytes)" + )] + pub struct ComponentValueSetFilter { + #[ethevent(indexed)] + pub arg_0: ::ethers::core::types::U256, + #[ethevent(indexed)] + pub arg_1: ::ethers::core::types::Address, + #[ethevent(indexed)] + pub arg_2: ::ethers::core::types::U256, + pub arg_3: ::ethers::core::types::Bytes, + } +}