diff --git a/ethfull/apicalls.go b/ethfull/apicalls.go index a601c3f..6eb89d7 100644 --- a/ethfull/apicalls.go +++ b/ethfull/apicalls.go @@ -17,8 +17,6 @@ import ( "github.com/tidwall/gjson" ) -var etherscanAPIKey = os.Getenv("SUBDEV_ETHERSCAN_API_KEY") - var httpClient = http.Client{ Transport: dhttp.NewLoggingRoundTripper(zlog, tracer, http.DefaultTransport), Timeout: 30 * time.Second, @@ -37,20 +35,20 @@ func getContractABIFollowingProxy(ctx context.Context, contractAddress string, c } return &ABI{abi, abiContent}, nil } - abi, abiContent, wait, err := getContractABI(ctx, contractAddress, chain.ApiEndpoint) + abi, abiContent, wait, err := getContractABI(ctx, contractAddress, chain.ApiEndpoint, os.Getenv(chain.APIKeyEnvVar)) if err != nil { return nil, err } <-wait.C - implementationAddress, wait, err := getProxyContractImplementation(ctx, contractAddress, chain.ApiEndpoint) + implementationAddress, wait, err := getProxyContractImplementation(ctx, contractAddress, chain.ApiEndpoint, os.Getenv(chain.APIKeyEnvVar)) if err != nil { return nil, err } <-wait.C if implementationAddress != "" { - implementationABI, implementationABIContent, wait, err := getContractABI(ctx, implementationAddress, chain.ApiEndpoint) + implementationABI, implementationABIContent, wait, err := getContractABI(ctx, implementationAddress, chain.ApiEndpoint, os.Getenv(chain.APIKeyEnvVar)) if err != nil { return nil, err } @@ -121,8 +119,11 @@ func getContractABIDirect(ctx context.Context, address string, endpoint string) } -func getContractABI(ctx context.Context, address string, endpoint string) (*eth.ABI, string, *time.Timer, error) { - req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/api?module=contract&action=getabi&address=%s&apiKey=%s", endpoint, address, etherscanAPIKey), nil) +func getContractABI(ctx context.Context, address string, endpoint string, apiKey string) (*eth.ABI, string, *time.Timer, error) { + if apiKey != "" { + apiKey = fmt.Sprintf("&apiKey=%s", apiKey) + } + req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/api?module=contract&action=getabi&address=%s%s", endpoint, address, apiKey), nil) if err != nil { return nil, "", nil, fmt.Errorf("new request: %w", err) } @@ -158,9 +159,12 @@ func getContractABI(ctx context.Context, address string, endpoint string) (*eth. } // getProxyContractImplementation returns the implementation address and a timer to wait before next call -func getProxyContractImplementation(ctx context.Context, address string, endpoint string) (string, *time.Timer, error) { +func getProxyContractImplementation(ctx context.Context, address string, endpoint string, apiKey string) (string, *time.Timer, error) { + if apiKey != "" { + apiKey = fmt.Sprintf("&apiKey=%s", apiKey) + } // check for proxy contract's implementation - req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/api?module=contract&action=getsourcecode&address=%s&apiKey=%s", endpoint, address, etherscanAPIKey), nil) + req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/api?module=contract&action=getsourcecode&address=%s%s", endpoint, address, apiKey), nil) if err != nil { return "", nil, fmt.Errorf("new request: %w", err) @@ -236,7 +240,11 @@ func getContractInitialBlock(ctx context.Context, chain *ChainConfig, contractAd return initBlock, nil } - req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/api?module=account&action=txlist&address=%s&page=1&offset=1&sort=asc&apikey=%s", chain.ApiEndpoint, contractAddress, etherscanAPIKey), nil) + apiKey := "" + if key := os.Getenv(chain.APIKeyEnvVar); key != "" { + apiKey = fmt.Sprintf("&apiKey=%s", key) + } + req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/api?module=account&action=txlist&address=%s&page=1&offset=1&sort=asc%s", chain.ApiEndpoint, contractAddress, apiKey), nil) if err != nil { return chain.FirstStreamableBlock, fmt.Errorf("new request: %w", err) } diff --git a/ethfull/chain_configs.go b/ethfull/chain_configs.go index a1c9b36..eafb04d 100644 --- a/ethfull/chain_configs.go +++ b/ethfull/chain_configs.go @@ -18,6 +18,7 @@ type ChainConfig struct { FirstStreamableBlock uint64 Network string SupportsCalls bool + APIKeyEnvVar string abiCache map[string]*ABI initialBlockCache map[string]uint64 @@ -36,6 +37,7 @@ var ChainConfigByID = map[string]*ChainConfig{ abiCache: make(map[string]*ABI), initialBlockCache: make(map[string]uint64), SupportsCalls: true, + APIKeyEnvVar: "CODEGEN_MAINNET_API_KEY", }, "bnb": { DisplayName: "BNB", @@ -47,6 +49,7 @@ var ChainConfigByID = map[string]*ChainConfig{ abiCache: make(map[string]*ABI), initialBlockCache: make(map[string]uint64), SupportsCalls: true, + APIKeyEnvVar: "CODEGEN_BNB_API_KEY", }, "polygon": { DisplayName: "Polygon", @@ -58,6 +61,7 @@ var ChainConfigByID = map[string]*ChainConfig{ abiCache: make(map[string]*ABI), initialBlockCache: make(map[string]uint64), SupportsCalls: true, + APIKeyEnvVar: "CODEGEN_POLYGON_API_KEY", }, "amoy": { DisplayName: "Polygon Amoy Testnet", @@ -113,6 +117,7 @@ var ChainConfigByID = map[string]*ChainConfig{ abiCache: make(map[string]*ABI), initialBlockCache: make(map[string]uint64), SupportsCalls: false, + APIKeyEnvVar: "CODEGEN_OPTIMISM_API_KEY", }, "avalanche": { DisplayName: "Avalanche C-chain", @@ -148,6 +153,18 @@ var ChainConfigByID = map[string]*ChainConfig{ initialBlockCache: make(map[string]uint64), SupportsCalls: true, }, + "base-mainnet": { + DisplayName: "Base Mainnet", + ExplorerLink: "https://basescan.org", + ApiEndpoint: "https://api.basescan.org", + FirehoseEndpoint: "base-mainnet.streamingfast.io", + FirstStreamableBlock: 0, + Network: "base-mainnet", + abiCache: make(map[string]*ABI), + initialBlockCache: make(map[string]uint64), + SupportsCalls: true, + APIKeyEnvVar: "CODEGEN_BASE_API_KEY", + }, } func init() { diff --git a/ethfull/templates/Cargo.toml.gotmpl b/ethfull/templates/Cargo.toml.gotmpl index ba18bf0..02931ed 100644 --- a/ethfull/templates/Cargo.toml.gotmpl +++ b/ethfull/templates/Cargo.toml.gotmpl @@ -14,7 +14,7 @@ num-bigint = "0.4" num-traits = "0.2.15" prost = "0.11" prost-types = "0.11" -substreams = "0.5" +substreams = "0.5.21" substreams-ethereum = "0.9" substreams-database-change = "1" substreams-entity-change = "1" diff --git a/ethfull/templates/entities/README.md b/ethfull/templates/entities/README.md index 39500e8..55f1b40 100644 --- a/ethfull/templates/entities/README.md +++ b/ethfull/templates/entities/README.md @@ -30,16 +30,6 @@ To run a local `graph-node` instance, you will need to install Docker. You can d To run the proto assembly script bindings, you will need to install the `buf` [cli](https://buf.build/docs/installation). -## Run the entire stack with the `run-local.sh` script - -You can run the entire stack (`docker`, `npm` installations and `graph` creation with deployment) by running the below script - -```bash -./run-local.sh -``` - -However, if you want to run each commen individually, follow the instructions below: - ## Install npm and nodeJS packages Run the following command in the `root` of the repository: diff --git a/ethfull/templates/src/lib.rs.gotmpl b/ethfull/templates/src/lib.rs.gotmpl index ceb06d5..c75d800 100644 --- a/ethfull/templates/src/lib.rs.gotmpl +++ b/ethfull/templates/src/lib.rs.gotmpl @@ -428,6 +428,7 @@ fn map_events(blk: eth::Block) -> Result Result { let mut events = contract::Events::default(); map_bayc_events(&blk, &mut events); + substreams::skip_empty_output(); Ok(events) } #[substreams::handlers::map] fn map_calls(blk: eth::Block) -> Result { let mut calls = contract::Calls::default(); map_bayc_calls(&blk, &mut calls); + substreams::skip_empty_output(); Ok(calls) } diff --git a/ethfull/testoutput/complex_abi/Cargo.toml b/ethfull/testoutput/complex_abi/Cargo.toml index e63a30e..f06375d 100644 --- a/ethfull/testoutput/complex_abi/Cargo.toml +++ b/ethfull/testoutput/complex_abi/Cargo.toml @@ -14,7 +14,7 @@ num-bigint = "0.4" num-traits = "0.2.15" prost = "0.11" prost-types = "0.11" -substreams = "0.5" +substreams = "0.5.21" substreams-ethereum = "0.9" substreams-database-change = "1" substreams-entity-change = "1" diff --git a/ethfull/testoutput/complex_abi/src/lib.rs b/ethfull/testoutput/complex_abi/src/lib.rs index d5ca4a8..7a54c35 100644 --- a/ethfull/testoutput/complex_abi/src/lib.rs +++ b/ethfull/testoutput/complex_abi/src/lib.rs @@ -1048,6 +1048,7 @@ fn map_events( let mut events = contract::Events::default(); map_ewqocontraadd123_events(&blk, &mut events); map_test_events(&blk, &store_test, &mut events); + substreams::skip_empty_output(); Ok(events) } #[substreams::handlers::map] @@ -1059,6 +1060,7 @@ fn map_calls( let mut calls = contract::Calls::default(); map_ewqocontraadd123_calls(&blk, &mut calls); map_test_calls(&blk, &store_test, &mut calls); + substreams::skip_empty_output(); Ok(calls) } #[substreams::handlers::map] diff --git a/ethfull/testoutput/uniswap_factory_v3/README.md b/ethfull/testoutput/uniswap_factory_v3/README.md index 39500e8..55f1b40 100644 --- a/ethfull/testoutput/uniswap_factory_v3/README.md +++ b/ethfull/testoutput/uniswap_factory_v3/README.md @@ -30,16 +30,6 @@ To run a local `graph-node` instance, you will need to install Docker. You can d To run the proto assembly script bindings, you will need to install the `buf` [cli](https://buf.build/docs/installation). -## Run the entire stack with the `run-local.sh` script - -You can run the entire stack (`docker`, `npm` installations and `graph` creation with deployment) by running the below script - -```bash -./run-local.sh -``` - -However, if you want to run each commen individually, follow the instructions below: - ## Install npm and nodeJS packages Run the following command in the `root` of the repository: diff --git a/ethfull/testoutput/uniswap_factory_v3/substreams/Cargo.toml b/ethfull/testoutput/uniswap_factory_v3/substreams/Cargo.toml index 11fe5fb..78cc69e 100644 --- a/ethfull/testoutput/uniswap_factory_v3/substreams/Cargo.toml +++ b/ethfull/testoutput/uniswap_factory_v3/substreams/Cargo.toml @@ -14,7 +14,7 @@ num-bigint = "0.4" num-traits = "0.2.15" prost = "0.11" prost-types = "0.11" -substreams = "0.5" +substreams = "0.5.21" substreams-ethereum = "0.9" substreams-database-change = "1" substreams-entity-change = "1" diff --git a/ethfull/testoutput/uniswap_factory_v3/substreams/src/lib.rs b/ethfull/testoutput/uniswap_factory_v3/substreams/src/lib.rs index 183b4cf..47b9058 100644 --- a/ethfull/testoutput/uniswap_factory_v3/substreams/src/lib.rs +++ b/ethfull/testoutput/uniswap_factory_v3/substreams/src/lib.rs @@ -87,6 +87,7 @@ fn map_unifactory_events(blk: ð::Block, events: &mut contract::Events) { fn map_events(blk: eth::Block) -> Result { let mut events = contract::Events::default(); map_unifactory_events(&blk, &mut events); + substreams::skip_empty_output(); Ok(events) } diff --git a/ethfull/testoutput/uniswap_v3_triggers_dynamic_datasources/substreams/Cargo.toml b/ethfull/testoutput/uniswap_v3_triggers_dynamic_datasources/substreams/Cargo.toml new file mode 100644 index 0000000..28224e2 --- /dev/null +++ b/ethfull/testoutput/uniswap_v3_triggers_dynamic_datasources/substreams/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "uniswap_v3" +version = "0.0.1" +edition = "2021" + +[lib] +name = "substreams" +crate-type = ["cdylib"] + +[dependencies] +ethabi = "17" +hex-literal = "0.3.4" +num-bigint = "0.4" +num-traits = "0.2.15" +prost = "0.11" +prost-types = "0.11" +substreams = "0.5.21" +substreams-ethereum = "0.9" +substreams-database-change = "1" +substreams-entity-change = "1" + +# Required so that ethabi > ethereum-types build correctly under wasm32-unknown-unknown +[target.wasm32-unknown-unknown.dependencies] +getrandom = { version = "0.2", features = ["custom"] } + +[build-dependencies] +anyhow = "1" +substreams-ethereum = "0.9" +regex = "1.8" + +[profile.release] +lto = true +opt-level = 's' +strip = "debuginfo" diff --git a/ethfull/testoutput/uniswap_v3_triggers_dynamic_datasources/substreams/src/lib.rs b/ethfull/testoutput/uniswap_v3_triggers_dynamic_datasources/substreams/src/lib.rs new file mode 100644 index 0000000..40ec4da --- /dev/null +++ b/ethfull/testoutput/uniswap_v3_triggers_dynamic_datasources/substreams/src/lib.rs @@ -0,0 +1,730 @@ +mod abi; +mod pb; +use hex_literal::hex; +use pb::contract::v1 as contract; +use substreams::prelude::*; +use substreams::store; +use substreams::Hex; +use substreams_ethereum::pb::eth::v2 as eth; +use substreams_ethereum::Event; + +#[allow(unused_imports)] +use num_traits::cast::ToPrimitive; +use std::str::FromStr; +use substreams::scalar::BigDecimal; + +substreams_ethereum::init!(); + +const FACTORY_TRACKED_CONTRACT: [u8; 20] = hex!("1f98431c8ad98523631ae4a59f267346ea31f984"); + +fn map_factory_events(blk: ð::Block, events: &mut contract::Events) { + events.factory_fee_amount_enableds.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| log.address == FACTORY_TRACKED_CONTRACT) + .filter_map(|log| { + if let Some(event) = abi::factory_contract::events::FeeAmountEnabled::match_and_decode(log) { + return Some(contract::FactoryFeeAmountEnabled { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + fee: event.fee.to_u64(), + tick_spacing: Into::::into(event.tick_spacing).to_i64().unwrap(), + }); + } + + None + }) + }) + .collect()); + events.factory_owner_changeds.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| log.address == FACTORY_TRACKED_CONTRACT) + .filter_map(|log| { + if let Some(event) = abi::factory_contract::events::OwnerChanged::match_and_decode(log) { + return Some(contract::FactoryOwnerChanged { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + new_owner: event.new_owner, + old_owner: event.old_owner, + }); + } + + None + }) + }) + .collect()); + events.factory_pool_createds.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| log.address == FACTORY_TRACKED_CONTRACT) + .filter_map(|log| { + if let Some(event) = abi::factory_contract::events::PoolCreated::match_and_decode(log) { + return Some(contract::FactoryPoolCreated { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + fee: event.fee.to_u64(), + pool: event.pool, + tick_spacing: Into::::into(event.tick_spacing).to_i64().unwrap(), + token0: event.token0, + token1: event.token1, + }); + } + + None + }) + }) + .collect()); +} +fn map_factory_calls(blk: ð::Block, calls: &mut contract::Calls) { + calls.factory_call_create_pools.append(&mut blk + .transactions() + .flat_map(|tx| { + tx.calls.iter() + .filter(|call| call.address == FACTORY_TRACKED_CONTRACT && abi::factory_contract::functions::CreatePool::match_call(call)) + .filter_map(|call| { + match abi::factory_contract::functions::CreatePool::decode(call) { + Ok(decoded_call) => { + let output_pool = match abi::factory_contract::functions::CreatePool::output(&call.return_data) { + Ok(output_pool) => {output_pool} + Err(_) => Default::default(), + }; + + Some(contract::FactoryCreatePoolCall { + call_tx_hash: Hex(&tx.hash).to_string(), + call_block_time: Some(blk.timestamp().to_owned()), + call_block_number: blk.number, + call_ordinal: call.begin_ordinal, + call_success: !call.state_reverted, + fee: decoded_call.fee.to_u64(), + output_pool: output_pool, + token_a: decoded_call.token_a, + token_b: decoded_call.token_b, + }) + }, + Err(_) => None, + } + }) + }) + .collect()); + calls.factory_call_enable_fee_amounts.append(&mut blk + .transactions() + .flat_map(|tx| { + tx.calls.iter() + .filter(|call| call.address == FACTORY_TRACKED_CONTRACT && abi::factory_contract::functions::EnableFeeAmount::match_call(call)) + .filter_map(|call| { + match abi::factory_contract::functions::EnableFeeAmount::decode(call) { + Ok(decoded_call) => { + Some(contract::FactoryEnableFeeAmountCall { + call_tx_hash: Hex(&tx.hash).to_string(), + call_block_time: Some(blk.timestamp().to_owned()), + call_block_number: blk.number, + call_ordinal: call.begin_ordinal, + call_success: !call.state_reverted, + fee: decoded_call.fee.to_u64(), + tick_spacing: Into::::into(decoded_call.tick_spacing).to_i64().unwrap(), + }) + }, + Err(_) => None, + } + }) + }) + .collect()); + calls.factory_call_set_owners.append(&mut blk + .transactions() + .flat_map(|tx| { + tx.calls.iter() + .filter(|call| call.address == FACTORY_TRACKED_CONTRACT && abi::factory_contract::functions::SetOwner::match_call(call)) + .filter_map(|call| { + match abi::factory_contract::functions::SetOwner::decode(call) { + Ok(decoded_call) => { + Some(contract::FactorySetOwnerCall { + call_tx_hash: Hex(&tx.hash).to_string(), + call_block_time: Some(blk.timestamp().to_owned()), + call_block_number: blk.number, + call_ordinal: call.begin_ordinal, + call_success: !call.state_reverted, + u_owner: decoded_call.u_owner, + }) + }, + Err(_) => None, + } + }) + }) + .collect()); +} + +#[substreams::handlers::map] +fn zipped_events_calls( + events: contract::Events, + calls: contract::Calls, +) -> Result { + Ok(contract::EventsCalls { + events: Some(events), + calls: Some(calls), + }) +} +fn is_declared_dds_address(addr: &Vec, ordinal: u64, dds_store: &store::StoreGetInt64) -> bool { + // substreams::log::info!("Checking if address {} is declared dds address", Hex(addr).to_string()); + if dds_store.get_at(ordinal, Hex(addr).to_string()).is_some() { + return true; + } + return false; +} +fn map_pools_events( + blk: ð::Block, + dds_store: &store::StoreGetInt64, + events: &mut contract::Events, +) { + + events.pools_burns.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::Burn::match_and_decode(log) { + return Some(contract::PoolsBurn { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + amount: event.amount.to_string(), + amount0: event.amount0.to_string(), + amount1: event.amount1.to_string(), + owner: event.owner, + tick_lower: Into::::into(event.tick_lower).to_i64().unwrap(), + tick_upper: Into::::into(event.tick_upper).to_i64().unwrap(), + }); + } + + None + }) + }) + .collect()); + + events.pools_collects.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::Collect::match_and_decode(log) { + return Some(contract::PoolsCollect { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + amount0: event.amount0.to_string(), + amount1: event.amount1.to_string(), + owner: event.owner, + recipient: event.recipient, + tick_lower: Into::::into(event.tick_lower).to_i64().unwrap(), + tick_upper: Into::::into(event.tick_upper).to_i64().unwrap(), + }); + } + + None + }) + }) + .collect()); + + events.pools_collect_protocols.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::CollectProtocol::match_and_decode(log) { + return Some(contract::PoolsCollectProtocol { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + amount0: event.amount0.to_string(), + amount1: event.amount1.to_string(), + recipient: event.recipient, + sender: event.sender, + }); + } + + None + }) + }) + .collect()); + + events.pools_flashes.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::Flash::match_and_decode(log) { + return Some(contract::PoolsFlash { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + amount0: event.amount0.to_string(), + amount1: event.amount1.to_string(), + paid0: event.paid0.to_string(), + paid1: event.paid1.to_string(), + recipient: event.recipient, + sender: event.sender, + }); + } + + None + }) + }) + .collect()); + + events.pools_increase_observation_cardinality_nexts.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::IncreaseObservationCardinalityNext::match_and_decode(log) { + return Some(contract::PoolsIncreaseObservationCardinalityNext { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + observation_cardinality_next_new: event.observation_cardinality_next_new.to_u64(), + observation_cardinality_next_old: event.observation_cardinality_next_old.to_u64(), + }); + } + + None + }) + }) + .collect()); + + events.pools_initializes.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::Initialize::match_and_decode(log) { + return Some(contract::PoolsInitialize { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + sqrt_price_x96: event.sqrt_price_x96.to_string(), + tick: Into::::into(event.tick).to_i64().unwrap(), + }); + } + + None + }) + }) + .collect()); + + events.pools_mints.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::Mint::match_and_decode(log) { + return Some(contract::PoolsMint { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + amount: event.amount.to_string(), + amount0: event.amount0.to_string(), + amount1: event.amount1.to_string(), + owner: event.owner, + sender: event.sender, + tick_lower: Into::::into(event.tick_lower).to_i64().unwrap(), + tick_upper: Into::::into(event.tick_upper).to_i64().unwrap(), + }); + } + + None + }) + }) + .collect()); + + events.pools_set_fee_protocols.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::SetFeeProtocol::match_and_decode(log) { + return Some(contract::PoolsSetFeeProtocol { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + fee_protocol0_new: event.fee_protocol0_new.to_u64(), + fee_protocol0_old: event.fee_protocol0_old.to_u64(), + fee_protocol1_new: event.fee_protocol1_new.to_u64(), + fee_protocol1_old: event.fee_protocol1_old.to_u64(), + }); + } + + None + }) + }) + .collect()); + + events.pools_swaps.append(&mut blk + .receipts() + .flat_map(|view| { + view.receipt.logs.iter() + .filter(|log| is_declared_dds_address(&log.address, log.ordinal, dds_store)) + .filter_map(|log| { + if let Some(event) = abi::pools_contract::events::Swap::match_and_decode(log) { + return Some(contract::PoolsSwap { + evt_tx_hash: Hex(&view.transaction.hash).to_string(), + evt_index: log.block_index, + evt_block_time: Some(blk.timestamp().to_owned()), + evt_block_number: blk.number, + evt_address: Hex(&log.address).to_string(), + amount0: event.amount0.to_string(), + amount1: event.amount1.to_string(), + liquidity: event.liquidity.to_string(), + recipient: event.recipient, + sender: event.sender, + sqrt_price_x96: event.sqrt_price_x96.to_string(), + tick: Into::::into(event.tick).to_i64().unwrap(), + }); + } + + None + }) + }) + .collect()); +} +fn map_pools_calls( + blk: ð::Block, + dds_store: &store::StoreGetInt64, + calls: &mut contract::Calls, +) { + calls.pools_call_burns.append(&mut blk + .transactions() + .flat_map(|tx| { + tx.calls.iter() + .filter(|call| is_declared_dds_address(&call.address, call.begin_ordinal, dds_store) && abi::pools_contract::functions::Burn::match_call(call)) + .filter_map(|call| { + match abi::pools_contract::functions::Burn::decode(call) { + Ok(decoded_call) => { + let (output_amount0, output_amount1) = match abi::pools_contract::functions::Burn::output(&call.return_data) { + Ok((output_amount0, output_amount1)) => {(output_amount0, output_amount1)} + Err(_) => Default::default(), + }; + + Some(contract::PoolsBurnCall { + call_tx_hash: Hex(&tx.hash).to_string(), + call_block_time: Some(blk.timestamp().to_owned()), + call_block_number: blk.number, + call_ordinal: call.begin_ordinal, + call_success: !call.state_reverted, + call_address: Hex(&call.address).to_string(), + amount: decoded_call.amount.to_string(), + output_amount0: output_amount0.to_string(), + output_amount1: output_amount1.to_string(), + tick_lower: Into::::into(decoded_call.tick_lower).to_i64().unwrap(), + tick_upper: Into::::into(decoded_call.tick_upper).to_i64().unwrap(), + }) + }, + Err(_) => None, + } + }) + }) + .collect()); + calls.pools_call_collects.append(&mut blk + .transactions() + .flat_map(|tx| { + tx.calls.iter() + .filter(|call| is_declared_dds_address(&call.address, call.begin_ordinal, dds_store) && abi::pools_contract::functions::Collect::match_call(call)) + .filter_map(|call| { + match abi::pools_contract::functions::Collect::decode(call) { + Ok(decoded_call) => { + let (output_amount0, output_amount1) = match abi::pools_contract::functions::Collect::output(&call.return_data) { + Ok((output_amount0, output_amount1)) => {(output_amount0, output_amount1)} + Err(_) => Default::default(), + }; + + Some(contract::PoolsCollectCall { + call_tx_hash: Hex(&tx.hash).to_string(), + call_block_time: Some(blk.timestamp().to_owned()), + call_block_number: blk.number, + call_ordinal: call.begin_ordinal, + call_success: !call.state_reverted, + call_address: Hex(&call.address).to_string(), + amount0_requested: decoded_call.amount0_requested.to_string(), + amount1_requested: decoded_call.amount1_requested.to_string(), + output_amount0: output_amount0.to_string(), + output_amount1: output_amount1.to_string(), + recipient: decoded_call.recipient, + tick_lower: Into::::into(decoded_call.tick_lower).to_i64().unwrap(), + tick_upper: Into::::into(decoded_call.tick_upper).to_i64().unwrap(), + }) + }, + Err(_) => None, + } + }) + }) + .collect()); + calls.pools_call_collect_protocols.append(&mut blk + .transactions() + .flat_map(|tx| { + tx.calls.iter() + .filter(|call| is_declared_dds_address(&call.address, call.begin_ordinal, dds_store) && abi::pools_contract::functions::CollectProtocol::match_call(call)) + .filter_map(|call| { + match abi::pools_contract::functions::CollectProtocol::decode(call) { + Ok(decoded_call) => { + let (output_amount0, output_amount1) = match abi::pools_contract::functions::CollectProtocol::output(&call.return_data) { + Ok((output_amount0, output_amount1)) => {(output_amount0, output_amount1)} + Err(_) => Default::default(), + }; + + Some(contract::PoolsCollectProtocolCall { + call_tx_hash: Hex(&tx.hash).to_string(), + call_block_time: Some(blk.timestamp().to_owned()), + call_block_number: blk.number, + call_ordinal: call.begin_ordinal, + call_success: !call.state_reverted, + call_address: Hex(&call.address).to_string(), + amount0_requested: decoded_call.amount0_requested.to_string(), + amount1_requested: decoded_call.amount1_requested.to_string(), + output_amount0: output_amount0.to_string(), + output_amount1: output_amount1.to_string(), + recipient: decoded_call.recipient, + }) + }, + Err(_) => None, + } + }) + }) + .collect()); + calls.pools_call_flashes.append(&mut blk + .transactions() + .flat_map(|tx| { + tx.calls.iter() + .filter(|call| is_declared_dds_address(&call.address, call.begin_ordinal, dds_store) && abi::pools_contract::functions::Flash::match_call(call)) + .filter_map(|call| { + match abi::pools_contract::functions::Flash::decode(call) { + Ok(decoded_call) => { + Some(contract::PoolsFlashCall { + call_tx_hash: Hex(&tx.hash).to_string(), + call_block_time: Some(blk.timestamp().to_owned()), + call_block_number: blk.number, + call_ordinal: call.begin_ordinal, + call_success: !call.state_reverted, + call_address: Hex(&call.address).to_string(), + amount0: decoded_call.amount0.to_string(), + amount1: decoded_call.amount1.to_string(), + data: decoded_call.data, + recipient: decoded_call.recipient, + }) + }, + Err(_) => None, + } + }) + }) + .collect()); + calls.pools_call_increase_observation_cardinality_nexts.append(&mut blk + .transactions() + .flat_map(|tx| { + tx.calls.iter() + .filter(|call| is_declared_dds_address(&call.address, call.begin_ordinal, dds_store) && abi::pools_contract::functions::IncreaseObservationCardinalityNext::match_call(call)) + .filter_map(|call| { + match abi::pools_contract::functions::IncreaseObservationCardinalityNext::decode(call) { + Ok(decoded_call) => { + Some(contract::PoolsIncreaseObservationCardinalityNextCall { + call_tx_hash: Hex(&tx.hash).to_string(), + call_block_time: Some(blk.timestamp().to_owned()), + call_block_number: blk.number, + call_ordinal: call.begin_ordinal, + call_success: !call.state_reverted, + call_address: Hex(&call.address).to_string(), + observation_cardinality_next: decoded_call.observation_cardinality_next.to_u64(), + }) + }, + Err(_) => None, + } + }) + }) + .collect()); + calls.pools_call_initializes.append(&mut blk + .transactions() + .flat_map(|tx| { + tx.calls.iter() + .filter(|call| is_declared_dds_address(&call.address, call.begin_ordinal, dds_store) && abi::pools_contract::functions::Initialize::match_call(call)) + .filter_map(|call| { + match abi::pools_contract::functions::Initialize::decode(call) { + Ok(decoded_call) => { + Some(contract::PoolsInitializeCall { + call_tx_hash: Hex(&tx.hash).to_string(), + call_block_time: Some(blk.timestamp().to_owned()), + call_block_number: blk.number, + call_ordinal: call.begin_ordinal, + call_success: !call.state_reverted, + call_address: Hex(&call.address).to_string(), + sqrt_price_x96: decoded_call.sqrt_price_x96.to_string(), + }) + }, + Err(_) => None, + } + }) + }) + .collect()); + calls.pools_call_mints.append(&mut blk + .transactions() + .flat_map(|tx| { + tx.calls.iter() + .filter(|call| is_declared_dds_address(&call.address, call.begin_ordinal, dds_store) && abi::pools_contract::functions::Mint::match_call(call)) + .filter_map(|call| { + match abi::pools_contract::functions::Mint::decode(call) { + Ok(decoded_call) => { + let (output_amount0, output_amount1) = match abi::pools_contract::functions::Mint::output(&call.return_data) { + Ok((output_amount0, output_amount1)) => {(output_amount0, output_amount1)} + Err(_) => Default::default(), + }; + + Some(contract::PoolsMintCall { + call_tx_hash: Hex(&tx.hash).to_string(), + call_block_time: Some(blk.timestamp().to_owned()), + call_block_number: blk.number, + call_ordinal: call.begin_ordinal, + call_success: !call.state_reverted, + call_address: Hex(&call.address).to_string(), + amount: decoded_call.amount.to_string(), + data: decoded_call.data, + output_amount0: output_amount0.to_string(), + output_amount1: output_amount1.to_string(), + recipient: decoded_call.recipient, + tick_lower: Into::::into(decoded_call.tick_lower).to_i64().unwrap(), + tick_upper: Into::::into(decoded_call.tick_upper).to_i64().unwrap(), + }) + }, + Err(_) => None, + } + }) + }) + .collect()); + calls.pools_call_set_fee_protocols.append(&mut blk + .transactions() + .flat_map(|tx| { + tx.calls.iter() + .filter(|call| is_declared_dds_address(&call.address, call.begin_ordinal, dds_store) && abi::pools_contract::functions::SetFeeProtocol::match_call(call)) + .filter_map(|call| { + match abi::pools_contract::functions::SetFeeProtocol::decode(call) { + Ok(decoded_call) => { + Some(contract::PoolsSetFeeProtocolCall { + call_tx_hash: Hex(&tx.hash).to_string(), + call_block_time: Some(blk.timestamp().to_owned()), + call_block_number: blk.number, + call_ordinal: call.begin_ordinal, + call_success: !call.state_reverted, + call_address: Hex(&call.address).to_string(), + fee_protocol0: decoded_call.fee_protocol0.to_u64(), + fee_protocol1: decoded_call.fee_protocol1.to_u64(), + }) + }, + Err(_) => None, + } + }) + }) + .collect()); + calls.pools_call_swaps.append(&mut blk + .transactions() + .flat_map(|tx| { + tx.calls.iter() + .filter(|call| is_declared_dds_address(&call.address, call.begin_ordinal, dds_store) && abi::pools_contract::functions::Swap::match_call(call)) + .filter_map(|call| { + match abi::pools_contract::functions::Swap::decode(call) { + Ok(decoded_call) => { + let (output_amount0, output_amount1) = match abi::pools_contract::functions::Swap::output(&call.return_data) { + Ok((output_amount0, output_amount1)) => {(output_amount0, output_amount1)} + Err(_) => Default::default(), + }; + + Some(contract::PoolsSwapCall { + call_tx_hash: Hex(&tx.hash).to_string(), + call_block_time: Some(blk.timestamp().to_owned()), + call_block_number: blk.number, + call_ordinal: call.begin_ordinal, + call_success: !call.state_reverted, + call_address: Hex(&call.address).to_string(), + amount_specified: decoded_call.amount_specified.to_string(), + data: decoded_call.data, + output_amount0: output_amount0.to_string(), + output_amount1: output_amount1.to_string(), + recipient: decoded_call.recipient, + sqrt_price_limit_x96: decoded_call.sqrt_price_limit_x96.to_string(), + zero_for_one: decoded_call.zero_for_one, + }) + }, + Err(_) => None, + } + }) + }) + .collect()); +} + + +#[substreams::handlers::store] +fn store_pools_created(blk: eth::Block, store: StoreSetInt64) { + for rcpt in blk.receipts() { + for log in rcpt + .receipt + .logs + .iter() + .filter(|log| log.address == FACTORY_TRACKED_CONTRACT) + { + if let Some(event) = abi::factory_contract::events::PoolCreated::match_and_decode(log) { + store.set(log.ordinal, Hex(event.pool).to_string(), &1); + } + } + } +} +#[substreams::handlers::map] +fn map_events( + blk: eth::Block, + store_pools: StoreGetInt64, +) -> Result { + let mut events = contract::Events::default(); + map_factory_events(&blk, &mut events); + map_pools_events(&blk, &store_pools, &mut events); + substreams::skip_empty_output(); + Ok(events) +} +#[substreams::handlers::map] +fn map_calls( + blk: eth::Block, + store_pools: StoreGetInt64, + +) -> Result { +let mut calls = contract::Calls::default(); + map_factory_calls(&blk, &mut calls); + map_pools_calls(&blk, &store_pools, &mut calls); + substreams::skip_empty_output(); + Ok(calls) +} + diff --git a/injective-events/templates/Cargo.toml.gotmpl b/injective-events/templates/Cargo.toml.gotmpl index 89785ce..f71cfcc 100644 --- a/injective-events/templates/Cargo.toml.gotmpl +++ b/injective-events/templates/Cargo.toml.gotmpl @@ -14,7 +14,7 @@ strip = "debuginfo" crate-type = ["cdylib"] [dependencies] -substreams = "^0.5.19" +substreams = "0.5.21" substreams-database-change = "1" hex = "0.4.3" prost = "0.11" diff --git a/injective-events/templates/lib.rs.gotmpl b/injective-events/templates/lib.rs.gotmpl index 576a77a..ba914d8 100644 --- a/injective-events/templates/lib.rs.gotmpl +++ b/injective-events/templates/lib.rs.gotmpl @@ -10,6 +10,7 @@ fn db_out(events: EventList) -> Result Result