From 9e8e360889498ae88f722c80e71d830f0e7ac86d Mon Sep 17 00:00:00 2001 From: Zizou <111426680+zizou0x@users.noreply.github.com> Date: Thu, 7 Nov 2024 06:16:55 +0100 Subject: [PATCH] refactor(substreams): improve logic to ignore updates (#96) * refactor(substreams): ignore transaction if contracts update are ignored. There are some cases where we ignore contracts updates (for example if the old and new values are the same). In that case if the transaction only contains ignored updates we don't emit it. * refactor(substreams): ignore deletions for freshly created attributes. There are cases where an attribute can be created and deleted during the same transaction. To avoid sending a confusing deletion for something that was never created before, we just ignore the deletion in that particular case. * feat(substreams): Add uniswap V3 logs only module (#98) * feat(substreams): add uniswapV3 logs only Substreams module * refactor(substreams): encode everything as big endian * refactor(substreams): mark changes as creation when a tick liq is updated from 0 This will allow the SDK to detect cases where a tick is created and deleted in the same transaction and ignore it. * ci(substreams): ignore built files for uniswapv3 logs only module and clean code * refactor(substreams): update uniswapv3 substreams with new SDK interface * feat(subtreams): emit default token balances value for uniswapv3 --------- Co-authored-by: zizou <111426680+flopell@users.noreply.github.com> --------- Co-authored-by: zizou <111426680+flopell@users.noreply.github.com> --- substreams/Cargo.lock | 92 +- substreams/Cargo.toml | 3 +- .../crates/tycho-substreams/src/contract.rs | 2 +- .../crates/tycho-substreams/src/models.rs | 180 +- .../ethereum-uniswap-v3-logs-only/Cargo.toml | 30 + .../ethereum-uniswap-v3-logs-only/Makefile | 2 + .../abi/Factory.json | 198 + .../abi/Pool.json | 988 ++++ .../buf.gen.yaml | 12 + .../ethereum-uniswap-v3-logs-only/build.rs | 12 + .../ethereum-uniswap-v3.yaml | 125 + .../proto/v1/uniswap.proto | 177 + .../src/abi/factory.rs | 1040 ++++ .../src/abi/mod.rs | 4 + .../src/abi/pool.rs | 5153 +++++++++++++++++ .../ethereum-uniswap-v3-logs-only/src/lib.rs | 7 + .../src/modules/1_map_pool_created.rs | 114 + .../src/modules/2_store_pools.rs | 24 + .../src/modules/3_map_events.rs | 183 + .../4_map_and_store_balance_changes.rs | 175 + .../src/modules/4_map_and_store_liquidity.rs | 137 + .../src/modules/4_map_and_store_ticks.rs | 91 + .../src/modules/5_map_protocol_changes.rs | 248 + .../src/modules/mod.rs | 39 + .../src/pb/mod.rs | 8 + .../src/pb/uniswap.v3.rs | 298 + substreams/rustfmt.toml | 1 + 27 files changed, 9300 insertions(+), 43 deletions(-) create mode 100644 substreams/ethereum-uniswap-v3-logs-only/Cargo.toml create mode 100644 substreams/ethereum-uniswap-v3-logs-only/Makefile create mode 100644 substreams/ethereum-uniswap-v3-logs-only/abi/Factory.json create mode 100644 substreams/ethereum-uniswap-v3-logs-only/abi/Pool.json create mode 100644 substreams/ethereum-uniswap-v3-logs-only/buf.gen.yaml create mode 100644 substreams/ethereum-uniswap-v3-logs-only/build.rs create mode 100644 substreams/ethereum-uniswap-v3-logs-only/ethereum-uniswap-v3.yaml create mode 100644 substreams/ethereum-uniswap-v3-logs-only/proto/v1/uniswap.proto create mode 100644 substreams/ethereum-uniswap-v3-logs-only/src/abi/factory.rs create mode 100644 substreams/ethereum-uniswap-v3-logs-only/src/abi/mod.rs create mode 100644 substreams/ethereum-uniswap-v3-logs-only/src/abi/pool.rs create mode 100644 substreams/ethereum-uniswap-v3-logs-only/src/lib.rs create mode 100644 substreams/ethereum-uniswap-v3-logs-only/src/modules/1_map_pool_created.rs create mode 100644 substreams/ethereum-uniswap-v3-logs-only/src/modules/2_store_pools.rs create mode 100644 substreams/ethereum-uniswap-v3-logs-only/src/modules/3_map_events.rs create mode 100644 substreams/ethereum-uniswap-v3-logs-only/src/modules/4_map_and_store_balance_changes.rs create mode 100644 substreams/ethereum-uniswap-v3-logs-only/src/modules/4_map_and_store_liquidity.rs create mode 100644 substreams/ethereum-uniswap-v3-logs-only/src/modules/4_map_and_store_ticks.rs create mode 100644 substreams/ethereum-uniswap-v3-logs-only/src/modules/5_map_protocol_changes.rs create mode 100644 substreams/ethereum-uniswap-v3-logs-only/src/modules/mod.rs create mode 100644 substreams/ethereum-uniswap-v3-logs-only/src/pb/mod.rs create mode 100644 substreams/ethereum-uniswap-v3-logs-only/src/pb/uniswap.v3.rs diff --git a/substreams/Cargo.lock b/substreams/Cargo.lock index 98088a6..1b18755 100644 --- a/substreams/Cargo.lock +++ b/substreams/Cargo.lock @@ -347,6 +347,26 @@ dependencies = [ "tycho-substreams", ] +[[package]] +name = "ethereum-uniswap-v3-logs-only" +version = "0.1.0" +dependencies = [ + "anyhow", + "ethabi 18.0.0", + "getrandom", + "hex", + "hex-literal 0.4.1", + "itertools 0.13.0", + "num-bigint", + "prost 0.11.9", + "substreams", + "substreams-entity-change", + "substreams-ethereum", + "substreams-helper", + "tiny-keccak", + "tycho-substreams", +] + [[package]] name = "fastrand" version = "2.0.1" @@ -660,6 +680,51 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pest" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "pest_meta" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "petgraph" version = "0.6.4" @@ -968,6 +1033,17 @@ dependencies = [ "thiserror", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha3" version = "0.10.8" @@ -986,9 +1062,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "substreams" -version = "0.5.13" +version = "0.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3520661f782c338f0e3c6cfc001ac790ed5e68d8f28515139e2aa674f8bb54da" +checksum = "92e47e531af83a3cbb78c627ee8232a0ac86604f11c89e34bd4b721ec41e03e5" dependencies = [ "anyhow", "bigdecimal", @@ -998,6 +1074,8 @@ dependencies = [ "num-integer", "num-traits", "pad", + "pest", + "pest_derive", "prost 0.11.9", "prost-build", "prost-types 0.11.9", @@ -1141,9 +1219,9 @@ dependencies = [ [[package]] name = "substreams-macro" -version = "0.5.13" +version = "0.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c15595ceab80fece579e462d4823048fe85d67922584c681f5e94305727ad9ee" +checksum = "a4ac77f08d723dace35739d65df8ed122f6d04e2a3e47929831d4021e3339240" dependencies = [ "proc-macro2", "quote", @@ -1258,6 +1336,12 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "uint" version = "0.9.5" diff --git a/substreams/Cargo.toml b/substreams/Cargo.toml index 4387a24..9a6ed0d 100644 --- a/substreams/Cargo.toml +++ b/substreams/Cargo.toml @@ -9,13 +9,14 @@ members = [ "ethereum-uniswap-v3", "ethereum-sfrax", "ethereum-sfraxeth", + "ethereum-uniswap-v3-logs-only", ] resolver = "2" [workspace.dependencies] substreams-ethereum = "0.9.9" -substreams = "0.5" +substreams = "0.5.22" prost = "0.11" prost-types = "0.12.3" hex-literal = "0.4.1" diff --git a/substreams/crates/tycho-substreams/src/contract.rs b/substreams/crates/tycho-substreams/src/contract.rs index 9e35120..5a49716 100644 --- a/substreams/crates/tycho-substreams/src/contract.rs +++ b/substreams/crates/tycho-substreams/src/contract.rs @@ -59,7 +59,7 @@ pub fn extract_contract_changes bool>( changed_contracts .clone() .into_values() - .map(|change| change.into()), + .filter_map(|change| change.into()), ); }) } diff --git a/substreams/crates/tycho-substreams/src/models.rs b/substreams/crates/tycho-substreams/src/models.rs index 359b2af..969710e 100644 --- a/substreams/crates/tycho-substreams/src/models.rs +++ b/substreams/crates/tycho-substreams/src/models.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use substreams_ethereum::pb::eth::v2::{self as sf, StorageChange}; // re-export the protobuf types here. @@ -114,6 +114,13 @@ impl TransactionChangesBuilder { .into_iter() .map(|a| (a.name.clone(), a)) .collect(), + created_attributes: change + .attributes + .clone() + .iter() + .filter(|&attr| (attr.change == i32::from(ChangeType::Creation))) + .map(|attr| attr.name.clone()) + .collect(), }); } @@ -141,34 +148,31 @@ impl TransactionChangesBuilder { } pub fn build(self) -> Option { - if self.contract_changes.is_empty() && - self.component_changes.is_empty() && - self.balance_changes.is_empty() && - self.entity_changes.is_empty() - { + let tx_changes = TransactionChanges { + tx: self.tx, + contract_changes: self + .contract_changes + .into_values() + .filter_map(|interim| interim.into()) + .collect::>(), + entity_changes: self + .entity_changes + .into_values() + .filter_map(|interim| interim.into()) + .collect::>(), + component_changes: self + .component_changes + .into_values() + .collect::>(), + balance_changes: self + .balance_changes + .into_values() + .collect::>(), + }; + if tx_changes.is_empty() { None } else { - Some(TransactionChanges { - tx: self.tx, - contract_changes: self - .contract_changes - .into_values() - .map(|interim| interim.into()) - .collect::>(), - entity_changes: self - .entity_changes - .into_values() - .map(|interim| interim.into()) - .collect::>(), - component_changes: self - .component_changes - .into_values() - .collect::>(), - balance_changes: self - .balance_changes - .into_values() - .collect::>(), - }) + Some(tx_changes) } } } @@ -389,6 +393,8 @@ impl ProtocolComponent { pub struct InterimEntityChanges { component_id: String, attributes: HashMap, + /// A set of created attributes during this transaction + created_attributes: HashSet, } impl InterimEntityChanges { @@ -397,26 +403,45 @@ impl InterimEntityChanges { } pub fn set_attribute(&mut self, attr: &Attribute) { - self.attributes - .entry(attr.name.clone()) - .and_modify(|existing| *existing = attr.clone()) - .or_insert(attr.clone()); + // Add any attribute creation to the map + if attr.change == i32::from(ChangeType::Creation) { + self.created_attributes + .insert(attr.name.clone()); + } + + if attr.change == i32::from(ChangeType::Deletion) && + self.created_attributes + .contains(&attr.name) + { + // If a freshly created attribute is deleted, remove the creation. + self.attributes.remove(&attr.name); + } else { + self.attributes + .entry(attr.name.clone()) + .and_modify(|existing| *existing = attr.clone()) + .or_insert(attr.clone()); + } } } -impl From for EntityChanges { +impl From for Option { fn from(value: InterimEntityChanges) -> Self { - EntityChanges { + let changes = EntityChanges { component_id: value.component_id.clone(), attributes: value .attributes .into_values() .collect::>(), + }; + if changes.attributes.is_empty() { + None + } else { + Some(changes) } } } -#[derive(Clone)] +#[derive(Clone, Debug)] struct SlotValue { new_value: Vec, start_value: Vec, @@ -435,7 +460,7 @@ impl From<&StorageChange> for SlotValue { } // Uses a map for slots, protobuf does not allow bytes in hashmap keys -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct InterimContractChange { address: Vec, balance: Vec, @@ -492,9 +517,9 @@ impl InterimContractChange { } } -impl From for ContractChange { +impl From for Option { fn from(value: InterimContractChange) -> Self { - ContractChange { + let contract_change = ContractChange { address: value.address, balance: value.balance, code: value.code, @@ -505,6 +530,87 @@ impl From for ContractChange { .map(|(slot, value)| ContractSlot { slot, value: value.new_value }) .collect(), change: value.change.into(), + }; + if contract_change.is_empty() { + None + } else { + Some(contract_change) } } } + +impl ContractChange { + fn is_empty(&self) -> bool { + self.balance.is_empty() && + self.slots.is_empty() && + self.code.is_empty() && + self.change == i32::from(ChangeType::Update) + } +} + +impl TransactionChanges { + fn is_empty(&self) -> bool { + self.contract_changes.is_empty() && + self.component_changes.is_empty() && + self.balance_changes.is_empty() && + self.entity_changes.is_empty() + } +} + +#[cfg(test)] +mod test { + use substreams_ethereum::pb::eth::v2::StorageChange; + + use crate::models::{Attribute, ChangeType, EntityChanges}; + + use super::{InterimContractChange, TransactionChangesBuilder}; + + #[test] + fn test_transaction_changes_builder_ignored_contract_changes() { + let mut builder = TransactionChangesBuilder::new(&super::Transaction::default()); + let mut contract_changes = InterimContractChange::new(&[1], false); + contract_changes.upsert_slot(&StorageChange { + address: [1].to_vec(), + key: [0].to_vec(), + old_value: [1].to_vec(), + new_value: [1].to_vec(), //Same old and new value, must be ignored + ordinal: 1, + }); + builder.add_contract_changes(&contract_changes); + + let tx_changes = builder.build(); + assert!(tx_changes.is_none()); + } + + #[test] + fn test_transaction_changes_builder_ignored_deletion() { + let mut builder = TransactionChangesBuilder::new(&super::Transaction::default()); + + // Create an attribute + let changes = EntityChanges { + component_id: "component".to_string(), + attributes: vec![Attribute { + name: "attribute".to_string(), + value: vec![1], + change: ChangeType::Creation.into(), + }], + }; + + builder.add_entity_change(&changes); + + // Delete the attribute + let changes = EntityChanges { + component_id: "component".to_string(), + attributes: vec![Attribute { + name: "attribute".to_string(), + value: vec![0], + change: ChangeType::Deletion.into(), + }], + }; + + builder.add_entity_change(&changes); + + let tx_changes = builder.build(); + assert!(tx_changes.is_none()); + } +} diff --git a/substreams/ethereum-uniswap-v3-logs-only/Cargo.toml b/substreams/ethereum-uniswap-v3-logs-only/Cargo.toml new file mode 100644 index 0000000..94e5f67 --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "ethereum-uniswap-v3-logs-only" +version = "0.1.0" +edition = "2021" + +[lib] +name = "ethereum_uniswap_v3_logs_only" +crate-type = ["cdylib"] + +[dependencies] +substreams.workspace = true +substreams-ethereum.workspace = true +prost.workspace = true +ethabi.workspace = true +anyhow = { workspace = true, features = [] } +hex-literal.workspace = true +substreams-helper.workspace = true +tycho-substreams.workspace = true +num-bigint = "0.4.4" +hex.workspace = true +tiny-keccak = "2.0" +substreams-entity-change = "1.3" +itertools = "0.13.0" + +[target.wasm32-unknown-unknown.dependencies] +getrandom = { version = "0.2", features = ["custom"] } + +[build-dependencies] +anyhow.workspace = true +substreams-ethereum.workspace = true diff --git a/substreams/ethereum-uniswap-v3-logs-only/Makefile b/substreams/ethereum-uniswap-v3-logs-only/Makefile new file mode 100644 index 0000000..a6fcb34 --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/Makefile @@ -0,0 +1,2 @@ +build: + cargo build --target wasm32-unknown-unknown --profile substreams \ No newline at end of file diff --git a/substreams/ethereum-uniswap-v3-logs-only/abi/Factory.json b/substreams/ethereum-uniswap-v3-logs-only/abi/Factory.json new file mode 100644 index 0000000..633c8d5 --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/abi/Factory.json @@ -0,0 +1,198 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint24", + "name": "fee", + "type": "uint24" + }, + { + "indexed": true, + "internalType": "int24", + "name": "tickSpacing", + "type": "int24" + } + ], + "name": "FeeAmountEnabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnerChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token0", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token1", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint24", + "name": "fee", + "type": "uint24" + }, + { + "indexed": false, + "internalType": "int24", + "name": "tickSpacing", + "type": "int24" + }, + { + "indexed": false, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint24", + "name": "fee", + "type": "uint24" + } + ], + "name": "createPool", + "outputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint24", + "name": "fee", + "type": "uint24" + }, + { + "internalType": "int24", + "name": "tickSpacing", + "type": "int24" + } + ], + "name": "enableFeeAmount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint24", + "name": "fee", + "type": "uint24" + } + ], + "name": "feeAmountTickSpacing", + "outputs": [ + { + "internalType": "int24", + "name": "", + "type": "int24" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint24", + "name": "fee", + "type": "uint24" + } + ], + "name": "getPool", + "outputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/substreams/ethereum-uniswap-v3-logs-only/abi/Pool.json b/substreams/ethereum-uniswap-v3-logs-only/abi/Pool.json new file mode 100644 index 0000000..6dd2066 --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/abi/Pool.json @@ -0,0 +1,988 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "indexed": true, + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "amount", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "name": "Burn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": true, + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "indexed": true, + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "amount0", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "amount1", + "type": "uint128" + } + ], + "name": "Collect", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "amount0", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "amount1", + "type": "uint128" + } + ], + "name": "CollectProtocol", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "paid0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "paid1", + "type": "uint256" + } + ], + "name": "Flash", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint16", + "name": "observationCardinalityNextOld", + "type": "uint16" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "observationCardinalityNextNew", + "type": "uint16" + } + ], + "name": "IncreaseObservationCardinalityNext", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint160", + "name": "sqrtPriceX96", + "type": "uint160" + }, + { + "indexed": false, + "internalType": "int24", + "name": "tick", + "type": "int24" + } + ], + "name": "Initialize", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "indexed": true, + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "amount", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "feeProtocol0Old", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "feeProtocol1Old", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "feeProtocol0New", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "feeProtocol1New", + "type": "uint8" + } + ], + "name": "SetFeeProtocol", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "int256", + "name": "amount0", + "type": "int256" + }, + { + "indexed": false, + "internalType": "int256", + "name": "amount1", + "type": "int256" + }, + { + "indexed": false, + "internalType": "uint160", + "name": "sqrtPriceX96", + "type": "uint160" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "liquidity", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "int24", + "name": "tick", + "type": "int24" + } + ], + "name": "Swap", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "internalType": "uint128", + "name": "amount", + "type": "uint128" + } + ], + "name": "burn", + "outputs": [ + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "internalType": "uint128", + "name": "amount0Requested", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "amount1Requested", + "type": "uint128" + } + ], + "name": "collect", + "outputs": [ + { + "internalType": "uint128", + "name": "amount0", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "amount1", + "type": "uint128" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint128", + "name": "amount0Requested", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "amount1Requested", + "type": "uint128" + } + ], + "name": "collectProtocol", + "outputs": [ + { + "internalType": "uint128", + "name": "amount0", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "amount1", + "type": "uint128" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "fee", + "outputs": [ + { + "internalType": "uint24", + "name": "", + "type": "uint24" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeGrowthGlobal0X128", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeGrowthGlobal1X128", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "flash", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "observationCardinalityNext", + "type": "uint16" + } + ], + "name": "increaseObservationCardinalityNext", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint160", + "name": "sqrtPriceX96", + "type": "uint160" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "liquidity", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxLiquidityPerTick", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "internalType": "uint128", + "name": "amount", + "type": "uint128" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "mint", + "outputs": [ + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "observations", + "outputs": [ + { + "internalType": "uint32", + "name": "blockTimestamp", + "type": "uint32" + }, + { + "internalType": "int56", + "name": "tickCumulative", + "type": "int56" + }, + { + "internalType": "uint160", + "name": "secondsPerLiquidityCumulativeX128", + "type": "uint160" + }, + { + "internalType": "bool", + "name": "initialized", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32[]", + "name": "secondsAgos", + "type": "uint32[]" + } + ], + "name": "observe", + "outputs": [ + { + "internalType": "int56[]", + "name": "tickCumulatives", + "type": "int56[]" + }, + { + "internalType": "uint160[]", + "name": "secondsPerLiquidityCumulativeX128s", + "type": "uint160[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "key", + "type": "bytes32" + } + ], + "name": "positions", + "outputs": [ + { + "internalType": "uint128", + "name": "_liquidity", + "type": "uint128" + }, + { + "internalType": "uint256", + "name": "feeGrowthInside0LastX128", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "feeGrowthInside1LastX128", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "tokensOwed0", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "tokensOwed1", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "protocolFees", + "outputs": [ + { + "internalType": "uint128", + "name": "token0", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "token1", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "feeProtocol0", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "feeProtocol1", + "type": "uint8" + } + ], + "name": "setFeeProtocol", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "slot0", + "outputs": [ + { + "internalType": "uint160", + "name": "sqrtPriceX96", + "type": "uint160" + }, + { + "internalType": "int24", + "name": "tick", + "type": "int24" + }, + { + "internalType": "uint16", + "name": "observationIndex", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "observationCardinality", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "observationCardinalityNext", + "type": "uint16" + }, + { + "internalType": "uint8", + "name": "feeProtocol", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "unlocked", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + } + ], + "name": "snapshotCumulativesInside", + "outputs": [ + { + "internalType": "int56", + "name": "tickCumulativeInside", + "type": "int56" + }, + { + "internalType": "uint160", + "name": "secondsPerLiquidityInsideX128", + "type": "uint160" + }, + { + "internalType": "uint32", + "name": "secondsInside", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "bool", + "name": "zeroForOne", + "type": "bool" + }, + { + "internalType": "int256", + "name": "amountSpecified", + "type": "int256" + }, + { + "internalType": "uint160", + "name": "sqrtPriceLimitX96", + "type": "uint160" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "swap", + "outputs": [ + { + "internalType": "int256", + "name": "amount0", + "type": "int256" + }, + { + "internalType": "int256", + "name": "amount1", + "type": "int256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int16", + "name": "wordPosition", + "type": "int16" + } + ], + "name": "tickBitmap", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "tickSpacing", + "outputs": [ + { + "internalType": "int24", + "name": "", + "type": "int24" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int24", + "name": "tick", + "type": "int24" + } + ], + "name": "ticks", + "outputs": [ + { + "internalType": "uint128", + "name": "liquidityGross", + "type": "uint128" + }, + { + "internalType": "int128", + "name": "liquidityNet", + "type": "int128" + }, + { + "internalType": "uint256", + "name": "feeGrowthOutside0X128", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "feeGrowthOutside1X128", + "type": "uint256" + }, + { + "internalType": "int56", + "name": "tickCumulativeOutside", + "type": "int56" + }, + { + "internalType": "uint160", + "name": "secondsPerLiquidityOutsideX128", + "type": "uint160" + }, + { + "internalType": "uint32", + "name": "secondsOutside", + "type": "uint32" + }, + { + "internalType": "bool", + "name": "initialized", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "token0", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "token1", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/substreams/ethereum-uniswap-v3-logs-only/buf.gen.yaml b/substreams/ethereum-uniswap-v3-logs-only/buf.gen.yaml new file mode 100644 index 0000000..d2e6544 --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/buf.gen.yaml @@ -0,0 +1,12 @@ + +version: v1 +plugins: +- plugin: buf.build/community/neoeinstein-prost:v0.2.2 + out: src/pb + opt: + - file_descriptor_set=false + +- plugin: buf.build/community/neoeinstein-prost-crate:v0.3.1 + out: src/pb + opt: + - no_features diff --git a/substreams/ethereum-uniswap-v3-logs-only/build.rs b/substreams/ethereum-uniswap-v3-logs-only/build.rs new file mode 100644 index 0000000..7992bb0 --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/build.rs @@ -0,0 +1,12 @@ +use anyhow::{Ok, Result}; +use substreams_ethereum::Abigen; + +fn main() -> Result<(), anyhow::Error> { + Abigen::new("Factory", "abi/Factory.json")? + .generate()? + .write_to_file("src/abi/factory.rs")?; + Abigen::new("Pool", "abi/Pool.json")? + .generate()? + .write_to_file("src/abi/pool.rs")?; + Ok(()) +} diff --git a/substreams/ethereum-uniswap-v3-logs-only/ethereum-uniswap-v3.yaml b/substreams/ethereum-uniswap-v3-logs-only/ethereum-uniswap-v3.yaml new file mode 100644 index 0000000..24eafc3 --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/ethereum-uniswap-v3.yaml @@ -0,0 +1,125 @@ +specVersion: v0.1.0 +package: + name: "ethereum_uniswap_v3_logs_only" + version: v0.1.0 + +protobuf: + files: + - tycho/evm/v1/entity.proto + - tycho/evm/v1/common.proto + - tycho/evm/v1/utils.proto + - uniswap.proto + importPaths: + - ./proto/v1 + - ../../proto/ + +binaries: + default: + type: wasm/rust-v1 + file: ../target/wasm32-unknown-unknown/release/ethereum_uniswap_v3_logs_only.wasm + +modules: + - name: map_pools_created + kind: map + initialBlock: 12369621 + inputs: + - params: string + - source: sf.ethereum.type.v2.Block + output: + type: proto:tycho.evm.v1.BlockEntityChanges + + - name: store_pools + kind: store + initialBlock: 12369621 + updatePolicy: set_if_not_exists + valueType: proto:uniswap.v3.Pool + inputs: + - map: map_pools_created + + - name: map_events + kind: map + initialBlock: 12369621 + inputs: + - source: sf.ethereum.type.v2.Block + - store: store_pools + output: + type: proto:uniswap.v3.Events + + - name: map_balance_changes + kind: map + initialBlock: 12369621 + inputs: + - map: map_events + output: + type: proto:tycho.evm.v1.BlockBalanceDeltas + + - name: store_pools_balances + kind: store + initialBlock: 12369621 + updatePolicy: add + valueType: bigint + inputs: + - map: map_balance_changes + + - name: map_ticks_changes + kind: map + initialBlock: 12369621 + inputs: + - map: map_events + output: + type: proto:uniswap.v3.TickDeltas + + - name: store_ticks_liquidity + kind: store + initialBlock: 12369621 + updatePolicy: add + valueType: bigint + inputs: + - map: map_ticks_changes + + - name: store_pool_current_tick + kind: store + initialBlock: 12369621 + updatePolicy: set + valueType: int64 + inputs: + - map: map_events + + - name: map_liquidity_changes + kind: map + initialBlock: 12369621 + inputs: + - map: map_events + - store: store_pool_current_tick + output: + type: proto:uniswap.v3.LiquidityChanges + + - name: store_liquidity + kind: store + initialBlock: 12369621 + updatePolicy: set_sum + valueType: bigint + inputs: + - map: map_liquidity_changes + + - name: map_protocol_changes + kind: map + initialBlock: 12369621 + inputs: + - source: sf.ethereum.type.v2.Block + - map: map_pools_created + - map: map_events + - map: map_balance_changes + - store: store_pools_balances + mode: deltas + - map: map_ticks_changes + - store: store_ticks_liquidity + mode: deltas + - map: map_liquidity_changes + - store: store_liquidity + mode: deltas + output: + type: proto:tycho.evm.v1.BlockChanges + +params: + map_pools_created: "1F98431c8aD98523631AE4a59f267346ea31F984" diff --git a/substreams/ethereum-uniswap-v3-logs-only/proto/v1/uniswap.proto b/substreams/ethereum-uniswap-v3-logs-only/proto/v1/uniswap.proto new file mode 100644 index 0000000..38320a5 --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/proto/v1/uniswap.proto @@ -0,0 +1,177 @@ +syntax = "proto3"; + +package uniswap.v3; + +message Pool { + bytes address = 1; + bytes token0 = 2; + bytes token1 = 3; + bytes created_tx_hash = 4; +} + +// A struct describing a transaction. +message Transaction { + // The transaction hash. + bytes hash = 1; + // The sender of the transaction. + bytes from = 2; + // The receiver of the transaction. + bytes to = 3; + // The transactions index within the block. + uint64 index = 4; +} + +// A change to a pool's tick. +message TickDelta { + // The address of the pool. + bytes pool_address = 1; + // The index of the tick. + int32 tick_index = 2; + // The liquidity net delta of this tick. Bigint encoded as signed little endian bytes. + bytes liquidity_net_delta = 3; + // Used to determine the order of the balance changes. Necessary for the balance store. + uint64 ordinal = 4; + Transaction transaction = 5; +} + +// A group of TickDelta +message TickDeltas { + repeated TickDelta deltas = 1; +} + +// A change to a pool's liquidity. +message LiquidityChange { + // The address of the pool. + bytes pool_address = 1; + // The liquidity changed amount. Bigint encoded as signed little endian bytes. + bytes value = 2; + // The type of update, can be absolute or delta. + LiquidityChangeType change_type = 3; + // Used to determine the order of the balance changes. Necessary for the balance store. + uint64 ordinal = 4; + Transaction transaction = 5; +} + +// A group of LiquidityChange +message LiquidityChanges { + repeated LiquidityChange changes = 1; +} + + +enum LiquidityChangeType { + DELTA = 0; + ABSOLUTE = 1; +} + +message Events { + repeated PoolEvent pool_events = 3; + + message PoolEvent { + oneof type { + Initialize initialize = 1; + Mint mint = 2; + Collect collect = 3; + Burn burn = 4; + Swap swap = 5; + Flash flash = 6; + SetFeeProtocol set_fee_protocol = 7; + CollectProtocol collect_protocol = 8; + } + uint64 log_ordinal = 100; + string pool_address = 102; + string token0 = 103; + string token1 = 104; + Transaction transaction = 105; + + message Initialize { + // Unsigned + string sqrt_price = 1; + int32 tick = 2; + } + + message Mint { + string sender = 1; + string owner = 2; + // Signed + int32 tick_lower = 3; + // Signed + int32 tick_upper = 4; + // Unsigned + string amount = 5; + // Unsigned + string amount_0 = 6; + // Unsigned + string amount_1 = 7; + } + + message Collect { + string owner = 1; + string recipient = 2; + int32 tick_lower = 3; + int32 tick_upper = 4; + // Unsigned + string amount_0 = 5; + // Unsigned + string amount_1 = 6; + } + + message Burn { + string owner = 1; + int32 tick_lower = 2; + int32 tick_upper = 3; + // Unsigned + string amount = 4; + // Unsigned + string amount_0 = 5; + // Unsigned + string amount_1 = 6; + } + + message Swap { + string sender = 1; + string recipient = 2; + // Signed + string amount_0 = 3; + // Signed + string amount_1 = 4; + // Unsigned + string sqrt_price = 6; + // Unsigned + string liquidity = 7; + int32 tick = 8; + } + + message Flash { + string sender = 1; + string recipient = 2; + // Unsigned + string amount_0 = 3; + // Unsigned + string amount_1 = 4; + // Unsigned + string paid_0 = 5; + // Unsigned + string paid_1 = 6; + } + + message SetFeeProtocol { + // Unsigned + uint64 fee_protocol_0_old = 1; + // Unsigned + uint64 fee_protocol_1_old = 2; + // Unsigned + uint64 fee_protocol_0_new = 3; + // Unsigned + uint64 fee_protocol_1_new = 4; + } + + message CollectProtocol { + string sender = 1; + string recipient = 2; + // Unsigned + string amount_0 = 3; + // Unsigned + string amount_1 = 4; + } + } +} \ No newline at end of file diff --git a/substreams/ethereum-uniswap-v3-logs-only/src/abi/factory.rs b/substreams/ethereum-uniswap-v3-logs-only/src/abi/factory.rs new file mode 100644 index 0000000..19b46de --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/src/abi/factory.rs @@ -0,0 +1,1040 @@ + const INTERNAL_ERR: &'static str = "`ethabi_derive` internal error"; + /// Contract's functions. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod functions { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct CreatePool { + pub token_a: Vec, + pub token_b: Vec, + pub fee: substreams::scalar::BigInt, + } + impl CreatePool { + const METHOD_ID: [u8; 4] = [161u8, 103u8, 18u8, 149u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Uint(24usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + token_a: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + token_b: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + fee: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.token_a), + ), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.token_b), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.fee.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for CreatePool { + const NAME: &'static str = "createPool"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for CreatePool { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct EnableFeeAmount { + pub fee: substreams::scalar::BigInt, + pub tick_spacing: substreams::scalar::BigInt, + } + impl EnableFeeAmount { + const METHOD_ID: [u8; 4] = [138u8, 124u8, 25u8, 95u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(24usize), + ethabi::ParamType::Int(24usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + fee: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tick_spacing: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.fee.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + { + let non_full_signed_bytes = self + .tick_spacing + .to_signed_bytes_be(); + let full_signed_bytes_init = if non_full_signed_bytes[0] + & 0x80 == 0x80 + { + 0xff + } else { + 0x00 + }; + let mut full_signed_bytes = [full_signed_bytes_init + as u8; 32]; + non_full_signed_bytes + .into_iter() + .rev() + .enumerate() + .for_each(|(i, byte)| full_signed_bytes[31 - i] = byte); + ethabi::Token::Int( + ethabi::Int::from_big_endian(full_signed_bytes.as_ref()), + ) + }, + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for EnableFeeAmount { + const NAME: &'static str = "enableFeeAmount"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct FeeAmountTickSpacing { + pub fee: substreams::scalar::BigInt, + } + impl FeeAmountTickSpacing { + const METHOD_ID: [u8; 4] = [34u8, 175u8, 204u8, 203u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(24usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + fee: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.fee.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Int(24usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for FeeAmountTickSpacing { + const NAME: &'static str = "feeAmountTickSpacing"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for FeeAmountTickSpacing { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPool { + pub token_a: Vec, + pub token_b: Vec, + pub fee: substreams::scalar::BigInt, + } + impl GetPool { + const METHOD_ID: [u8; 4] = [22u8, 152u8, 238u8, 130u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Uint(24usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + token_a: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + token_b: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + fee: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.token_a), + ), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.token_b), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.fee.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPool { + const NAME: &'static str = "getPool"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetPool { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Owner {} + impl Owner { + const METHOD_ID: [u8; 4] = [141u8, 165u8, 203u8, 91u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Owner { + const NAME: &'static str = "owner"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for Owner { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct SetOwner { + pub owner: Vec, + } + impl SetOwner { + const METHOD_ID: [u8; 4] = [19u8, 175u8, 64u8, 53u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + owner: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::Address(ethabi::Address::from_slice(&self.owner))], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for SetOwner { + const NAME: &'static str = "setOwner"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + } + /// Contract's events. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod events { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct FeeAmountEnabled { + pub fee: substreams::scalar::BigInt, + pub tick_spacing: substreams::scalar::BigInt, + } + impl FeeAmountEnabled { + const TOPIC_ID: [u8; 32] = [ + 198u8, + 106u8, + 63u8, + 223u8, + 7u8, + 35u8, + 44u8, + 221u8, + 24u8, + 95u8, + 235u8, + 204u8, + 101u8, + 121u8, + 212u8, + 8u8, + 194u8, + 65u8, + 180u8, + 122u8, + 226u8, + 249u8, + 144u8, + 125u8, + 132u8, + 190u8, + 101u8, + 81u8, + 65u8, + 238u8, + 174u8, + 204u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self { + fee: { + let mut v = [0 as u8; 32]; + ethabi::decode( + &[ethabi::ParamType::Uint(24usize)], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'fee' from topic of type 'uint24': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tick_spacing: substreams::scalar::BigInt::from_signed_bytes_be( + log.topics[2usize].as_ref(), + ), + }) + } + } + impl substreams_ethereum::Event for FeeAmountEnabled { + const NAME: &'static str = "FeeAmountEnabled"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct OwnerChanged { + pub old_owner: Vec, + pub new_owner: Vec, + } + impl OwnerChanged { + const TOPIC_ID: [u8; 32] = [ + 181u8, + 50u8, + 7u8, + 59u8, + 56u8, + 200u8, + 49u8, + 69u8, + 227u8, + 229u8, + 19u8, + 83u8, + 119u8, + 160u8, + 139u8, + 249u8, + 170u8, + 181u8, + 91u8, + 192u8, + 253u8, + 124u8, + 17u8, + 121u8, + 205u8, + 79u8, + 185u8, + 149u8, + 210u8, + 165u8, + 21u8, + 156u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self { + old_owner: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'old_owner' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + new_owner: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'new_owner' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + } + impl substreams_ethereum::Event for OwnerChanged { + const NAME: &'static str = "OwnerChanged"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct PoolCreated { + pub token0: Vec, + pub token1: Vec, + pub fee: substreams::scalar::BigInt, + pub tick_spacing: substreams::scalar::BigInt, + pub pool: Vec, + } + impl PoolCreated { + const TOPIC_ID: [u8; 32] = [ + 120u8, + 60u8, + 202u8, + 28u8, + 4u8, + 18u8, + 221u8, + 13u8, + 105u8, + 94u8, + 120u8, + 69u8, + 104u8, + 201u8, + 109u8, + 162u8, + 233u8, + 194u8, + 47u8, + 249u8, + 137u8, + 53u8, + 122u8, + 46u8, + 139u8, + 29u8, + 155u8, + 43u8, + 78u8, + 107u8, + 113u8, + 24u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 4usize { + return false; + } + if log.data.len() != 64usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Int(24usize), ethabi::ParamType::Address], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + token0: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'token0' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + token1: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'token1' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + fee: { + let mut v = [0 as u8; 32]; + ethabi::decode( + &[ethabi::ParamType::Uint(24usize)], + log.topics[3usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'fee' from topic of type 'uint24': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tick_spacing: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + pool: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + } + impl substreams_ethereum::Event for PoolCreated { + const NAME: &'static str = "PoolCreated"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + } \ No newline at end of file diff --git a/substreams/ethereum-uniswap-v3-logs-only/src/abi/mod.rs b/substreams/ethereum-uniswap-v3-logs-only/src/abi/mod.rs new file mode 100644 index 0000000..f743394 --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/src/abi/mod.rs @@ -0,0 +1,4 @@ +#![allow(clippy::all, clippy::pedantic, clippy::nursery)] + +pub mod factory; +pub mod pool; diff --git a/substreams/ethereum-uniswap-v3-logs-only/src/abi/pool.rs b/substreams/ethereum-uniswap-v3-logs-only/src/abi/pool.rs new file mode 100644 index 0000000..1208919 --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/src/abi/pool.rs @@ -0,0 +1,5153 @@ + const INTERNAL_ERR: &'static str = "`ethabi_derive` internal error"; + /// Contract's functions. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod functions { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct Burn { + pub tick_lower: substreams::scalar::BigInt, + pub tick_upper: substreams::scalar::BigInt, + pub amount: substreams::scalar::BigInt, + } + impl Burn { + const METHOD_ID: [u8; 4] = [163u8, 65u8, 35u8, 167u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Int(24usize), + ethabi::ParamType::Int(24usize), + ethabi::ParamType::Uint(128usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + tick_lower: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + tick_upper: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + amount: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + { + let non_full_signed_bytes = self + .tick_lower + .to_signed_bytes_be(); + let full_signed_bytes_init = if non_full_signed_bytes[0] + & 0x80 == 0x80 + { + 0xff + } else { + 0x00 + }; + let mut full_signed_bytes = [full_signed_bytes_init + as u8; 32]; + non_full_signed_bytes + .into_iter() + .rev() + .enumerate() + .for_each(|(i, byte)| full_signed_bytes[31 - i] = byte); + ethabi::Token::Int( + ethabi::Int::from_big_endian(full_signed_bytes.as_ref()), + ) + }, + { + let non_full_signed_bytes = self + .tick_upper + .to_signed_bytes_be(); + let full_signed_bytes_init = if non_full_signed_bytes[0] + & 0x80 == 0x80 + { + 0xff + } else { + 0x00 + }; + let mut full_signed_bytes = [full_signed_bytes_init + as u8; 32]; + non_full_signed_bytes + .into_iter() + .rev() + .enumerate() + .for_each(|(i, byte)| full_signed_bytes[31 - i] = byte); + ethabi::Token::Int( + ethabi::Int::from_big_endian(full_signed_bytes.as_ref()), + ) + }, + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.amount.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option<(substreams::scalar::BigInt, substreams::scalar::BigInt)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Burn { + const NAME: &'static str = "burn"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + > for Burn { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Collect { + pub recipient: Vec, + pub tick_lower: substreams::scalar::BigInt, + pub tick_upper: substreams::scalar::BigInt, + pub amount0_requested: substreams::scalar::BigInt, + pub amount1_requested: substreams::scalar::BigInt, + } + impl Collect { + const METHOD_ID: [u8; 4] = [79u8, 30u8, 179u8, 216u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Address, + ethabi::ParamType::Int(24usize), + ethabi::ParamType::Int(24usize), + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(128usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + recipient: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tick_lower: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + tick_upper: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + amount0_requested: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + amount1_requested: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.recipient), + ), + { + let non_full_signed_bytes = self + .tick_lower + .to_signed_bytes_be(); + let full_signed_bytes_init = if non_full_signed_bytes[0] + & 0x80 == 0x80 + { + 0xff + } else { + 0x00 + }; + let mut full_signed_bytes = [full_signed_bytes_init + as u8; 32]; + non_full_signed_bytes + .into_iter() + .rev() + .enumerate() + .for_each(|(i, byte)| full_signed_bytes[31 - i] = byte); + ethabi::Token::Int( + ethabi::Int::from_big_endian(full_signed_bytes.as_ref()), + ) + }, + { + let non_full_signed_bytes = self + .tick_upper + .to_signed_bytes_be(); + let full_signed_bytes_init = if non_full_signed_bytes[0] + & 0x80 == 0x80 + { + 0xff + } else { + 0x00 + }; + let mut full_signed_bytes = [full_signed_bytes_init + as u8; 32]; + non_full_signed_bytes + .into_iter() + .rev() + .enumerate() + .for_each(|(i, byte)| full_signed_bytes[31 - i] = byte); + ethabi::Token::Int( + ethabi::Int::from_big_endian(full_signed_bytes.as_ref()), + ) + }, + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.amount0_requested.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.amount1_requested.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(128usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option<(substreams::scalar::BigInt, substreams::scalar::BigInt)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Collect { + const NAME: &'static str = "collect"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + > for Collect { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct CollectProtocol { + pub recipient: Vec, + pub amount0_requested: substreams::scalar::BigInt, + pub amount1_requested: substreams::scalar::BigInt, + } + impl CollectProtocol { + const METHOD_ID: [u8; 4] = [133u8, 182u8, 103u8, 41u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(128usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + recipient: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + amount0_requested: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + amount1_requested: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.recipient), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.amount0_requested.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.amount1_requested.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(128usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option<(substreams::scalar::BigInt, substreams::scalar::BigInt)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for CollectProtocol { + const NAME: &'static str = "collectProtocol"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + > for CollectProtocol { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Factory {} + impl Factory { + const METHOD_ID: [u8; 4] = [196u8, 90u8, 1u8, 85u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Factory { + const NAME: &'static str = "factory"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for Factory { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Fee {} + impl Fee { + const METHOD_ID: [u8; 4] = [221u8, 202u8, 63u8, 67u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(24usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Fee { + const NAME: &'static str = "fee"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for Fee { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct FeeGrowthGlobal0X128 {} + impl FeeGrowthGlobal0X128 { + const METHOD_ID: [u8; 4] = [243u8, 5u8, 131u8, 153u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for FeeGrowthGlobal0X128 { + const NAME: &'static str = "feeGrowthGlobal0X128"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for FeeGrowthGlobal0X128 { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct FeeGrowthGlobal1X128 {} + impl FeeGrowthGlobal1X128 { + const METHOD_ID: [u8; 4] = [70u8, 20u8, 19u8, 25u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for FeeGrowthGlobal1X128 { + const NAME: &'static str = "feeGrowthGlobal1X128"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for FeeGrowthGlobal1X128 { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Flash { + pub recipient: Vec, + pub amount0: substreams::scalar::BigInt, + pub amount1: substreams::scalar::BigInt, + pub data: Vec, + } + impl Flash { + const METHOD_ID: [u8; 4] = [73u8, 14u8, 108u8, 188u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Address, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Bytes, + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + recipient: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + amount0: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + amount1: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + data: values + .pop() + .expect(INTERNAL_ERR) + .into_bytes() + .expect(INTERNAL_ERR), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.recipient), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.amount0.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.amount1.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Bytes(self.data.clone()), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for Flash { + const NAME: &'static str = "flash"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IncreaseObservationCardinalityNext { + pub observation_cardinality_next: substreams::scalar::BigInt, + } + impl IncreaseObservationCardinalityNext { + const METHOD_ID: [u8; 4] = [50u8, 20u8, 143u8, 103u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(16usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + observation_cardinality_next: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self + .observation_cardinality_next + .clone() + .to_bytes_be() + { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for IncreaseObservationCardinalityNext { + const NAME: &'static str = "increaseObservationCardinalityNext"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Initialize { + pub sqrt_price_x96: substreams::scalar::BigInt, + } + impl Initialize { + const METHOD_ID: [u8; 4] = [246u8, 55u8, 115u8, 29u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(160usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + sqrt_price_x96: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.sqrt_price_x96.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for Initialize { + const NAME: &'static str = "initialize"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Liquidity {} + impl Liquidity { + const METHOD_ID: [u8; 4] = [26u8, 104u8, 101u8, 2u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(128usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Liquidity { + const NAME: &'static str = "liquidity"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for Liquidity { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct MaxLiquidityPerTick {} + impl MaxLiquidityPerTick { + const METHOD_ID: [u8; 4] = [112u8, 207u8, 117u8, 74u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(128usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for MaxLiquidityPerTick { + const NAME: &'static str = "maxLiquidityPerTick"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for MaxLiquidityPerTick { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Mint { + pub recipient: Vec, + pub tick_lower: substreams::scalar::BigInt, + pub tick_upper: substreams::scalar::BigInt, + pub amount: substreams::scalar::BigInt, + pub data: Vec, + } + impl Mint { + const METHOD_ID: [u8; 4] = [60u8, 138u8, 125u8, 141u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Address, + ethabi::ParamType::Int(24usize), + ethabi::ParamType::Int(24usize), + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Bytes, + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + recipient: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tick_lower: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + tick_upper: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + amount: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + data: values + .pop() + .expect(INTERNAL_ERR) + .into_bytes() + .expect(INTERNAL_ERR), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.recipient), + ), + { + let non_full_signed_bytes = self + .tick_lower + .to_signed_bytes_be(); + let full_signed_bytes_init = if non_full_signed_bytes[0] + & 0x80 == 0x80 + { + 0xff + } else { + 0x00 + }; + let mut full_signed_bytes = [full_signed_bytes_init + as u8; 32]; + non_full_signed_bytes + .into_iter() + .rev() + .enumerate() + .for_each(|(i, byte)| full_signed_bytes[31 - i] = byte); + ethabi::Token::Int( + ethabi::Int::from_big_endian(full_signed_bytes.as_ref()), + ) + }, + { + let non_full_signed_bytes = self + .tick_upper + .to_signed_bytes_be(); + let full_signed_bytes_init = if non_full_signed_bytes[0] + & 0x80 == 0x80 + { + 0xff + } else { + 0x00 + }; + let mut full_signed_bytes = [full_signed_bytes_init + as u8; 32]; + non_full_signed_bytes + .into_iter() + .rev() + .enumerate() + .for_each(|(i, byte)| full_signed_bytes[31 - i] = byte); + ethabi::Token::Int( + ethabi::Int::from_big_endian(full_signed_bytes.as_ref()), + ) + }, + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.amount.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Bytes(self.data.clone()), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option<(substreams::scalar::BigInt, substreams::scalar::BigInt)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Mint { + const NAME: &'static str = "mint"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + > for Mint { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Observations { + pub index: substreams::scalar::BigInt, + } + impl Observations { + const METHOD_ID: [u8; 4] = [37u8, 44u8, 9u8, 215u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + index: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.index.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + bool, + ), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + bool, + ), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(32usize), + ethabi::ParamType::Int(56usize), + ethabi::ParamType::Uint(160usize), + ethabi::ParamType::Bool, + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + values.pop().expect(INTERNAL_ERR).into_bool().expect(INTERNAL_ERR), + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + bool, + ), + > { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Observations { + const NAME: &'static str = "observations"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + bool, + ), + > for Observations { + fn output( + data: &[u8], + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + bool, + ), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Observe { + pub seconds_agos: Vec, + } + impl Observe { + const METHOD_ID: [u8; 4] = [136u8, 59u8, 219u8, 253u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Uint(32usize)), + ), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + seconds_agos: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let mut v = [0 as u8; 32]; + inner + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + .collect(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + { + let v = self + .seconds_agos + .iter() + .map(|inner| ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match inner.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + )) + .collect(); + ethabi::Token::Array(v) + }, + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + (Vec, Vec), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + (Vec, Vec), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Int(56usize)), + ), + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Uint(160usize)), + ), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let mut v = [0 as u8; 32]; + inner + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }) + .collect(), + values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let mut v = [0 as u8; 32]; + inner + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + .collect(), + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option< + (Vec, Vec), + > { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Observe { + const NAME: &'static str = "observe"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (Vec, Vec), + > for Observe { + fn output( + data: &[u8], + ) -> Result< + (Vec, Vec), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Positions { + pub key: [u8; 32usize], + } + impl Positions { + const METHOD_ID: [u8; 4] = [81u8, 78u8, 164u8, 191u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + key: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::FixedBytes(self.key.as_ref().to_vec())], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(128usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + > { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Positions { + const NAME: &'static str = "positions"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + > for Positions { + fn output( + data: &[u8], + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct ProtocolFees {} + impl ProtocolFees { + const METHOD_ID: [u8; 4] = [26u8, 216u8, 176u8, 59u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(128usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option<(substreams::scalar::BigInt, substreams::scalar::BigInt)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for ProtocolFees { + const NAME: &'static str = "protocolFees"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + > for ProtocolFees { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct SetFeeProtocol { + pub fee_protocol0: substreams::scalar::BigInt, + pub fee_protocol1: substreams::scalar::BigInt, + } + impl SetFeeProtocol { + const METHOD_ID: [u8; 4] = [130u8, 6u8, 164u8, 209u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(8usize), + ethabi::ParamType::Uint(8usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + fee_protocol0: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + fee_protocol1: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.fee_protocol0.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.fee_protocol1.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for SetFeeProtocol { + const NAME: &'static str = "setFeeProtocol"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Slot0 {} + impl Slot0 { + const METHOD_ID: [u8; 4] = [56u8, 80u8, 199u8, 189u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + bool, + ), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + bool, + ), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(160usize), + ethabi::ParamType::Int(24usize), + ethabi::ParamType::Uint(16usize), + ethabi::ParamType::Uint(16usize), + ethabi::ParamType::Uint(16usize), + ethabi::ParamType::Uint(8usize), + ethabi::ParamType::Bool, + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + values.pop().expect(INTERNAL_ERR).into_bool().expect(INTERNAL_ERR), + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + bool, + ), + > { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Slot0 { + const NAME: &'static str = "slot0"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + bool, + ), + > for Slot0 { + fn output( + data: &[u8], + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + bool, + ), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct SnapshotCumulativesInside { + pub tick_lower: substreams::scalar::BigInt, + pub tick_upper: substreams::scalar::BigInt, + } + impl SnapshotCumulativesInside { + const METHOD_ID: [u8; 4] = [163u8, 136u8, 7u8, 242u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Int(24usize), + ethabi::ParamType::Int(24usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + tick_lower: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + tick_upper: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + { + let non_full_signed_bytes = self + .tick_lower + .to_signed_bytes_be(); + let full_signed_bytes_init = if non_full_signed_bytes[0] + & 0x80 == 0x80 + { + 0xff + } else { + 0x00 + }; + let mut full_signed_bytes = [full_signed_bytes_init + as u8; 32]; + non_full_signed_bytes + .into_iter() + .rev() + .enumerate() + .for_each(|(i, byte)| full_signed_bytes[31 - i] = byte); + ethabi::Token::Int( + ethabi::Int::from_big_endian(full_signed_bytes.as_ref()), + ) + }, + { + let non_full_signed_bytes = self + .tick_upper + .to_signed_bytes_be(); + let full_signed_bytes_init = if non_full_signed_bytes[0] + & 0x80 == 0x80 + { + 0xff + } else { + 0x00 + }; + let mut full_signed_bytes = [full_signed_bytes_init + as u8; 32]; + non_full_signed_bytes + .into_iter() + .rev() + .enumerate() + .for_each(|(i, byte)| full_signed_bytes[31 - i] = byte); + ethabi::Token::Int( + ethabi::Int::from_big_endian(full_signed_bytes.as_ref()), + ) + }, + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Int(56usize), + ethabi::ParamType::Uint(160usize), + ethabi::ParamType::Uint(32usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + > { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for SnapshotCumulativesInside { + const NAME: &'static str = "snapshotCumulativesInside"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + > for SnapshotCumulativesInside { + fn output( + data: &[u8], + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Swap { + pub recipient: Vec, + pub zero_for_one: bool, + pub amount_specified: substreams::scalar::BigInt, + pub sqrt_price_limit_x96: substreams::scalar::BigInt, + pub data: Vec, + } + impl Swap { + const METHOD_ID: [u8; 4] = [18u8, 138u8, 203u8, 8u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Address, + ethabi::ParamType::Bool, + ethabi::ParamType::Int(256usize), + ethabi::ParamType::Uint(160usize), + ethabi::ParamType::Bytes, + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + recipient: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + zero_for_one: values + .pop() + .expect(INTERNAL_ERR) + .into_bool() + .expect(INTERNAL_ERR), + amount_specified: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + sqrt_price_limit_x96: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + data: values + .pop() + .expect(INTERNAL_ERR) + .into_bytes() + .expect(INTERNAL_ERR), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.recipient), + ), + ethabi::Token::Bool(self.zero_for_one.clone()), + { + let non_full_signed_bytes = self + .amount_specified + .to_signed_bytes_be(); + let full_signed_bytes_init = if non_full_signed_bytes[0] + & 0x80 == 0x80 + { + 0xff + } else { + 0x00 + }; + let mut full_signed_bytes = [full_signed_bytes_init + as u8; 32]; + non_full_signed_bytes + .into_iter() + .rev() + .enumerate() + .for_each(|(i, byte)| full_signed_bytes[31 - i] = byte); + ethabi::Token::Int( + ethabi::Int::from_big_endian(full_signed_bytes.as_ref()), + ) + }, + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.sqrt_price_limit_x96.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Bytes(self.data.clone()), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Int(256usize), + ethabi::ParamType::Int(256usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option<(substreams::scalar::BigInt, substreams::scalar::BigInt)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Swap { + const NAME: &'static str = "swap"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + > for Swap { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct TickBitmap { + pub word_position: substreams::scalar::BigInt, + } + impl TickBitmap { + const METHOD_ID: [u8; 4] = [83u8, 57u8, 194u8, 150u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Int(16usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + word_position: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + { + let non_full_signed_bytes = self + .word_position + .to_signed_bytes_be(); + let full_signed_bytes_init = if non_full_signed_bytes[0] + & 0x80 == 0x80 + { + 0xff + } else { + 0x00 + }; + let mut full_signed_bytes = [full_signed_bytes_init + as u8; 32]; + non_full_signed_bytes + .into_iter() + .rev() + .enumerate() + .for_each(|(i, byte)| full_signed_bytes[31 - i] = byte); + ethabi::Token::Int( + ethabi::Int::from_big_endian(full_signed_bytes.as_ref()), + ) + }, + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for TickBitmap { + const NAME: &'static str = "tickBitmap"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for TickBitmap { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct TickSpacing {} + impl TickSpacing { + const METHOD_ID: [u8; 4] = [208u8, 201u8, 58u8, 124u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Int(24usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for TickSpacing { + const NAME: &'static str = "tickSpacing"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for TickSpacing { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Ticks { + pub tick: substreams::scalar::BigInt, + } + impl Ticks { + const METHOD_ID: [u8; 4] = [243u8, 13u8, 186u8, 147u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Int(24usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + tick: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + { + let non_full_signed_bytes = self.tick.to_signed_bytes_be(); + let full_signed_bytes_init = if non_full_signed_bytes[0] + & 0x80 == 0x80 + { + 0xff + } else { + 0x00 + }; + let mut full_signed_bytes = [full_signed_bytes_init + as u8; 32]; + non_full_signed_bytes + .into_iter() + .rev() + .enumerate() + .for_each(|(i, byte)| full_signed_bytes[31 - i] = byte); + ethabi::Token::Int( + ethabi::Int::from_big_endian(full_signed_bytes.as_ref()), + ) + }, + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + bool, + ), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + bool, + ), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Int(128usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Int(56usize), + ethabi::ParamType::Uint(160usize), + ethabi::ParamType::Uint(32usize), + ethabi::ParamType::Bool, + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + values.pop().expect(INTERNAL_ERR).into_bool().expect(INTERNAL_ERR), + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + bool, + ), + > { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Ticks { + const NAME: &'static str = "ticks"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + bool, + ), + > for Ticks { + fn output( + data: &[u8], + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + bool, + ), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Token0 {} + impl Token0 { + const METHOD_ID: [u8; 4] = [13u8, 254u8, 22u8, 129u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Token0 { + const NAME: &'static str = "token0"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for Token0 { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Token1 {} + impl Token1 { + const METHOD_ID: [u8; 4] = [210u8, 18u8, 32u8, 167u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Token1 { + const NAME: &'static str = "token1"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for Token1 { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + } + /// Contract's events. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod events { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct Burn { + pub owner: Vec, + pub tick_lower: substreams::scalar::BigInt, + pub tick_upper: substreams::scalar::BigInt, + pub amount: substreams::scalar::BigInt, + pub amount0: substreams::scalar::BigInt, + pub amount1: substreams::scalar::BigInt, + } + impl Burn { + const TOPIC_ID: [u8; 32] = [ + 12u8, + 57u8, + 108u8, + 217u8, + 137u8, + 163u8, + 159u8, + 68u8, + 89u8, + 181u8, + 250u8, + 26u8, + 237u8, + 106u8, + 154u8, + 141u8, + 205u8, + 188u8, + 69u8, + 144u8, + 138u8, + 207u8, + 214u8, + 126u8, + 2u8, + 140u8, + 213u8, + 104u8, + 218u8, + 152u8, + 152u8, + 44u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 4usize { + return false; + } + if log.data.len() != 96usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + owner: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'owner' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tick_lower: substreams::scalar::BigInt::from_signed_bytes_be( + log.topics[2usize].as_ref(), + ), + tick_upper: substreams::scalar::BigInt::from_signed_bytes_be( + log.topics[3usize].as_ref(), + ), + amount: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + amount0: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + amount1: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for Burn { + const NAME: &'static str = "Burn"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Collect { + pub owner: Vec, + pub recipient: Vec, + pub tick_lower: substreams::scalar::BigInt, + pub tick_upper: substreams::scalar::BigInt, + pub amount0: substreams::scalar::BigInt, + pub amount1: substreams::scalar::BigInt, + } + impl Collect { + const TOPIC_ID: [u8; 32] = [ + 112u8, + 147u8, + 83u8, + 56u8, + 230u8, + 151u8, + 117u8, + 69u8, + 106u8, + 133u8, + 221u8, + 239u8, + 34u8, + 108u8, + 57u8, + 95u8, + 182u8, + 104u8, + 182u8, + 63u8, + 160u8, + 17u8, + 95u8, + 95u8, + 32u8, + 97u8, + 11u8, + 56u8, + 142u8, + 108u8, + 169u8, + 192u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 4usize { + return false; + } + if log.data.len() != 96usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(128usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + owner: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'owner' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tick_lower: substreams::scalar::BigInt::from_signed_bytes_be( + log.topics[2usize].as_ref(), + ), + tick_upper: substreams::scalar::BigInt::from_signed_bytes_be( + log.topics[3usize].as_ref(), + ), + recipient: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + amount0: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + amount1: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for Collect { + const NAME: &'static str = "Collect"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct CollectProtocol { + pub sender: Vec, + pub recipient: Vec, + pub amount0: substreams::scalar::BigInt, + pub amount1: substreams::scalar::BigInt, + } + impl CollectProtocol { + const TOPIC_ID: [u8; 32] = [ + 89u8, + 107u8, + 87u8, + 57u8, + 6u8, + 33u8, + 141u8, + 52u8, + 17u8, + 133u8, + 11u8, + 38u8, + 166u8, + 180u8, + 55u8, + 214u8, + 196u8, + 82u8, + 47u8, + 219u8, + 67u8, + 210u8, + 210u8, + 56u8, + 98u8, + 99u8, + 248u8, + 109u8, + 80u8, + 184u8, + 177u8, + 81u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 64usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(128usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + sender: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'sender' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + recipient: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'recipient' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + amount0: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + amount1: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for CollectProtocol { + const NAME: &'static str = "CollectProtocol"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Flash { + pub sender: Vec, + pub recipient: Vec, + pub amount0: substreams::scalar::BigInt, + pub amount1: substreams::scalar::BigInt, + pub paid0: substreams::scalar::BigInt, + pub paid1: substreams::scalar::BigInt, + } + impl Flash { + const TOPIC_ID: [u8; 32] = [ + 189u8, + 189u8, + 183u8, + 29u8, + 120u8, + 96u8, + 55u8, + 107u8, + 165u8, + 43u8, + 37u8, + 165u8, + 2u8, + 139u8, + 238u8, + 162u8, + 53u8, + 129u8, + 54u8, + 74u8, + 64u8, + 82u8, + 47u8, + 107u8, + 207u8, + 184u8, + 107u8, + 177u8, + 242u8, + 220u8, + 166u8, + 51u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 128usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + sender: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'sender' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + recipient: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'recipient' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + amount0: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + amount1: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + paid0: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + paid1: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for Flash { + const NAME: &'static str = "Flash"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IncreaseObservationCardinalityNext { + pub observation_cardinality_next_old: substreams::scalar::BigInt, + pub observation_cardinality_next_new: substreams::scalar::BigInt, + } + impl IncreaseObservationCardinalityNext { + const TOPIC_ID: [u8; 32] = [ + 172u8, + 73u8, + 229u8, + 24u8, + 249u8, + 10u8, + 53u8, + 143u8, + 101u8, + 46u8, + 68u8, + 0u8, + 22u8, + 79u8, + 5u8, + 165u8, + 216u8, + 247u8, + 227u8, + 94u8, + 119u8, + 71u8, + 39u8, + 155u8, + 195u8, + 169u8, + 61u8, + 191u8, + 88u8, + 78u8, + 18u8, + 90u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 64usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(16usize), + ethabi::ParamType::Uint(16usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + observation_cardinality_next_old: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + observation_cardinality_next_new: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for IncreaseObservationCardinalityNext { + const NAME: &'static str = "IncreaseObservationCardinalityNext"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Initialize { + pub sqrt_price_x96: substreams::scalar::BigInt, + pub tick: substreams::scalar::BigInt, + } + impl Initialize { + const TOPIC_ID: [u8; 32] = [ + 152u8, + 99u8, + 96u8, + 54u8, + 203u8, + 102u8, + 169u8, + 193u8, + 154u8, + 55u8, + 67u8, + 94u8, + 252u8, + 30u8, + 144u8, + 20u8, + 33u8, + 144u8, + 33u8, + 78u8, + 138u8, + 190u8, + 184u8, + 33u8, + 189u8, + 186u8, + 63u8, + 41u8, + 144u8, + 221u8, + 76u8, + 149u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 64usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(160usize), + ethabi::ParamType::Int(24usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + sqrt_price_x96: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tick: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for Initialize { + const NAME: &'static str = "Initialize"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Mint { + pub sender: Vec, + pub owner: Vec, + pub tick_lower: substreams::scalar::BigInt, + pub tick_upper: substreams::scalar::BigInt, + pub amount: substreams::scalar::BigInt, + pub amount0: substreams::scalar::BigInt, + pub amount1: substreams::scalar::BigInt, + } + impl Mint { + const TOPIC_ID: [u8; 32] = [ + 122u8, + 83u8, + 8u8, + 11u8, + 164u8, + 20u8, + 21u8, + 139u8, + 231u8, + 236u8, + 105u8, + 185u8, + 135u8, + 181u8, + 251u8, + 125u8, + 7u8, + 222u8, + 225u8, + 1u8, + 254u8, + 133u8, + 72u8, + 143u8, + 8u8, + 83u8, + 174u8, + 22u8, + 35u8, + 157u8, + 11u8, + 222u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 4usize { + return false; + } + if log.data.len() != 128usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + owner: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'owner' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tick_lower: substreams::scalar::BigInt::from_signed_bytes_be( + log.topics[2usize].as_ref(), + ), + tick_upper: substreams::scalar::BigInt::from_signed_bytes_be( + log.topics[3usize].as_ref(), + ), + sender: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + amount: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + amount0: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + amount1: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for Mint { + const NAME: &'static str = "Mint"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct SetFeeProtocol { + pub fee_protocol0_old: substreams::scalar::BigInt, + pub fee_protocol1_old: substreams::scalar::BigInt, + pub fee_protocol0_new: substreams::scalar::BigInt, + pub fee_protocol1_new: substreams::scalar::BigInt, + } + impl SetFeeProtocol { + const TOPIC_ID: [u8; 32] = [ + 151u8, + 61u8, + 141u8, + 146u8, + 187u8, + 41u8, + 159u8, + 74u8, + 246u8, + 206u8, + 73u8, + 181u8, + 42u8, + 138u8, + 219u8, + 133u8, + 174u8, + 70u8, + 185u8, + 242u8, + 20u8, + 196u8, + 196u8, + 252u8, + 6u8, + 172u8, + 119u8, + 64u8, + 18u8, + 55u8, + 177u8, + 51u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 128usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(8usize), + ethabi::ParamType::Uint(8usize), + ethabi::ParamType::Uint(8usize), + ethabi::ParamType::Uint(8usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + fee_protocol0_old: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + fee_protocol1_old: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + fee_protocol0_new: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + fee_protocol1_new: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for SetFeeProtocol { + const NAME: &'static str = "SetFeeProtocol"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Swap { + pub sender: Vec, + pub recipient: Vec, + pub amount0: substreams::scalar::BigInt, + pub amount1: substreams::scalar::BigInt, + pub sqrt_price_x96: substreams::scalar::BigInt, + pub liquidity: substreams::scalar::BigInt, + pub tick: substreams::scalar::BigInt, + } + impl Swap { + const TOPIC_ID: [u8; 32] = [ + 196u8, + 32u8, + 121u8, + 249u8, + 74u8, + 99u8, + 80u8, + 215u8, + 230u8, + 35u8, + 95u8, + 41u8, + 23u8, + 73u8, + 36u8, + 249u8, + 40u8, + 204u8, + 42u8, + 200u8, + 24u8, + 235u8, + 100u8, + 254u8, + 216u8, + 0u8, + 78u8, + 17u8, + 95u8, + 188u8, + 202u8, + 103u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 160usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Int(256usize), + ethabi::ParamType::Int(256usize), + ethabi::ParamType::Uint(160usize), + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Int(24usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + sender: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'sender' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + recipient: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'recipient' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + amount0: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + amount1: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + sqrt_price_x96: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + liquidity: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tick: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for Swap { + const NAME: &'static str = "Swap"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + } \ No newline at end of file diff --git a/substreams/ethereum-uniswap-v3-logs-only/src/lib.rs b/substreams/ethereum-uniswap-v3-logs-only/src/lib.rs new file mode 100644 index 0000000..dc70218 --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/src/lib.rs @@ -0,0 +1,7 @@ +#![allow(clippy::not_unsafe_ptr_arg_deref)] + +mod abi; +mod modules; +mod pb; + +pub use modules::*; diff --git a/substreams/ethereum-uniswap-v3-logs-only/src/modules/1_map_pool_created.rs b/substreams/ethereum-uniswap-v3-logs-only/src/modules/1_map_pool_created.rs new file mode 100644 index 0000000..3ade85c --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/src/modules/1_map_pool_created.rs @@ -0,0 +1,114 @@ +use std::str::FromStr; + +use ethabi::ethereum_types::Address; +use substreams::scalar::BigInt; +use substreams_ethereum::pb::eth::v2::{self as eth}; + +use substreams_helper::{event_handler::EventHandler, hex::Hexable}; + +use crate::abi::factory::events::PoolCreated; + +use tycho_substreams::prelude::*; + +#[substreams::handlers::map] +pub fn map_pools_created( + params: String, + block: eth::Block, +) -> Result { + let mut new_pools: Vec = vec![]; + let factory_address = params.as_str(); + + get_new_pools(&block, &mut new_pools, factory_address); + + Ok(BlockEntityChanges { block: None, changes: new_pools }) +} + +// Extract new pools from PoolCreated events +fn get_new_pools( + block: ð::Block, + new_pools: &mut Vec, + factory_address: &str, +) { + // Extract new pools from PoolCreated events + let mut on_pool_created = |event: PoolCreated, _tx: ð::TransactionTrace, _log: ð::Log| { + let tycho_tx: Transaction = _tx.into(); + + new_pools.push(TransactionEntityChanges { + tx: Some(tycho_tx.clone()), + entity_changes: vec![EntityChanges { + component_id: event.pool.clone().to_hex(), + attributes: vec![ + Attribute { + name: "liquidity".to_string(), + value: BigInt::from(0).to_signed_bytes_be(), + change: ChangeType::Creation.into(), + }, + Attribute { + name: "tick".to_string(), + value: BigInt::from(0).to_signed_bytes_be(), + change: ChangeType::Creation.into(), + }, + Attribute { + name: "sqrt_price_x96".to_string(), + value: BigInt::from(0).to_signed_bytes_be(), + change: ChangeType::Creation.into(), + }, + ], + }], + component_changes: vec![ProtocolComponent { + id: event.pool.to_hex(), + tokens: vec![event.token0.clone(), event.token1.clone()], + contracts: vec![], + static_att: vec![ + Attribute { + name: "fee".to_string(), + value: event.fee.to_signed_bytes_be(), + change: ChangeType::Creation.into(), + }, + Attribute { + name: "tick_spacing".to_string(), + value: event.tick_spacing.to_signed_bytes_be(), + change: ChangeType::Creation.into(), + }, + Attribute { + name: "pool_address".to_string(), + value: event.pool.clone(), + change: ChangeType::Creation.into(), + }, + ], + change: i32::from(ChangeType::Creation), + protocol_type: Option::from(ProtocolType { + name: "uniswap_v3_pool".to_string(), + financial_type: FinancialType::Swap.into(), + attribute_schema: vec![], + implementation_type: ImplementationType::Custom.into(), + }), + tx: Some(tycho_tx), + }], + balance_changes: vec![ + BalanceChange { + token: event.token0, + balance: BigInt::from(0).to_signed_bytes_be(), + component_id: event + .pool + .clone() + .to_hex() + .as_bytes() + .to_vec(), + }, + BalanceChange { + token: event.token1, + balance: BigInt::from(0).to_signed_bytes_be(), + component_id: event.pool.to_hex().as_bytes().to_vec(), + }, + ], + }) + }; + + let mut eh = EventHandler::new(block); + + eh.filter_by_address(vec![Address::from_str(factory_address).unwrap()]); + + eh.on::(&mut on_pool_created); + eh.handle_events(); +} diff --git a/substreams/ethereum-uniswap-v3-logs-only/src/modules/2_store_pools.rs b/substreams/ethereum-uniswap-v3-logs-only/src/modules/2_store_pools.rs new file mode 100644 index 0000000..fa769d4 --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/src/modules/2_store_pools.rs @@ -0,0 +1,24 @@ +use std::str; + +use substreams::store::{StoreNew, StoreSetIfNotExists, StoreSetIfNotExistsProto}; +use tycho_substreams::models::BlockEntityChanges; + +use crate::pb::uniswap::v3::Pool; + +#[substreams::handlers::store] +pub fn store_pools(pools_created: BlockEntityChanges, store: StoreSetIfNotExistsProto) { + // Store pools. Required so the next maps can match any event to a known pool by their address + + for change in pools_created.changes { + for component_change in &change.component_changes { + let pool_address: &str = &component_change.id; + let pool: Pool = Pool { + address: hex::decode(pool_address.trim_start_matches("0x")).unwrap(), + token0: component_change.tokens[0].clone(), + token1: component_change.tokens[1].clone(), + created_tx_hash: change.tx.as_ref().unwrap().hash.clone(), + }; + store.set_if_not_exists(0, format!("{}:{}", "Pool", pool_address), &pool); + } + } +} diff --git a/substreams/ethereum-uniswap-v3-logs-only/src/modules/3_map_events.rs b/substreams/ethereum-uniswap-v3-logs-only/src/modules/3_map_events.rs new file mode 100644 index 0000000..4a88fb0 --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/src/modules/3_map_events.rs @@ -0,0 +1,183 @@ +use anyhow::Ok; +use substreams::{ + store::{StoreGet, StoreGetProto}, + Hex, +}; +use substreams_ethereum::{ + pb::eth::v2::{self as eth, Log, TransactionTrace}, + Event, +}; +use substreams_helper::hex::Hexable; + +use crate::{ + abi::pool::events::{ + Burn, Collect, CollectProtocol, Flash, Initialize, Mint, SetFeeProtocol, Swap, + }, + pb::uniswap::v3::{ + events::{ + pool_event::{self, Type}, + PoolEvent, + }, + Events, Pool, + }, +}; + +#[substreams::handlers::map] +pub fn map_events( + block: eth::Block, + pools_store: StoreGetProto, +) -> Result { + let mut pool_events = block + .transaction_traces + .into_iter() + .filter(|tx| tx.status == 1) + .flat_map(|tx| { + tx.clone() + .receipt + .into_iter() + .flat_map(|receipt| receipt.logs) + .filter_map(|log| { + let key = format!("{}:{}", "Pool", log.address.to_hex()); + // Skip if the log is not from a known uniswapV3 pool. + if let Some(pool) = pools_store.get_last(key) { + log_to_event(&log, pool, tx.clone()) + } else { + None + } + }) + .collect::>() + }) + .collect::>(); + + pool_events.sort_unstable_by_key(|e| e.log_ordinal); + + Ok(Events { pool_events }) +} + +fn log_to_event(event: &Log, pool: Pool, tx: TransactionTrace) -> Option { + if let Some(init) = Initialize::match_and_decode(event) { + Some(PoolEvent { + log_ordinal: event.ordinal, + pool_address: Hex(pool.address).to_string(), + token0: Hex(pool.token0).to_string(), + token1: Hex(pool.token1).to_string(), + transaction: Some(tx.into()), + r#type: Some(Type::Initialize(pool_event::Initialize { + sqrt_price: init.sqrt_price_x96.to_string(), + tick: init.tick.into(), + })), + }) + } else if let Some(swap) = Swap::match_and_decode(event) { + Some(PoolEvent { + log_ordinal: event.ordinal, + pool_address: Hex(pool.address).to_string(), + token0: Hex(pool.token0).to_string(), + token1: Hex(pool.token1).to_string(), + transaction: Some(tx.into()), + r#type: Some(Type::Swap(pool_event::Swap { + sender: Hex(swap.sender).to_string(), + recipient: Hex(swap.recipient).to_string(), + amount_0: swap.amount0.to_string(), + amount_1: swap.amount1.to_string(), + sqrt_price: swap.sqrt_price_x96.to_string(), + liquidity: swap.liquidity.to_string(), + tick: swap.tick.into(), + })), + }) + } else if let Some(flash) = Flash::match_and_decode(event) { + Some(PoolEvent { + log_ordinal: event.ordinal, + pool_address: Hex(pool.address).to_string(), + token0: Hex(pool.token0).to_string(), + token1: Hex(pool.token1).to_string(), + transaction: Some(tx.into()), + r#type: Some(Type::Flash(pool_event::Flash { + sender: Hex(flash.sender).to_string(), + recipient: Hex(flash.recipient).to_string(), + amount_0: flash.amount0.to_string(), + amount_1: flash.amount1.to_string(), + paid_0: flash.paid0.to_string(), + paid_1: flash.paid1.to_string(), + })), + }) + } else if let Some(mint) = Mint::match_and_decode(event) { + Some(PoolEvent { + log_ordinal: event.ordinal, + pool_address: Hex(pool.address).to_string(), + token0: Hex(pool.token0).to_string(), + token1: Hex(pool.token1).to_string(), + transaction: Some(tx.into()), + r#type: Some(Type::Mint(pool_event::Mint { + sender: Hex(mint.sender).to_string(), + owner: Hex(mint.owner).to_string(), + tick_lower: mint.tick_lower.into(), + tick_upper: mint.tick_upper.into(), + amount: mint.amount.to_string(), + amount_0: mint.amount0.to_string(), + amount_1: mint.amount1.to_string(), + })), + }) + } else if let Some(burn) = Burn::match_and_decode(event) { + Some(PoolEvent { + log_ordinal: event.ordinal, + pool_address: Hex(pool.address).to_string(), + token0: Hex(pool.token0).to_string(), + token1: Hex(pool.token1).to_string(), + transaction: Some(tx.into()), + r#type: Some(Type::Burn(pool_event::Burn { + owner: Hex(burn.owner).to_string(), + tick_lower: burn.tick_lower.into(), + tick_upper: burn.tick_upper.into(), + amount: burn.amount.to_string(), + amount_0: burn.amount0.to_string(), + amount_1: burn.amount1.to_string(), + })), + }) + } else if let Some(collect) = Collect::match_and_decode(event) { + Some(PoolEvent { + log_ordinal: event.ordinal, + pool_address: Hex(pool.address).to_string(), + token0: Hex(pool.token0).to_string(), + token1: Hex(pool.token1).to_string(), + transaction: Some(tx.into()), + r#type: Some(Type::Collect(pool_event::Collect { + owner: Hex(collect.owner).to_string(), + recipient: Hex(collect.recipient).to_string(), + tick_lower: collect.tick_lower.into(), + tick_upper: collect.tick_upper.into(), + amount_0: collect.amount0.to_string(), + amount_1: collect.amount1.to_string(), + })), + }) + } else if let Some(set_fp) = SetFeeProtocol::match_and_decode(event) { + Some(PoolEvent { + log_ordinal: event.ordinal, + pool_address: Hex(pool.address).to_string(), + token0: Hex(pool.token0).to_string(), + token1: Hex(pool.token1).to_string(), + transaction: Some(tx.into()), + r#type: Some(Type::SetFeeProtocol(pool_event::SetFeeProtocol { + fee_protocol_0_old: set_fp.fee_protocol0_old.to_u64(), + fee_protocol_1_old: set_fp.fee_protocol1_old.to_u64(), + fee_protocol_0_new: set_fp.fee_protocol0_new.to_u64(), + fee_protocol_1_new: set_fp.fee_protocol1_new.to_u64(), + })), + }) + } else if let Some(cp) = CollectProtocol::match_and_decode(event) { + Some(PoolEvent { + log_ordinal: event.ordinal, + pool_address: Hex(pool.address).to_string(), + token0: Hex(pool.token0).to_string(), + token1: Hex(pool.token1).to_string(), + transaction: Some(tx.into()), + r#type: Some(Type::CollectProtocol(pool_event::CollectProtocol { + sender: Hex(cp.sender).to_string(), + recipient: Hex(cp.recipient).to_string(), + amount_0: cp.amount0.to_string(), + amount_1: cp.amount1.to_string(), + })), + }) + } else { + None + } +} diff --git a/substreams/ethereum-uniswap-v3-logs-only/src/modules/4_map_and_store_balance_changes.rs b/substreams/ethereum-uniswap-v3-logs-only/src/modules/4_map_and_store_balance_changes.rs new file mode 100644 index 0000000..e5e2480 --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/src/modules/4_map_and_store_balance_changes.rs @@ -0,0 +1,175 @@ +use std::str::FromStr; + +use anyhow::Ok; +use tycho_substreams::models::{BalanceDelta, BlockBalanceDeltas}; + +use crate::pb::uniswap::v3::{ + events::{pool_event, PoolEvent}, + Events, +}; +use substreams::{ + scalar::BigInt, + store::{StoreAddBigInt, StoreNew}, +}; + +#[substreams::handlers::map] +pub fn map_balance_changes(events: Events) -> Result { + let balance_deltas = events + .pool_events + .into_iter() + .flat_map(event_to_balance_deltas) + .collect(); + + Ok(BlockBalanceDeltas { balance_deltas }) +} + +#[substreams::handlers::store] +pub fn store_pools_balances(balances_deltas: BlockBalanceDeltas, store: StoreAddBigInt) { + tycho_substreams::balances::store_balance_changes(balances_deltas, store); +} + +fn event_to_balance_deltas(event: PoolEvent) -> Vec { + let address = format!("0x{}", event.pool_address) + .as_bytes() + .to_vec(); + match event.r#type.unwrap() { + pool_event::Type::Mint(e) => vec![ + BalanceDelta { + token: hex::decode(event.token0.clone()).unwrap(), + delta: BigInt::from_str(&e.amount_0) + .unwrap() + .to_signed_bytes_be(), + component_id: address.clone(), + ord: event.log_ordinal, + tx: event + .transaction + .clone() + .map(Into::into), + }, + BalanceDelta { + token: hex::decode(event.token1.clone()).unwrap(), + delta: BigInt::from_str(&e.amount_1) + .unwrap() + .to_signed_bytes_be(), + component_id: address, + ord: event.log_ordinal, + tx: event.transaction.map(Into::into), + }, + ], + pool_event::Type::Collect(e) => vec![ + BalanceDelta { + token: hex::decode(event.token0.clone()).unwrap(), + delta: BigInt::from_str(&e.amount_0) + .unwrap() + .neg() + .to_signed_bytes_be(), + component_id: address.clone(), + ord: event.log_ordinal, + tx: event + .transaction + .clone() + .map(Into::into), + }, + BalanceDelta { + token: hex::decode(event.token1.clone()).unwrap(), + delta: BigInt::from_str(&e.amount_1) + .unwrap() + .neg() + .to_signed_bytes_be(), + component_id: address, + ord: event.log_ordinal, + tx: event.transaction.map(Into::into), + }, + ], + //Burn balance changes are accounted for in the Collect event. + pool_event::Type::Burn(_) => vec![], + pool_event::Type::Swap(e) => { + vec![ + BalanceDelta { + token: hex::decode(event.token0.clone()).unwrap(), + delta: BigInt::from_str(&e.amount_0) + .unwrap() + .to_signed_bytes_be(), + component_id: address.clone(), + ord: event.log_ordinal, + tx: event + .transaction + .clone() + .map(Into::into), + }, + BalanceDelta { + token: hex::decode(event.token1.clone()).unwrap(), + delta: BigInt::from_str(&e.amount_1) + .unwrap() + .to_signed_bytes_be(), + component_id: address.clone(), + ord: event.log_ordinal, + tx: event.transaction.map(Into::into), + }, + ] + } + pool_event::Type::Flash(e) => vec![ + BalanceDelta { + token: hex::decode(event.token0).unwrap(), + delta: BigInt::from_str(&e.paid_0) + .unwrap() + .clone() + .to_signed_bytes_be(), + component_id: address.clone(), + ord: event.log_ordinal, + tx: event + .transaction + .clone() + .map(Into::into), + }, + BalanceDelta { + token: hex::decode(event.token1).unwrap(), + delta: BigInt::from_str(&e.paid_1) + .unwrap() + .clone() + .to_signed_bytes_be(), + component_id: address, + ord: event.log_ordinal, + tx: event.transaction.map(Into::into), + }, + ], + pool_event::Type::CollectProtocol(e) => { + vec![ + BalanceDelta { + token: hex::decode(event.token0).unwrap(), + delta: BigInt::from_str(&e.amount_0) + .unwrap() + .neg() + .clone() + .to_signed_bytes_be(), + component_id: event + .pool_address + .clone() + .as_bytes() + .to_vec(), + ord: event.log_ordinal, + tx: event + .transaction + .clone() + .map(Into::into), + }, + BalanceDelta { + token: hex::decode(event.token1).unwrap(), + delta: BigInt::from_str(&e.amount_1) + .unwrap() + .clone() + .neg() + .to_signed_bytes_be(), + component_id: event + .pool_address + .clone() + .as_bytes() + .to_vec(), + ord: event.log_ordinal, + tx: event.transaction.map(Into::into), + }, + ] + } + _ => vec![], + } +} diff --git a/substreams/ethereum-uniswap-v3-logs-only/src/modules/4_map_and_store_liquidity.rs b/substreams/ethereum-uniswap-v3-logs-only/src/modules/4_map_and_store_liquidity.rs new file mode 100644 index 0000000..b7e6a30 --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/src/modules/4_map_and_store_liquidity.rs @@ -0,0 +1,137 @@ +use std::str::FromStr; + +use substreams::store::{ + StoreGet, StoreGetInt64, StoreSet, StoreSetInt64, StoreSetSum, StoreSetSumBigInt, +}; + +use crate::pb::uniswap::v3::{ + events::{pool_event, PoolEvent}, + Events, LiquidityChange, LiquidityChangeType, LiquidityChanges, +}; + +use substreams::{scalar::BigInt, store::StoreNew}; + +use anyhow::Ok; + +#[substreams::handlers::store] +pub fn store_pool_current_tick(events: Events, store: StoreSetInt64) { + events + .pool_events + .into_iter() + .filter_map(event_to_current_tick) + .for_each(|(pool, ordinal, new_tick_index)| { + store.set(ordinal, format!("pool:{0}", pool), &new_tick_index.into()) + }); +} + +#[substreams::handlers::map] +pub fn map_liquidity_changes( + events: Events, + pools_current_tick_store: StoreGetInt64, +) -> Result { + let mut changes = events + .pool_events + .into_iter() + .filter(PoolEvent::can_introduce_liquidity_changes) + .map(|e| { + ( + pools_current_tick_store + .get_at(e.log_ordinal, format!("pool:{0}", &e.pool_address)) + .unwrap_or(0), + e, + ) + }) + .filter_map(|(current_tick, event)| event_to_liquidity_deltas(current_tick, event)) + .collect::>(); + + changes.sort_unstable_by_key(|l| l.ordinal); + Ok(LiquidityChanges { changes }) +} + +#[substreams::handlers::store] +pub fn store_liquidity(ticks_deltas: LiquidityChanges, store: StoreSetSumBigInt) { + ticks_deltas + .changes + .iter() + .for_each(|changes| match changes.change_type() { + LiquidityChangeType::Delta => { + store.sum( + changes.ordinal, + format!("pool:{0}", hex::encode(&changes.pool_address)), + BigInt::from_signed_bytes_be(&changes.value), + ); + } + LiquidityChangeType::Absolute => { + store.set( + changes.ordinal, + format!("pool:{0}", hex::encode(&changes.pool_address)), + BigInt::from_signed_bytes_be(&changes.value), + ); + } + }); +} + +fn event_to_liquidity_deltas(current_tick: i64, event: PoolEvent) -> Option { + match event.r#type.as_ref().unwrap() { + pool_event::Type::Mint(mint) => { + if current_tick >= mint.tick_lower.into() && current_tick < mint.tick_upper.into() { + Some(LiquidityChange { + pool_address: hex::decode(event.pool_address).unwrap(), + value: BigInt::from_str(&mint.amount) + .unwrap() + .to_signed_bytes_be(), + change_type: LiquidityChangeType::Delta.into(), + ordinal: event.log_ordinal, + transaction: Some(event.transaction.unwrap()), + }) + } else { + None + } + } + pool_event::Type::Burn(burn) => { + if current_tick >= burn.tick_lower.into() && current_tick < burn.tick_upper.into() { + Some(LiquidityChange { + pool_address: hex::decode(event.pool_address).unwrap(), + value: BigInt::from_str(&burn.amount) + .unwrap() + .neg() + .to_signed_bytes_be(), + change_type: LiquidityChangeType::Delta.into(), + ordinal: event.log_ordinal, + transaction: Some(event.transaction.unwrap()), + }) + } else { + None + } + } + pool_event::Type::Swap(swap) => Some(LiquidityChange { + pool_address: hex::decode(event.pool_address).unwrap(), + value: BigInt::from_str(&swap.liquidity) + .unwrap() + .to_signed_bytes_be(), + change_type: LiquidityChangeType::Absolute.into(), + ordinal: event.log_ordinal, + transaction: Some(event.transaction.unwrap()), + }), + _ => None, + } +} + +impl PoolEvent { + fn can_introduce_liquidity_changes(&self) -> bool { + matches!( + self.r#type.as_ref().unwrap(), + pool_event::Type::Mint(_) | pool_event::Type::Burn(_) | pool_event::Type::Swap(_) + ) + } +} + +fn event_to_current_tick(event: PoolEvent) -> Option<(String, u64, i32)> { + match event.r#type.as_ref().unwrap() { + pool_event::Type::Initialize(initialize) => { + Some((event.pool_address, event.log_ordinal, initialize.tick)) + } + pool_event::Type::Swap(swap) => Some((event.pool_address, event.log_ordinal, swap.tick)), + _ => None, + } +} diff --git a/substreams/ethereum-uniswap-v3-logs-only/src/modules/4_map_and_store_ticks.rs b/substreams/ethereum-uniswap-v3-logs-only/src/modules/4_map_and_store_ticks.rs new file mode 100644 index 0000000..a551e4f --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/src/modules/4_map_and_store_ticks.rs @@ -0,0 +1,91 @@ +use std::str::FromStr; + +use substreams::store::StoreAddBigInt; + +use crate::pb::uniswap::v3::{ + events::{pool_event, PoolEvent}, + Events, TickDelta, TickDeltas, +}; + +use substreams::{ + scalar::BigInt, + store::{StoreAdd, StoreNew}, +}; + +use anyhow::Ok; + +#[substreams::handlers::map] +pub fn map_ticks_changes(events: Events) -> Result { + let ticks_deltas = events + .pool_events + .into_iter() + .flat_map(event_to_ticks_deltas) + .collect(); + + Ok(TickDeltas { deltas: ticks_deltas }) +} + +#[substreams::handlers::store] +pub fn store_ticks_liquidity(ticks_deltas: TickDeltas, store: StoreAddBigInt) { + let mut deltas = ticks_deltas.deltas.clone(); + + deltas.sort_unstable_by_key(|delta| delta.ordinal); + + deltas.iter().for_each(|delta| { + store.add( + delta.ordinal, + format!("pool:{0}:tick:{1}", hex::encode(&delta.pool_address), delta.tick_index,), + BigInt::from_signed_bytes_be(&delta.liquidity_net_delta), + ); + }); +} + +fn event_to_ticks_deltas(event: PoolEvent) -> Vec { + match event.r#type.as_ref().unwrap() { + pool_event::Type::Mint(mint) => { + vec![ + TickDelta { + pool_address: hex::decode(&event.pool_address).unwrap(), + tick_index: mint.tick_lower, + liquidity_net_delta: BigInt::from_str(&mint.amount) + .unwrap() + .to_signed_bytes_be(), + ordinal: event.log_ordinal, + transaction: event.transaction.clone(), + }, + TickDelta { + pool_address: hex::decode(&event.pool_address).unwrap(), + tick_index: mint.tick_upper, + liquidity_net_delta: BigInt::from_str(&mint.amount) + .unwrap() + .neg() + .to_signed_bytes_be(), + ordinal: event.log_ordinal, + transaction: event.transaction, + }, + ] + } + pool_event::Type::Burn(burn) => vec![ + TickDelta { + pool_address: hex::decode(&event.pool_address).unwrap(), + tick_index: burn.tick_lower, + liquidity_net_delta: BigInt::from_str(&burn.amount) + .unwrap() + .neg() + .to_signed_bytes_be(), + ordinal: event.log_ordinal, + transaction: event.transaction.clone(), + }, + TickDelta { + pool_address: hex::decode(&event.pool_address).unwrap(), + tick_index: burn.tick_upper, + liquidity_net_delta: BigInt::from_str(&burn.amount) + .unwrap() + .to_signed_bytes_be(), + ordinal: event.log_ordinal, + transaction: event.transaction, + }, + ], + _ => vec![], + } +} diff --git a/substreams/ethereum-uniswap-v3-logs-only/src/modules/5_map_protocol_changes.rs b/substreams/ethereum-uniswap-v3-logs-only/src/modules/5_map_protocol_changes.rs new file mode 100644 index 0000000..05237e1 --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/src/modules/5_map_protocol_changes.rs @@ -0,0 +1,248 @@ +use crate::pb::uniswap::v3::{ + events::{pool_event, PoolEvent}, + Events, LiquidityChanges, TickDeltas, +}; +use itertools::Itertools; +use std::{collections::HashMap, str::FromStr, vec}; +use substreams::{pb::substreams::StoreDeltas, scalar::BigInt}; +use substreams_ethereum::pb::eth::v2::{self as eth}; +use substreams_helper::hex::Hexable; +use tycho_substreams::{balances::aggregate_balances_changes, prelude::*}; + +type PoolAddress = Vec; + +#[substreams::handlers::map] +pub fn map_protocol_changes( + block: eth::Block, + created_pools: BlockEntityChanges, + events: Events, + balances_map_deltas: BlockBalanceDeltas, + balances_store_deltas: StoreDeltas, + ticks_map_deltas: TickDeltas, + ticks_store_deltas: StoreDeltas, + pool_liquidity_changes: LiquidityChanges, + pool_liquidity_store_deltas: StoreDeltas, +) -> Result { + // We merge contract changes by transaction (identified by transaction index) making it easy to + // sort them at the very end. + let mut transaction_changes: HashMap<_, TransactionChangesBuilder> = HashMap::new(); + + // Add created pools to the tx_changes_map + for change in created_pools.changes.into_iter() { + let tx = change.tx.as_ref().unwrap(); + let builder = transaction_changes + .entry(tx.index) + .or_insert_with(|| TransactionChangesBuilder::new(tx)); + change + .component_changes + .iter() + .for_each(|c| { + builder.add_protocol_component(c); + }); + change + .entity_changes + .iter() + .for_each(|ec| { + builder.add_entity_change(ec); + }); + change + .balance_changes + .iter() + .for_each(|bc| { + builder.add_balance_change(bc); + }); + } + + // Balance changes are gathered by the `StoreDelta` based on `PoolBalanceChanged` creating + // `BlockBalanceDeltas`. We essentially just process the changes that occurred to the `store` + // this block. Then, these balance changes are merged onto the existing map of tx contract + // changes, inserting a new one if it doesn't exist. + aggregate_balances_changes(balances_store_deltas, balances_map_deltas) + .into_iter() + .for_each(|(_, (tx, balances))| { + let builder = transaction_changes + .entry(tx.index) + .or_insert_with(|| TransactionChangesBuilder::new(&tx)); + balances + .values() + .for_each(|token_bc_map| { + token_bc_map + .values() + .for_each(|bc| builder.add_balance_change(bc)) + }); + }); + + // Insert ticks net-liquidity changes + ticks_store_deltas + .deltas + .into_iter() + .zip(ticks_map_deltas.deltas) + .for_each(|(store_delta, tick_delta)| { + let new_value_bigint = + BigInt::from_str(&String::from_utf8(store_delta.new_value).unwrap()).unwrap(); + + // If old value is empty or the int value is 0, it's considered as a creation. + let is_creation = store_delta.old_value.is_empty() || + BigInt::from_str(&String::from_utf8(store_delta.old_value).unwrap()) + .unwrap() + .is_zero(); + let attribute_name = format!("ticks/{}/net-liquidity", tick_delta.tick_index); + let attribute = Attribute { + name: attribute_name, + value: new_value_bigint.to_signed_bytes_be(), + change: if is_creation { + ChangeType::Creation.into() + } else if new_value_bigint.is_zero() { + ChangeType::Deletion.into() + } else { + ChangeType::Update.into() + }, + }; + let tx = tick_delta.transaction.unwrap(); + let builder = transaction_changes + .entry(tx.index) + .or_insert_with(|| TransactionChangesBuilder::new(&tx.into())); + + builder.add_entity_change(&EntityChanges { + component_id: tick_delta.pool_address.to_hex(), + attributes: vec![attribute], + }); + }); + + // Insert liquidity changes + pool_liquidity_store_deltas + .deltas + .into_iter() + .zip(pool_liquidity_changes.changes) + .for_each(|(store_delta, change)| { + let new_value_bigint = BigInt::from_str( + String::from_utf8(store_delta.new_value) + .unwrap() + .split(':') + .nth(1) + .unwrap(), + ) + .unwrap(); + let tx = change.transaction.unwrap(); + let builder = transaction_changes + .entry(tx.index) + .or_insert_with(|| TransactionChangesBuilder::new(&tx.into())); + + builder.add_entity_change(&EntityChanges { + component_id: change.pool_address.to_hex(), + attributes: vec![Attribute { + name: "liquidity".to_string(), + value: new_value_bigint.to_signed_bytes_be(), + change: ChangeType::Update.into(), + }], + }); + }); + + // Insert others changes + events + .pool_events + .into_iter() + .flat_map(event_to_attributes_updates) + .for_each(|(tx, pool_address, attr)| { + let builder = transaction_changes + .entry(tx.index) + .or_insert_with(|| TransactionChangesBuilder::new(&tx)); + builder.add_entity_change(&EntityChanges { + component_id: pool_address.to_hex(), + attributes: vec![attr], + }); + }); + + Ok(BlockChanges { + block: Some((&block).into()), + changes: transaction_changes + .drain() + .sorted_unstable_by_key(|(index, _)| *index) + .filter_map(|(_, builder)| builder.build()) + .collect::>(), + }) +} + +fn event_to_attributes_updates(event: PoolEvent) -> Vec<(Transaction, PoolAddress, Attribute)> { + match event.r#type.as_ref().unwrap() { + pool_event::Type::Initialize(initalize) => { + vec![ + ( + event + .transaction + .clone() + .unwrap() + .into(), + hex::decode(event.pool_address.clone()).unwrap(), + Attribute { + name: "sqrt_price_x96".to_string(), + value: BigInt::from_str(&initalize.sqrt_price) + .unwrap() + .to_signed_bytes_be(), + change: ChangeType::Update.into(), + }, + ), + ( + event.transaction.unwrap().into(), + hex::decode(event.pool_address).unwrap(), + Attribute { + name: "tick".to_string(), + value: BigInt::from(initalize.tick).to_signed_bytes_be(), + change: ChangeType::Update.into(), + }, + ), + ] + } + pool_event::Type::Swap(swap) => vec![ + ( + event + .transaction + .clone() + .unwrap() + .into(), + hex::decode(event.pool_address.clone()).unwrap(), + Attribute { + name: "sqrt_price_x96".to_string(), + value: BigInt::from_str(&swap.sqrt_price) + .unwrap() + .to_signed_bytes_be(), + change: ChangeType::Update.into(), + }, + ), + ( + event.transaction.unwrap().into(), + hex::decode(event.pool_address).unwrap(), + Attribute { + name: "tick".to_string(), + value: BigInt::from(swap.tick).to_signed_bytes_be(), + change: ChangeType::Update.into(), + }, + ), + ], + pool_event::Type::SetFeeProtocol(sfp) => vec![ + ( + event + .transaction + .clone() + .unwrap() + .into(), + hex::decode(event.pool_address.clone()).unwrap(), + Attribute { + name: "protocol_fees/token0".to_string(), + value: BigInt::from(sfp.fee_protocol_0_new).to_signed_bytes_be(), + change: ChangeType::Update.into(), + }, + ), + ( + event.transaction.unwrap().into(), + hex::decode(event.pool_address).unwrap(), + Attribute { + name: "protocol_fees/token1".to_string(), + value: BigInt::from(sfp.fee_protocol_1_new).to_signed_bytes_be(), + change: ChangeType::Update.into(), + }, + ), + ], + _ => vec![], + } +} diff --git a/substreams/ethereum-uniswap-v3-logs-only/src/modules/mod.rs b/substreams/ethereum-uniswap-v3-logs-only/src/modules/mod.rs new file mode 100644 index 0000000..8c679c1 --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/src/modules/mod.rs @@ -0,0 +1,39 @@ +pub use map_pool_created::map_pools_created; +pub use map_protocol_changes::map_protocol_changes; +pub use store_pools::store_pools; +use substreams_ethereum::pb::eth::v2::TransactionTrace; + +use crate::pb::uniswap::v3::Transaction; + +#[path = "1_map_pool_created.rs"] +mod map_pool_created; + +#[path = "2_store_pools.rs"] +mod store_pools; + +#[path = "3_map_events.rs"] +mod map_events; + +#[path = "4_map_and_store_balance_changes.rs"] +mod map_store_balance_changes; + +#[path = "4_map_and_store_ticks.rs"] +mod map_store_ticks; + +#[path = "4_map_and_store_liquidity.rs"] +mod map_store_liquidity; + +#[path = "5_map_protocol_changes.rs"] +mod map_protocol_changes; + +impl From for Transaction { + fn from(value: TransactionTrace) -> Self { + Self { hash: value.hash, from: value.from, to: value.to, index: value.index.into() } + } +} + +impl From for tycho_substreams::prelude::Transaction { + fn from(value: Transaction) -> Self { + Self { hash: value.hash, from: value.from, to: value.to, index: value.index } + } +} diff --git a/substreams/ethereum-uniswap-v3-logs-only/src/pb/mod.rs b/substreams/ethereum-uniswap-v3-logs-only/src/pb/mod.rs new file mode 100644 index 0000000..83e1f97 --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/src/pb/mod.rs @@ -0,0 +1,8 @@ +// @generated +pub mod uniswap { + // @@protoc_insertion_point(attribute:uniswap.v3) + pub mod v3 { + include!("uniswap.v3.rs"); + // @@protoc_insertion_point(uniswap.v3) + } +} diff --git a/substreams/ethereum-uniswap-v3-logs-only/src/pb/uniswap.v3.rs b/substreams/ethereum-uniswap-v3-logs-only/src/pb/uniswap.v3.rs new file mode 100644 index 0000000..14cb7ce --- /dev/null +++ b/substreams/ethereum-uniswap-v3-logs-only/src/pb/uniswap.v3.rs @@ -0,0 +1,298 @@ +// @generated +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Pool { + #[prost(bytes="vec", tag="1")] + pub address: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="2")] + pub token0: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="3")] + pub token1: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="4")] + pub created_tx_hash: ::prost::alloc::vec::Vec, +} +/// A struct describing a transaction. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Transaction { + /// The transaction hash. + #[prost(bytes="vec", tag="1")] + pub hash: ::prost::alloc::vec::Vec, + /// The sender of the transaction. + #[prost(bytes="vec", tag="2")] + pub from: ::prost::alloc::vec::Vec, + /// The receiver of the transaction. + #[prost(bytes="vec", tag="3")] + pub to: ::prost::alloc::vec::Vec, + /// The transactions index within the block. + #[prost(uint64, tag="4")] + pub index: u64, +} +/// A change to a pool's tick. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TickDelta { + /// The address of the pool. + #[prost(bytes="vec", tag="1")] + pub pool_address: ::prost::alloc::vec::Vec, + /// The index of the tick. + #[prost(int32, tag="2")] + pub tick_index: i32, + /// The liquidity net delta of this tick. Bigint encoded as signed little endian bytes. + #[prost(bytes="vec", tag="3")] + pub liquidity_net_delta: ::prost::alloc::vec::Vec, + /// Used to determine the order of the balance changes. Necessary for the balance store. + #[prost(uint64, tag="4")] + pub ordinal: u64, + #[prost(message, optional, tag="5")] + pub transaction: ::core::option::Option, +} +/// A group of TickDelta +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TickDeltas { + #[prost(message, repeated, tag="1")] + pub deltas: ::prost::alloc::vec::Vec, +} +/// A change to a pool's liquidity. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LiquidityChange { + /// The address of the pool. + #[prost(bytes="vec", tag="1")] + pub pool_address: ::prost::alloc::vec::Vec, + /// The liquidity changed amount. Bigint encoded as signed little endian bytes. + #[prost(bytes="vec", tag="2")] + pub value: ::prost::alloc::vec::Vec, + /// The type of update, can be absolute or delta. + #[prost(enumeration="LiquidityChangeType", tag="3")] + pub change_type: i32, + /// Used to determine the order of the balance changes. Necessary for the balance store. + #[prost(uint64, tag="4")] + pub ordinal: u64, + #[prost(message, optional, tag="5")] + pub transaction: ::core::option::Option, +} +/// A group of LiquidityChange +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LiquidityChanges { + #[prost(message, repeated, tag="1")] + pub changes: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Events { + #[prost(message, repeated, tag="3")] + pub pool_events: ::prost::alloc::vec::Vec, +} +/// Nested message and enum types in `Events`. +pub mod events { + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct PoolEvent { + #[prost(uint64, tag="100")] + pub log_ordinal: u64, + #[prost(string, tag="102")] + pub pool_address: ::prost::alloc::string::String, + #[prost(string, tag="103")] + pub token0: ::prost::alloc::string::String, + #[prost(string, tag="104")] + pub token1: ::prost::alloc::string::String, + #[prost(message, optional, tag="105")] + pub transaction: ::core::option::Option, + #[prost(oneof="pool_event::Type", tags="1, 2, 3, 4, 5, 6, 7, 8")] + pub r#type: ::core::option::Option, + } + /// Nested message and enum types in `PoolEvent`. + pub mod pool_event { + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct Initialize { + /// Unsigned + #[prost(string, tag="1")] + pub sqrt_price: ::prost::alloc::string::String, + #[prost(int32, tag="2")] + pub tick: i32, + } + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct Mint { + #[prost(string, tag="1")] + pub sender: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub owner: ::prost::alloc::string::String, + /// Signed + #[prost(int32, tag="3")] + pub tick_lower: i32, + /// Signed + #[prost(int32, tag="4")] + pub tick_upper: i32, + /// Unsigned + #[prost(string, tag="5")] + pub amount: ::prost::alloc::string::String, + /// Unsigned + #[prost(string, tag="6")] + pub amount_0: ::prost::alloc::string::String, + /// Unsigned + #[prost(string, tag="7")] + pub amount_1: ::prost::alloc::string::String, + } + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct Collect { + #[prost(string, tag="1")] + pub owner: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub recipient: ::prost::alloc::string::String, + #[prost(int32, tag="3")] + pub tick_lower: i32, + #[prost(int32, tag="4")] + pub tick_upper: i32, + /// Unsigned + #[prost(string, tag="5")] + pub amount_0: ::prost::alloc::string::String, + /// Unsigned + #[prost(string, tag="6")] + pub amount_1: ::prost::alloc::string::String, + } + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct Burn { + #[prost(string, tag="1")] + pub owner: ::prost::alloc::string::String, + #[prost(int32, tag="2")] + pub tick_lower: i32, + #[prost(int32, tag="3")] + pub tick_upper: i32, + /// Unsigned + #[prost(string, tag="4")] + pub amount: ::prost::alloc::string::String, + /// Unsigned + #[prost(string, tag="5")] + pub amount_0: ::prost::alloc::string::String, + /// Unsigned + #[prost(string, tag="6")] + pub amount_1: ::prost::alloc::string::String, + } + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct Swap { + #[prost(string, tag="1")] + pub sender: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub recipient: ::prost::alloc::string::String, + /// Signed + #[prost(string, tag="3")] + pub amount_0: ::prost::alloc::string::String, + /// Signed + #[prost(string, tag="4")] + pub amount_1: ::prost::alloc::string::String, + /// Unsigned + #[prost(string, tag="6")] + pub sqrt_price: ::prost::alloc::string::String, + /// Unsigned + #[prost(string, tag="7")] + pub liquidity: ::prost::alloc::string::String, + #[prost(int32, tag="8")] + pub tick: i32, + } + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct Flash { + #[prost(string, tag="1")] + pub sender: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub recipient: ::prost::alloc::string::String, + /// Unsigned + #[prost(string, tag="3")] + pub amount_0: ::prost::alloc::string::String, + /// Unsigned + #[prost(string, tag="4")] + pub amount_1: ::prost::alloc::string::String, + /// Unsigned + #[prost(string, tag="5")] + pub paid_0: ::prost::alloc::string::String, + /// Unsigned + #[prost(string, tag="6")] + pub paid_1: ::prost::alloc::string::String, + } + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct SetFeeProtocol { + /// Unsigned + #[prost(uint64, tag="1")] + pub fee_protocol_0_old: u64, + /// Unsigned + #[prost(uint64, tag="2")] + pub fee_protocol_1_old: u64, + /// Unsigned + #[prost(uint64, tag="3")] + pub fee_protocol_0_new: u64, + /// Unsigned + #[prost(uint64, tag="4")] + pub fee_protocol_1_new: u64, + } + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct CollectProtocol { + #[prost(string, tag="1")] + pub sender: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub recipient: ::prost::alloc::string::String, + /// Unsigned + #[prost(string, tag="3")] + pub amount_0: ::prost::alloc::string::String, + /// Unsigned + #[prost(string, tag="4")] + pub amount_1: ::prost::alloc::string::String, + } + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Type { + #[prost(message, tag="1")] + Initialize(Initialize), + #[prost(message, tag="2")] + Mint(Mint), + #[prost(message, tag="3")] + Collect(Collect), + #[prost(message, tag="4")] + Burn(Burn), + #[prost(message, tag="5")] + Swap(Swap), + #[prost(message, tag="6")] + Flash(Flash), + #[prost(message, tag="7")] + SetFeeProtocol(SetFeeProtocol), + #[prost(message, tag="8")] + CollectProtocol(CollectProtocol), + } + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum LiquidityChangeType { + Delta = 0, + Absolute = 1, +} +impl LiquidityChangeType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + LiquidityChangeType::Delta => "DELTA", + LiquidityChangeType::Absolute => "ABSOLUTE", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "DELTA" => Some(Self::Delta), + "ABSOLUTE" => Some(Self::Absolute), + _ => None, + } + } +} +// @@protoc_insertion_point(module) diff --git a/substreams/rustfmt.toml b/substreams/rustfmt.toml index f427b9e..d6d891f 100644 --- a/substreams/rustfmt.toml +++ b/substreams/rustfmt.toml @@ -15,4 +15,5 @@ ignore = [ "ethereum-curve/src/abi", "ethereum-uniswap-v2/src/abi", "ethereum-uniswap-v3/src/abi", + "ethereum-uniswap-v3-logs-only/src/abi", ]