From 093a64a7a05ab381b1bdcaaf5856bad0ce562724 Mon Sep 17 00:00:00 2001 From: kayibal Date: Tue, 28 Jan 2025 18:17:36 -0300 Subject: [PATCH 1/8] feat(template): More detailed template. Add a more detailed protocol implementation in the template. This should allow more ppl to get started quicker. Additionally more people will follow a predetermined structure --- substreams/Cargo.lock | 60 +- substreams/Cargo.toml | 1 + .../ethereum-balancer-v2/src/modules.rs | 4 +- substreams/ethereum-template/Cargo.toml | 12 + substreams/ethereum-template/abi/erc20.json | 222 +++ substreams/ethereum-template/build.rs | 49 + substreams/ethereum-template/src/abi/erc20.rs | 1257 +++++++++++++++++ substreams/ethereum-template/src/abi/mod.rs | 2 + substreams/ethereum-template/src/lib.rs | 12 +- substreams/ethereum-template/src/modules.rs | 12 - .../ethereum-template/src/modules_factory.rs | 265 ++++ .../ethereum-template/src/pool_factories.rs | 44 + 12 files changed, 1900 insertions(+), 40 deletions(-) create mode 100644 substreams/ethereum-template/abi/erc20.json create mode 100644 substreams/ethereum-template/build.rs create mode 100644 substreams/ethereum-template/src/abi/erc20.rs create mode 100644 substreams/ethereum-template/src/abi/mod.rs delete mode 100644 substreams/ethereum-template/src/modules.rs create mode 100644 substreams/ethereum-template/src/modules_factory.rs create mode 100644 substreams/ethereum-template/src/pool_factories.rs diff --git a/substreams/Cargo.lock b/substreams/Cargo.lock index 63e0b591f..e7a89b826 100644 --- a/substreams/Cargo.lock +++ b/substreams/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "arrayvec" @@ -300,6 +300,23 @@ dependencies = [ "tycho-substreams 0.2.0 (git+https://github.com/propeller-heads/tycho-protocol-sdk.git?rev=b8aeaa3)", ] +[[package]] +name = "ethereum-template" +version = "0.1.0" +dependencies = [ + "anyhow", + "ethabi 18.0.0", + "hex", + "itertools 0.10.5", + "num-bigint", + "prost 0.11.9", + "serde", + "serde-sibor", + "substreams", + "substreams-ethereum", + "tycho-substreams 0.2.0 (git+https://github.com/propeller-heads/tycho-protocol-sdk.git?rev=b8aeaa3)", +] + [[package]] name = "ethereum-types" version = "0.13.1" @@ -606,11 +623,10 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", ] @@ -711,7 +727,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.96", ] [[package]] @@ -789,9 +805,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -861,7 +877,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.96", ] [[package]] @@ -993,22 +1009,32 @@ checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] +[[package]] +name = "serde-sibor" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859877cf5123a0b2c03e92b01c0b7adefb5ea0b6e6a390f2f7107b85783eee14" +dependencies = [ + "serde", + "thiserror", +] + [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.96", ] [[package]] @@ -1265,9 +1291,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.52" +version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", @@ -1309,7 +1335,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.96", ] [[package]] diff --git a/substreams/Cargo.toml b/substreams/Cargo.toml index 0b4d12cbe..21f7059d1 100644 --- a/substreams/Cargo.toml +++ b/substreams/Cargo.toml @@ -10,6 +10,7 @@ members = [ "ethereum-sfrax", "ethereum-sfraxeth", "ethereum-uniswap-v3-logs-only", + "ethereum-template", ] resolver = "2" diff --git a/substreams/ethereum-balancer-v2/src/modules.rs b/substreams/ethereum-balancer-v2/src/modules.rs index 448ea62c2..8a5dd4280 100644 --- a/substreams/ethereum-balancer-v2/src/modules.rs +++ b/substreams/ethereum-balancer-v2/src/modules.rs @@ -58,7 +58,7 @@ pub fn store_components(map: BlockTransactionProtocolComponents, store: StoreSet } /// Since the `PoolBalanceChanged` and `Swap` events administer only deltas, we need to leverage a -/// map and a store to be able to tally up final balances for tokens in a pool. +/// map and a store to be able to tally up final balances for tokens in a pool. #[substreams::handlers::map] pub fn map_relative_balances( block: eth::v2::Block, @@ -253,7 +253,7 @@ pub fn map_protocol_changes( let id = components_store .get_last(format!("pool:0x{}", hex::encode(address))) .unwrap(); // Shouldn't happen because we filter by known components in - // `extract_contract_changes_builder` + // `extract_contract_changes_builder` change.mark_component_as_updated(&id); } }) diff --git a/substreams/ethereum-template/Cargo.toml b/substreams/ethereum-template/Cargo.toml index 63ac7a2ec..acbb0e8e9 100644 --- a/substreams/ethereum-template/Cargo.toml +++ b/substreams/ethereum-template/Cargo.toml @@ -12,3 +12,15 @@ substreams = "0.5.22" substreams-ethereum = "0.9.9" prost = "0.11" tycho-substreams = { git = "https://github.com/propeller-heads/tycho-protocol-sdk.git", rev = "b8aeaa3" } +anyhow = "1.0.95" +ethabi = "18.0.0" +num-bigint = "0.4.6" +hex = "0.4.3" +itertools = "0.10.5" +serde = "1.0.217" +serde-sibor = "0.1.0" + + +[build-dependencies] +anyhow = "1" +substreams-ethereum = "0.9.9" diff --git a/substreams/ethereum-template/abi/erc20.json b/substreams/ethereum-template/abi/erc20.json new file mode 100644 index 000000000..3b0ab2f1a --- /dev/null +++ b/substreams/ethereum-template/abi/erc20.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] \ No newline at end of file diff --git a/substreams/ethereum-template/build.rs b/substreams/ethereum-template/build.rs new file mode 100644 index 000000000..5e7bd34c5 --- /dev/null +++ b/substreams/ethereum-template/build.rs @@ -0,0 +1,49 @@ +use anyhow::Result; +use std::{fs, io::Write}; +use substreams_ethereum::Abigen; + +fn main() -> Result<()> { + let abi_folder = "abi"; + let output_folder = "src/abi"; + + let abis = fs::read_dir(abi_folder)?; + + let mut files = abis.collect::, _>>()?; + + // Sort the files by their name + files.sort_by_key(|a| a.file_name()); + + let mut mod_rs_content = String::new(); + mod_rs_content.push_str("#![allow(clippy::all)]\n"); + + for file in files { + let file_name = file.file_name(); + let file_name = file_name.to_string_lossy(); + + if !file_name.ends_with(".json") { + continue; + } + + let contract_name = file_name.split('.').next().unwrap(); + + let input_path = format!("{}/{}", abi_folder, file_name); + let output_path = format!("{}/{}.rs", output_folder, contract_name); + + mod_rs_content.push_str(&format!("pub mod {};\n", contract_name)); + + if std::path::Path::new(&output_path).exists() { + continue; + } + + Abigen::new(contract_name, &input_path)? + .generate()? + .write_to_file(&output_path)?; + } + + let mod_rs_path = format!("{}/mod.rs", output_folder); + let mut mod_rs_file = fs::File::create(mod_rs_path)?; + + mod_rs_file.write_all(mod_rs_content.as_bytes())?; + + Ok(()) +} diff --git a/substreams/ethereum-template/src/abi/erc20.rs b/substreams/ethereum-template/src/abi/erc20.rs new file mode 100644 index 000000000..b7b3a395b --- /dev/null +++ b/substreams/ethereum-template/src/abi/erc20.rs @@ -0,0 +1,1257 @@ + 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 Allowance { + pub owner: Vec, + pub spender: Vec, + } + impl Allowance { + const METHOD_ID: [u8; 4] = [221u8, 98u8, 237u8, 62u8]; + 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], + 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(), + spender: 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)), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.spender), + ), + ], + ); + 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 Allowance { + const NAME: &'static str = "allowance"; + 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 Allowance { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Approve { + pub spender: Vec, + pub value: substreams::scalar::BigInt, + } + impl Approve { + const METHOD_ID: [u8; 4] = [9u8, 94u8, 167u8, 179u8]; + 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)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + spender: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + 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.spender), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.value.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::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .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 { + 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 Approve { + const NAME: &'static str = "approve"; + 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 Approve { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct BalanceOf { + pub owner: Vec, + } + impl BalanceOf { + const METHOD_ID: [u8; 4] = [112u8, 160u8, 130u8, 49u8]; + 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 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 BalanceOf { + const NAME: &'static str = "balanceOf"; + 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 BalanceOf { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Decimals {} + impl Decimals { + const METHOD_ID: [u8; 4] = [49u8, 60u8, 229u8, 103u8]; + 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(8usize)], + 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 Decimals { + const NAME: &'static str = "decimals"; + 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 Decimals { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Name {} + impl Name { + const METHOD_ID: [u8; 4] = [6u8, 253u8, 222u8, 3u8]; + 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::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .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 { + 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 Name { + const NAME: &'static str = "name"; + 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 Name { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Symbol {} + impl Symbol { + const METHOD_ID: [u8; 4] = [149u8, 216u8, 155u8, 65u8]; + 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::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .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 { + 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 Symbol { + const NAME: &'static str = "symbol"; + 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 Symbol { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct TotalSupply {} + impl TotalSupply { + const METHOD_ID: [u8; 4] = [24u8, 22u8, 13u8, 221u8]; + 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 TotalSupply { + const NAME: &'static str = "totalSupply"; + 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 TotalSupply { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Transfer { + pub to: Vec, + pub value: substreams::scalar::BigInt, + } + impl Transfer { + const METHOD_ID: [u8; 4] = [169u8, 5u8, 156u8, 187u8]; + 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)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + to: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + 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.to)), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.value.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::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .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 { + 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 Transfer { + const NAME: &'static str = "transfer"; + 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 Transfer { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct TransferFrom { + pub from: Vec, + pub to: Vec, + pub value: substreams::scalar::BigInt, + } + impl TransferFrom { + const METHOD_ID: [u8; 4] = [35u8, 184u8, 114u8, 221u8]; + 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(256usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + from: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + to: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + 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.from)), + ethabi::Token::Address(ethabi::Address::from_slice(&self.to)), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.value.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::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .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 { + 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 TransferFrom { + const NAME: &'static str = "transferFrom"; + 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 TransferFrom { + fn output(data: &[u8]) -> Result { + 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 Approval { + pub owner: Vec, + pub spender: Vec, + pub value: substreams::scalar::BigInt, + } + impl Approval { + const TOPIC_ID: [u8; 32] = [ + 140u8, + 91u8, + 225u8, + 229u8, + 235u8, + 236u8, + 125u8, + 91u8, + 209u8, + 79u8, + 113u8, + 66u8, + 125u8, + 30u8, + 132u8, + 243u8, + 221u8, + 3u8, + 20u8, + 192u8, + 247u8, + 178u8, + 41u8, + 30u8, + 91u8, + 32u8, + 10u8, + 200u8, + 199u8, + 195u8, + 185u8, + 37u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 32usize { + 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)], + 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(), + spender: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'spender' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + 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 Approval { + const NAME: &'static str = "Approval"; + 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 Transfer { + pub from: Vec, + pub to: Vec, + pub value: substreams::scalar::BigInt, + } + impl Transfer { + const TOPIC_ID: [u8; 32] = [ + 221u8, + 242u8, + 82u8, + 173u8, + 27u8, + 226u8, + 200u8, + 155u8, + 105u8, + 194u8, + 176u8, + 104u8, + 252u8, + 55u8, + 141u8, + 170u8, + 149u8, + 43u8, + 167u8, + 241u8, + 99u8, + 196u8, + 161u8, + 22u8, + 40u8, + 245u8, + 90u8, + 77u8, + 245u8, + 35u8, + 179u8, + 239u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 32usize { + 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)], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + from: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'from' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + to: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'to' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + 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 Transfer { + const NAME: &'static str = "Transfer"; + 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-template/src/abi/mod.rs b/substreams/ethereum-template/src/abi/mod.rs new file mode 100644 index 000000000..4542b55b8 --- /dev/null +++ b/substreams/ethereum-template/src/abi/mod.rs @@ -0,0 +1,2 @@ +#![allow(clippy::all)] +pub mod erc20; diff --git a/substreams/ethereum-template/src/lib.rs b/substreams/ethereum-template/src/lib.rs index 94324fd1d..4e5889a56 100644 --- a/substreams/ethereum-template/src/lib.rs +++ b/substreams/ethereum-template/src/lib.rs @@ -1,9 +1,3 @@ -use substreams_ethereum::pb::eth; -mod modules; - -#[substreams::handlers::map] -fn map_changes( - block: eth::v2::Block, -) -> Result { - todo!("Not implemented") -} +mod modules_factory; +mod abi; +mod pool_factories; diff --git a/substreams/ethereum-template/src/modules.rs b/substreams/ethereum-template/src/modules.rs deleted file mode 100644 index 136d351c6..000000000 --- a/substreams/ethereum-template/src/modules.rs +++ /dev/null @@ -1,12 +0,0 @@ -use std::collections::HashMap; -use substreams_ethereum::pb::eth; -use tycho_substreams::prelude::*; - -#[substreams::handlers::map] -fn map_protocol_changes( - block: eth::v2::Block, -) -> Result { - let mut transaction_contract_changes = Vec::::new(); - // TODO: protocol specific logic goes here - Ok(BlockContractChanges { block: Some((&block).into()), changes: transaction_contract_changes }) -} diff --git a/substreams/ethereum-template/src/modules_factory.rs b/substreams/ethereum-template/src/modules_factory.rs new file mode 100644 index 000000000..84d1ab5cb --- /dev/null +++ b/substreams/ethereum-template/src/modules_factory.rs @@ -0,0 +1,265 @@ +//! Template for Protocols with contract factories +//! +//! This template provides foundational maps and store substream modules for indexing a +//! protocol where each component (e.g., pool) is deployed to a separate contract. Each +//! contract is expected to escrow its ERC-20 token balances. +//! +//! If your protocol supports native ETH, you may need to adjust the balance tracking +//! logic in `map_relative_component_balance` to account for native token handling. +//! +//! ## Alternative Module +//! If your protocol uses a vault-like contract to manage balances, or if pools are +//! registered within a singleton contract, refer to the `modules_singleton` module +//! for an appropriate alternative. +//! +//! ## Warning +//! This template provides a general framework for indexing a protocol. However, it is +//! likely that you will need to adapt the steps to suit your specific use case. Use the +//! provided code with care and ensure you fully understand each step before proceeding +//! with your implementation. +//! +//! ## Example Use Case +//! For an Uniswap-like protocol where each liquidity pool is deployed as a separate +//! contract, you can use this template to: +//! - Track relative component balances (e.g., ERC-20 token balances in each pool). +//! - Index individual pool contracts as they are created by the factory contract. +//! +//! Adjustments to the template may include: +//! - Handling native ETH balances alongside token balances. +//! - Customizing indexing logic for specific factory contract behavior. +use std::collections::HashMap; +use anyhow::Result; +use substreams::pb::substreams::StoreDeltas; +use substreams::prelude::*; +use substreams_ethereum::Event; +use substreams_ethereum::pb::eth; +use tycho_substreams::balances::aggregate_balances_changes; +use tycho_substreams::contract::extract_contract_changes_builder; +use tycho_substreams::prelude::*; +use itertools::Itertools; +use crate::pool_factories; + +/// Find and create all relevant protocol components +/// +/// This method maps over blocks and instantiates ProtocolComponents with a unique ids +/// as well as all necessary metadata for routing and encoding. +#[substreams::handlers::map] +fn map_protocol_components( + block: eth::v2::Block +) -> Result { + Ok(BlockTransactionProtocolComponents { + tx_components: block + .transactions() + .filter_map(|tx| { + let components = tx + .logs_with_calls() + .filter_map(|(log, call)| { + // TODO: ensure this method is implemented correctly + pool_factories::maybe_create_component( + call.call, + log, + tx, + ) + }) + .collect::>(); + + if !components.is_empty() { + Some(TransactionProtocolComponents { tx: Some(tx.into()), components }) + } else { + None + } + }) + .collect::>(), + }) +} + +/// Stores all protocol components in a store. +/// +/// Stores information about components in a key value store. This is only necessary if +/// you need to access the whole set of components within your indexing logic. +/// +/// Popular use cases are: +/// - Checking if a contract belongs to a component. In this case suggest to use an +/// address as the store key so lookup operations are O(1). +/// - Tallying up relative balances changes to calcualte absolute erc20 token balances +/// per component. +/// +/// Usually you can skip this step if: +/// - You are interested in a static set of components only +/// - Your protocol emits balance change events with absolute values +#[substreams::handlers::store] +fn store_protocol_components(map_protocol_components: BlockTransactionProtocolComponents, store: StoreSetRaw) { + map_protocol_components.tx_components + .into_iter() + .for_each(|tx_pc| { + tx_pc + .components + .into_iter() + .for_each(|pc| { + // Assumes that the component id is a hex encoded contract address + let key = pc.id.clone(); + // we store the components tokens + // TODO: proper error handling + let val = serde_sibor::to_bytes(&pc.tokens).unwrap(); + store.set(0, key, &val); + }) + }); +} + +/// Extracts balance changes per component +/// +/// This template function uses ERC20 transfer events to extract balance changes. It +/// assumes that each component is deployed at a dedicated contract address. If a +/// transfer to the component is detected, it's balanced is increased and if a balance +/// from the component is detected its balance is decreased. +/// +/// ## Note: +/// Changes are necessary if your protocol uses native ETH, uses a vault contract or if +/// your component burn or mint tokens without emitting transfer events. +/// +/// You may want to ignore LP tokens if your protocol emits transfer events for these +/// here. +#[substreams::handlers::map] +fn map_relative_component_balance(block: eth::v2::Block, store: StoreGetRaw) -> Result { + let res = block.logs() + .filter_map(|log| { + crate::abi::erc20::events::Transfer::match_and_decode(log).map(|transfer| { + let to_addr = hex::encode(transfer.to.as_slice()); + let from_addr = hex::encode(transfer.from.as_slice()); + let tx = log.receipt.transaction; + if let Some(val) = store.get_last(&to_addr) { + let component_tokens: Vec> = serde_sibor::from_bytes(&val).unwrap(); + if component_tokens.contains(&log.address().to_vec()) { + return Some(BalanceDelta { + ord: log.ordinal(), + tx: Some(tx.into()), + token: log.address().to_vec(), + delta: transfer.value.to_signed_bytes_be(), + component_id: to_addr.into_bytes(), + }); + } + } else if let Some(val) = store.get_last(&from_addr) { + let component_tokens: Vec> = serde_sibor::from_bytes(&val).unwrap(); + if component_tokens.contains(&log.address().to_vec()) { + return Some(BalanceDelta { + ord: log.ordinal(), + tx: Some(tx.into()), + token: log.address().to_vec(), + delta: (transfer.value.neg()).to_signed_bytes_be(), + component_id: to_addr.into_bytes(), + }); + } + } + None + }) + }) + .flatten() + .collect::>(); + + Ok(BlockBalanceDeltas { balance_deltas: res }) +} + +/// Aggregates relative balances values into absolute values +/// +/// Aggregate the relative balances in an additive store since tycho-indexer expects +/// absolute balance inputs. +/// +/// ## Note: +/// This method should usually not require any changes. +#[substreams::handlers::store] +pub fn store_balances(deltas: BlockBalanceDeltas, store: StoreAddBigInt) { + tycho_substreams::balances::store_balance_changes(deltas, store); +} + +/// Aggregates protocol components and balance changes by transaction. +/// +/// This is the main method that will aggregate all changes as well as extract all +/// relevant contract storage deltas. +/// +/// ## Note: +/// You may have to change this method if your components have any default dynamic +/// attributes, or if you need any additional static contracts indexed. +#[substreams::handlers::map] +fn map_protocol_changes( + block: eth::v2::Block, + new_components: BlockTransactionProtocolComponents, + components_store: StoreGetRaw, + balance_store: StoreDeltas, + deltas: BlockBalanceDeltas, +) -> 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(); + + // Aggregate newly created components per tx + new_components + .tx_components + .iter() + .for_each(|tx_component| { + // initialise builder if not yet present for this tx + let tx = tx_component.tx.as_ref().unwrap(); + let builder = transaction_changes + .entry(tx.index) + .or_insert_with(|| TransactionChangesBuilder::new(tx)); + + // iterate over individual components created within this tx + tx_component + .components + .iter() + .for_each(|component| { + builder.add_protocol_component(component); + // TODO: In case you require to add any dynamic attributes to the + // component you can do so here: + /* + builder.add_entity_change(&EntityChanges { + component_id: component.id.clone(), + attributes: default_attributes.clone(), + }); + */ + }); + }); + + // Aggregate absolute balances per transaction. + aggregate_balances_changes(balance_store, 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)) + }); + }); + + + // Extract and insert any storage changes that happened for any of the components. + extract_contract_changes_builder( + &block, + |addr| { + // we assume that the store holds contract addresses as keys and if it + // contains a value, that contract is of relevance. + // TODO: if you have any additional static contracts that need to be indexed, + // please add them here. + components_store + .get_last(hex::encode(addr)) + .is_some() + }, + &mut transaction_changes, + ); + + + // Process all `transaction_changes` for final output in the `BlockChanges`, + // sorted by transaction index (the key). + Ok(BlockChanges { + block: Some((&block).into()), + changes: transaction_changes + .drain() + .sorted_unstable_by_key(|(index, _)| *index) + .filter_map(|(_, builder)| builder.build()) + .collect::>(), + }) +} diff --git a/substreams/ethereum-template/src/pool_factories.rs b/substreams/ethereum-template/src/pool_factories.rs new file mode 100644 index 000000000..3078f9c8e --- /dev/null +++ b/substreams/ethereum-template/src/pool_factories.rs @@ -0,0 +1,44 @@ +use substreams::hex; +use substreams_ethereum::pb::eth::v2::{Call, Log, TransactionTrace}; +use tycho_substreams::models::{ChangeType, FinancialType, ImplementationType, ProtocolComponent, ProtocolType}; + + +/// Potentially constructs a new ProtocolComponent given a call +/// +/// This method is given each individual call within a transaction, the corresponding +/// logs emitted during that call as well as the full transaction trace. +/// +/// If this call creates a component in your protocol please contstruct and return it +/// here. Otherwise, simply return None. +pub fn maybe_create_component( + call: &Call, + _log: &Log, + tx: &TransactionTrace, +) -> Option { + match *call.address { + // TODO: replace with your logic + hex!("0000000000000000000000000000000000000000") => { + Some(ProtocolComponent { + id: "".to_string(), + tokens: vec![ + // TODO: add the components tokens + ], + contracts: vec![ + // TODO: any contracts required during swapping + ], + static_att: vec![ + // TODO: any additional metadata required, e.g. for swap encoding + ], + change: ChangeType::Creation.into(), + protocol_type: Some(ProtocolType { + name: "template".to_string(), + financial_type: FinancialType::Swap.into(), + attribute_schema: vec![], + implementation_type: ImplementationType::Vm.into(), + }), + tx: Some(tx.into()), + }) + } + _ => None, + } +} \ No newline at end of file From 2b367893147b0253dfddbacb4732f69dbd840001 Mon Sep 17 00:00:00 2001 From: kayibal Date: Thu, 30 Jan 2025 15:54:25 -0300 Subject: [PATCH 2/8] feat(template): Add template for singleton protocols. Separate templates and add one for protocols with only a single contract. --- .gitignore | 2 +- substreams/Cargo.lock | 41 +- substreams/Cargo.toml | 3 +- .../Cargo.toml | 6 +- .../abi/erc20.json | 0 .../buf.gen.yaml | 0 .../build.rs | 0 .../integration_test.tycho.yaml | 0 .../src/abi/erc20.rs | 0 .../src/abi/mod.rs | 0 .../src/lib.rs | 3 +- .../src/modules.rs} | 0 .../src/pool_factories.rs | 3 +- .../ethereum-template-factory/substreams.yaml | 64 + .../ethereum-template-singleton/Cargo.toml | 27 + .../abi/erc20.json | 222 +++ .../ethereum-template-singleton/buf.gen.yaml | 12 + .../ethereum-template-singleton/build.rs | 49 + .../integration_test.tycho.yaml | 57 + .../src/abi/erc20.rs | 1257 +++++++++++++++++ .../src/abi/mod.rs | 2 + .../ethereum-template-singleton/src/lib.rs | 4 + .../src/modules.rs | 246 ++++ .../src/pool_factories.rs | 50 + .../substreams.yaml | 73 + substreams/ethereum-template/substreams.yaml | 25 - 26 files changed, 2111 insertions(+), 35 deletions(-) rename substreams/{ethereum-template => ethereum-template-factory}/Cargo.toml (78%) rename substreams/{ethereum-template => ethereum-template-factory}/abi/erc20.json (100%) rename substreams/{ethereum-template => ethereum-template-factory}/buf.gen.yaml (100%) rename substreams/{ethereum-template => ethereum-template-factory}/build.rs (100%) rename substreams/{ethereum-template => ethereum-template-factory}/integration_test.tycho.yaml (100%) rename substreams/{ethereum-template => ethereum-template-factory}/src/abi/erc20.rs (100%) rename substreams/{ethereum-template => ethereum-template-factory}/src/abi/mod.rs (100%) rename substreams/{ethereum-template => ethereum-template-factory}/src/lib.rs (58%) rename substreams/{ethereum-template/src/modules_factory.rs => ethereum-template-factory/src/modules.rs} (100%) rename substreams/{ethereum-template => ethereum-template-factory}/src/pool_factories.rs (96%) create mode 100644 substreams/ethereum-template-factory/substreams.yaml create mode 100644 substreams/ethereum-template-singleton/Cargo.toml create mode 100644 substreams/ethereum-template-singleton/abi/erc20.json create mode 100644 substreams/ethereum-template-singleton/buf.gen.yaml create mode 100644 substreams/ethereum-template-singleton/build.rs create mode 100644 substreams/ethereum-template-singleton/integration_test.tycho.yaml create mode 100644 substreams/ethereum-template-singleton/src/abi/erc20.rs create mode 100644 substreams/ethereum-template-singleton/src/abi/mod.rs create mode 100644 substreams/ethereum-template-singleton/src/lib.rs create mode 100644 substreams/ethereum-template-singleton/src/modules.rs create mode 100644 substreams/ethereum-template-singleton/src/pool_factories.rs create mode 100644 substreams/ethereum-template-singleton/substreams.yaml delete mode 100644 substreams/ethereum-template/substreams.yaml diff --git a/.gitignore b/.gitignore index 43d247ae4..6e0396a1e 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,7 @@ target/ __pycache__ -substreams/ethereum-template/Cargo.lock +substreams/ethereum-template-factory/Cargo.lock .DS_Store diff --git a/substreams/Cargo.lock b/substreams/Cargo.lock index e7a89b826..bb5ec2b6e 100644 --- a/substreams/Cargo.lock +++ b/substreams/Cargo.lock @@ -301,7 +301,7 @@ dependencies = [ ] [[package]] -name = "ethereum-template" +name = "ethereum-template-factory" version = "0.1.0" dependencies = [ "anyhow", @@ -314,7 +314,25 @@ dependencies = [ "serde-sibor", "substreams", "substreams-ethereum", - "tycho-substreams 0.2.0 (git+https://github.com/propeller-heads/tycho-protocol-sdk.git?rev=b8aeaa3)", + "tycho-substreams 0.2.0 (git+https://github.com/propeller-heads/tycho-protocol-sdk.git?rev=3c08359)", +] + +[[package]] +name = "ethereum-template-singleton" +version = "0.1.0" +dependencies = [ + "anyhow", + "ethabi 18.0.0", + "hex", + "itertools 0.10.5", + "num-bigint", + "prost 0.11.9", + "serde", + "serde-sibor", + "serde_qs", + "substreams", + "substreams-ethereum", + "tycho-substreams 0.2.0 (git+https://github.com/propeller-heads/tycho-protocol-sdk.git?rev=3c08359)", ] [[package]] @@ -464,6 +482,9 @@ name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] [[package]] name = "hex-literal" @@ -1379,6 +1400,22 @@ dependencies = [ "substreams-ethereum", ] +[[package]] +name = "tycho-substreams" +version = "0.2.0" +source = "git+https://github.com/propeller-heads/tycho-protocol-sdk.git?rev=3c08359#3c08359cf112e15c137dd5256b8dc8e9cd6c1626" +dependencies = [ + "ethabi 18.0.0", + "hex", + "itertools 0.12.1", + "num-bigint", + "prost 0.11.9", + "serde", + "serde_json", + "substreams", + "substreams-ethereum", +] + [[package]] name = "tycho-substreams" version = "0.2.0" diff --git a/substreams/Cargo.toml b/substreams/Cargo.toml index 21f7059d1..1d7dfe528 100644 --- a/substreams/Cargo.toml +++ b/substreams/Cargo.toml @@ -10,7 +10,8 @@ members = [ "ethereum-sfrax", "ethereum-sfraxeth", "ethereum-uniswap-v3-logs-only", - "ethereum-template", + "ethereum-template-factory", + "ethereum-template-singleton", ] resolver = "2" diff --git a/substreams/ethereum-template/Cargo.toml b/substreams/ethereum-template-factory/Cargo.toml similarity index 78% rename from substreams/ethereum-template/Cargo.toml rename to substreams/ethereum-template-factory/Cargo.toml index acbb0e8e9..9d4f94a27 100644 --- a/substreams/ethereum-template/Cargo.toml +++ b/substreams/ethereum-template-factory/Cargo.toml @@ -1,17 +1,17 @@ [package] -name = "ethereum-template" +name = "ethereum-template-factory" version = "0.1.0" edition = "2021" [lib] -name = "ethereum_template" +name = "ethereum_template_factory" crate-type = ["cdylib"] [dependencies] substreams = "0.5.22" substreams-ethereum = "0.9.9" prost = "0.11" -tycho-substreams = { git = "https://github.com/propeller-heads/tycho-protocol-sdk.git", rev = "b8aeaa3" } +tycho-substreams = { git = "https://github.com/propeller-heads/tycho-protocol-sdk.git", rev = "3c08359" } anyhow = "1.0.95" ethabi = "18.0.0" num-bigint = "0.4.6" diff --git a/substreams/ethereum-template/abi/erc20.json b/substreams/ethereum-template-factory/abi/erc20.json similarity index 100% rename from substreams/ethereum-template/abi/erc20.json rename to substreams/ethereum-template-factory/abi/erc20.json diff --git a/substreams/ethereum-template/buf.gen.yaml b/substreams/ethereum-template-factory/buf.gen.yaml similarity index 100% rename from substreams/ethereum-template/buf.gen.yaml rename to substreams/ethereum-template-factory/buf.gen.yaml diff --git a/substreams/ethereum-template/build.rs b/substreams/ethereum-template-factory/build.rs similarity index 100% rename from substreams/ethereum-template/build.rs rename to substreams/ethereum-template-factory/build.rs diff --git a/substreams/ethereum-template/integration_test.tycho.yaml b/substreams/ethereum-template-factory/integration_test.tycho.yaml similarity index 100% rename from substreams/ethereum-template/integration_test.tycho.yaml rename to substreams/ethereum-template-factory/integration_test.tycho.yaml diff --git a/substreams/ethereum-template/src/abi/erc20.rs b/substreams/ethereum-template-factory/src/abi/erc20.rs similarity index 100% rename from substreams/ethereum-template/src/abi/erc20.rs rename to substreams/ethereum-template-factory/src/abi/erc20.rs diff --git a/substreams/ethereum-template/src/abi/mod.rs b/substreams/ethereum-template-factory/src/abi/mod.rs similarity index 100% rename from substreams/ethereum-template/src/abi/mod.rs rename to substreams/ethereum-template-factory/src/abi/mod.rs diff --git a/substreams/ethereum-template/src/lib.rs b/substreams/ethereum-template-factory/src/lib.rs similarity index 58% rename from substreams/ethereum-template/src/lib.rs rename to substreams/ethereum-template-factory/src/lib.rs index 4e5889a56..b5b1fb665 100644 --- a/substreams/ethereum-template/src/lib.rs +++ b/substreams/ethereum-template-factory/src/lib.rs @@ -1,3 +1,4 @@ -mod modules_factory; mod abi; +mod modules; mod pool_factories; + diff --git a/substreams/ethereum-template/src/modules_factory.rs b/substreams/ethereum-template-factory/src/modules.rs similarity index 100% rename from substreams/ethereum-template/src/modules_factory.rs rename to substreams/ethereum-template-factory/src/modules.rs diff --git a/substreams/ethereum-template/src/pool_factories.rs b/substreams/ethereum-template-factory/src/pool_factories.rs similarity index 96% rename from substreams/ethereum-template/src/pool_factories.rs rename to substreams/ethereum-template-factory/src/pool_factories.rs index 3078f9c8e..647872d43 100644 --- a/substreams/ethereum-template/src/pool_factories.rs +++ b/substreams/ethereum-template-factory/src/pool_factories.rs @@ -13,7 +13,7 @@ use tycho_substreams::models::{ChangeType, FinancialType, ImplementationType, Pr pub fn maybe_create_component( call: &Call, _log: &Log, - tx: &TransactionTrace, + _tx: &TransactionTrace, ) -> Option { match *call.address { // TODO: replace with your logic @@ -36,7 +36,6 @@ pub fn maybe_create_component( attribute_schema: vec![], implementation_type: ImplementationType::Vm.into(), }), - tx: Some(tx.into()), }) } _ => None, diff --git a/substreams/ethereum-template-factory/substreams.yaml b/substreams/ethereum-template-factory/substreams.yaml new file mode 100644 index 000000000..5aa8ba7fb --- /dev/null +++ b/substreams/ethereum-template-factory/substreams.yaml @@ -0,0 +1,64 @@ +specVersion: v0.1.0 +package: + name: "ethereum_template" + version: v0.1.0 + +protobuf: + files: + - tycho/evm/v1/vm.proto + - tycho/evm/v1/common.proto + - tycho/evm/v1/utils.proto + importPaths: + - ../../proto + +binaries: + default: + type: wasm/rust-v1 + file: ../target/wasm32-unknown-unknown/release/ethereum_template.wasm + +modules: + - name: map_protocol_components + kind: map + initialBlock: 1 + inputs: + - source: sf.ethereum.type.v2.Block + output: + type: proto:tycho.evm.v1.BlockTransactionProtocolComponents + + - name: store_protocol_components + kind: store + initialBlock: 1 + updatePolicy: set + valueType: string + inputs: + - map: map_protocol_components + + - name: map_relative_component_balance + kind: map + initialBlock: 1 + inputs: + - source: sf.ethereum.type.v2.Block + - store: store_components + output: + type: proto:tycho.evm.v1.BlockBalanceDeltas + + - name: store_balances + kind: store + initialBlock: 1 + updatePolicy: add + valueType: bigint + inputs: + - map: map_relative_component_balance + + - name: map_protocol_changes + kind: map + initialBlock: 0 + inputs: + - source: sf.ethereum.type.v2.Block + - map: map_protocol_components + - map: map_relative_component_balance + - store: store_components + - store: store_balances + mode: deltas + output: + type: proto:tycho.evm.v1.BlockChanges diff --git a/substreams/ethereum-template-singleton/Cargo.toml b/substreams/ethereum-template-singleton/Cargo.toml new file mode 100644 index 000000000..93537f116 --- /dev/null +++ b/substreams/ethereum-template-singleton/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "ethereum-template-singleton" +version = "0.1.0" +edition = "2021" + +[lib] +name = "ethereum_template_singleton" +crate-type = ["cdylib"] + +[dependencies] +substreams = "0.5.22" +substreams-ethereum = "0.9.9" +prost = "0.11" +tycho-substreams = { git = "https://github.com/propeller-heads/tycho-protocol-sdk.git", rev = "3c08359" } +anyhow = "1.0.95" +ethabi = "18.0.0" +num-bigint = "0.4.6" +hex = { version = "0.4", features = ["serde"] } +itertools = "0.10.5" +serde = "1.0.217" +serde-sibor = "0.1.0" +serde_qs = "0.13.0" + + +[build-dependencies] +anyhow = "1" +substreams-ethereum = "0.9.9" diff --git a/substreams/ethereum-template-singleton/abi/erc20.json b/substreams/ethereum-template-singleton/abi/erc20.json new file mode 100644 index 000000000..3b0ab2f1a --- /dev/null +++ b/substreams/ethereum-template-singleton/abi/erc20.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] \ No newline at end of file diff --git a/substreams/ethereum-template-singleton/buf.gen.yaml b/substreams/ethereum-template-singleton/buf.gen.yaml new file mode 100644 index 000000000..d2e6544e9 --- /dev/null +++ b/substreams/ethereum-template-singleton/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-template-singleton/build.rs b/substreams/ethereum-template-singleton/build.rs new file mode 100644 index 000000000..5e7bd34c5 --- /dev/null +++ b/substreams/ethereum-template-singleton/build.rs @@ -0,0 +1,49 @@ +use anyhow::Result; +use std::{fs, io::Write}; +use substreams_ethereum::Abigen; + +fn main() -> Result<()> { + let abi_folder = "abi"; + let output_folder = "src/abi"; + + let abis = fs::read_dir(abi_folder)?; + + let mut files = abis.collect::, _>>()?; + + // Sort the files by their name + files.sort_by_key(|a| a.file_name()); + + let mut mod_rs_content = String::new(); + mod_rs_content.push_str("#![allow(clippy::all)]\n"); + + for file in files { + let file_name = file.file_name(); + let file_name = file_name.to_string_lossy(); + + if !file_name.ends_with(".json") { + continue; + } + + let contract_name = file_name.split('.').next().unwrap(); + + let input_path = format!("{}/{}", abi_folder, file_name); + let output_path = format!("{}/{}.rs", output_folder, contract_name); + + mod_rs_content.push_str(&format!("pub mod {};\n", contract_name)); + + if std::path::Path::new(&output_path).exists() { + continue; + } + + Abigen::new(contract_name, &input_path)? + .generate()? + .write_to_file(&output_path)?; + } + + let mod_rs_path = format!("{}/mod.rs", output_folder); + let mut mod_rs_file = fs::File::create(mod_rs_path)?; + + mod_rs_file.write_all(mod_rs_content.as_bytes())?; + + Ok(()) +} diff --git a/substreams/ethereum-template-singleton/integration_test.tycho.yaml b/substreams/ethereum-template-singleton/integration_test.tycho.yaml new file mode 100644 index 000000000..bea6aa301 --- /dev/null +++ b/substreams/ethereum-template-singleton/integration_test.tycho.yaml @@ -0,0 +1,57 @@ +# Name of the substreams config file in your substreams module. Usually "./substreams.yaml" +substreams_yaml_path: ./substreams.yaml +# Name of the adapter contract, usually: ProtocolSwapAdapter" +adapter_contract: "SwapAdapter" +# Constructor signature of the Adapter contract" +adapter_build_signature: "constructor(address)" +# A comma separated list of args to be passed to the contructor of the Adapter contract" +adapter_build_args: "0x0000000000000000000000000000000000000000" +# Whether or not the testing script should skip checking balances of the protocol components. +# If set to `true` please always add a reason why it's skipped. +skip_balance_check: false +# A list of accounts that need to be indexed to run the tests properly. +# Usually used when there is a global component required by all pools and created before the tested range of blocks. For example a factory or a vault. +# Please note that this component needs to be indexed by your substreams module, this feature is only for testing purpose. +# Also please always add a reason why this account is needed for your tests. +# This will be applied to each test. +initialized_accounts: + - "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84" # Needed for .... +# A list of protocol types names created by your Substreams module. +protocol_type_names: + - "type_name_1" + - "type_name_2" +# A list of tests. +tests: + # Name of the test + - name: test_pool_creation + # Indexed block range + start_block: 123 + stop_block: 456 + # Same as global `initialized_accounts` but only scoped to this test. + initialized_accounts: + - "0x0c0e5f2fF0ff18a3be9b835635039256dC4B4963" # Needed for .... + # A list of expected component indexed in the block range. Each component must match perfectly the `ProtocolComponent` indexed by your subtreams module. + expected_components: + - id: "0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7" + tokens: + - "0xdac17f958d2ee523a2206206994597c13d831ec7" + - "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + - "0x6b175474e89094c44da98b954eedeac495271d0f" + static_attributes: + attr_1: "value" + attr_2: "value" + creation_tx: "0x20793bbf260912aae189d5d261ff003c9b9166da8191d8f9d63ff1c7722f3ac6" + # Whether or not the script should skip trying to simulate a swap on this component. + # If set to `true` please always add a reason why it's skipped. + skip_simulation: false + - name: test_something_else + start_block: 123 + stop_block: 456 + expected_components: + - id: "0xdc24316b9ae028f1497c275eb9192a3ea0f67022" + tokens: + - "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" + - "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84" + static_attributes: null + creation_tx: "0xfac67ecbd423a5b915deff06045ec9343568edaec34ae95c43d35f2c018afdaa" + skip_simulation: true # If true, always add a reason diff --git a/substreams/ethereum-template-singleton/src/abi/erc20.rs b/substreams/ethereum-template-singleton/src/abi/erc20.rs new file mode 100644 index 000000000..b7b3a395b --- /dev/null +++ b/substreams/ethereum-template-singleton/src/abi/erc20.rs @@ -0,0 +1,1257 @@ + 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 Allowance { + pub owner: Vec, + pub spender: Vec, + } + impl Allowance { + const METHOD_ID: [u8; 4] = [221u8, 98u8, 237u8, 62u8]; + 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], + 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(), + spender: 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)), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.spender), + ), + ], + ); + 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 Allowance { + const NAME: &'static str = "allowance"; + 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 Allowance { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Approve { + pub spender: Vec, + pub value: substreams::scalar::BigInt, + } + impl Approve { + const METHOD_ID: [u8; 4] = [9u8, 94u8, 167u8, 179u8]; + 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)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + spender: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + 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.spender), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.value.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::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .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 { + 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 Approve { + const NAME: &'static str = "approve"; + 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 Approve { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct BalanceOf { + pub owner: Vec, + } + impl BalanceOf { + const METHOD_ID: [u8; 4] = [112u8, 160u8, 130u8, 49u8]; + 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 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 BalanceOf { + const NAME: &'static str = "balanceOf"; + 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 BalanceOf { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Decimals {} + impl Decimals { + const METHOD_ID: [u8; 4] = [49u8, 60u8, 229u8, 103u8]; + 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(8usize)], + 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 Decimals { + const NAME: &'static str = "decimals"; + 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 Decimals { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Name {} + impl Name { + const METHOD_ID: [u8; 4] = [6u8, 253u8, 222u8, 3u8]; + 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::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .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 { + 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 Name { + const NAME: &'static str = "name"; + 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 Name { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Symbol {} + impl Symbol { + const METHOD_ID: [u8; 4] = [149u8, 216u8, 155u8, 65u8]; + 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::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .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 { + 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 Symbol { + const NAME: &'static str = "symbol"; + 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 Symbol { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct TotalSupply {} + impl TotalSupply { + const METHOD_ID: [u8; 4] = [24u8, 22u8, 13u8, 221u8]; + 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 TotalSupply { + const NAME: &'static str = "totalSupply"; + 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 TotalSupply { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Transfer { + pub to: Vec, + pub value: substreams::scalar::BigInt, + } + impl Transfer { + const METHOD_ID: [u8; 4] = [169u8, 5u8, 156u8, 187u8]; + 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)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + to: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + 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.to)), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.value.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::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .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 { + 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 Transfer { + const NAME: &'static str = "transfer"; + 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 Transfer { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct TransferFrom { + pub from: Vec, + pub to: Vec, + pub value: substreams::scalar::BigInt, + } + impl TransferFrom { + const METHOD_ID: [u8; 4] = [35u8, 184u8, 114u8, 221u8]; + 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(256usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + from: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + to: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + 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.from)), + ethabi::Token::Address(ethabi::Address::from_slice(&self.to)), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.value.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::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .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 { + 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 TransferFrom { + const NAME: &'static str = "transferFrom"; + 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 TransferFrom { + fn output(data: &[u8]) -> Result { + 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 Approval { + pub owner: Vec, + pub spender: Vec, + pub value: substreams::scalar::BigInt, + } + impl Approval { + const TOPIC_ID: [u8; 32] = [ + 140u8, + 91u8, + 225u8, + 229u8, + 235u8, + 236u8, + 125u8, + 91u8, + 209u8, + 79u8, + 113u8, + 66u8, + 125u8, + 30u8, + 132u8, + 243u8, + 221u8, + 3u8, + 20u8, + 192u8, + 247u8, + 178u8, + 41u8, + 30u8, + 91u8, + 32u8, + 10u8, + 200u8, + 199u8, + 195u8, + 185u8, + 37u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 32usize { + 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)], + 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(), + spender: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'spender' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + 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 Approval { + const NAME: &'static str = "Approval"; + 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 Transfer { + pub from: Vec, + pub to: Vec, + pub value: substreams::scalar::BigInt, + } + impl Transfer { + const TOPIC_ID: [u8; 32] = [ + 221u8, + 242u8, + 82u8, + 173u8, + 27u8, + 226u8, + 200u8, + 155u8, + 105u8, + 194u8, + 176u8, + 104u8, + 252u8, + 55u8, + 141u8, + 170u8, + 149u8, + 43u8, + 167u8, + 241u8, + 99u8, + 196u8, + 161u8, + 22u8, + 40u8, + 245u8, + 90u8, + 77u8, + 245u8, + 35u8, + 179u8, + 239u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 32usize { + 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)], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + from: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'from' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + to: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'to' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + 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 Transfer { + const NAME: &'static str = "Transfer"; + 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-template-singleton/src/abi/mod.rs b/substreams/ethereum-template-singleton/src/abi/mod.rs new file mode 100644 index 000000000..4542b55b8 --- /dev/null +++ b/substreams/ethereum-template-singleton/src/abi/mod.rs @@ -0,0 +1,2 @@ +#![allow(clippy::all)] +pub mod erc20; diff --git a/substreams/ethereum-template-singleton/src/lib.rs b/substreams/ethereum-template-singleton/src/lib.rs new file mode 100644 index 000000000..83bc58617 --- /dev/null +++ b/substreams/ethereum-template-singleton/src/lib.rs @@ -0,0 +1,4 @@ +mod abi; +mod pool_factories; +mod modules; + diff --git a/substreams/ethereum-template-singleton/src/modules.rs b/substreams/ethereum-template-singleton/src/modules.rs new file mode 100644 index 000000000..b3c523b66 --- /dev/null +++ b/substreams/ethereum-template-singleton/src/modules.rs @@ -0,0 +1,246 @@ +//! Template for Protocols with singleton contract +//! +//! +use std::collections::HashMap; +use anyhow::Result; +use substreams::pb::substreams::StoreDeltas; +use substreams::prelude::*; +use substreams_ethereum::Event; +use substreams_ethereum::pb::eth; +use tycho_substreams::balances::aggregate_balances_changes; +use tycho_substreams::contract::extract_contract_changes_builder; +use tycho_substreams::prelude::*; +use itertools::Itertools; +use prost::Message; +use substreams_ethereum::block_view::CallView; +use crate::pool_factories; +use crate::pool_factories::DeploymentConfig; + +/// Find and create all relevant protocol components +/// +/// This method maps over blocks and instantiates ProtocolComponents with a unique ids +/// as well as all necessary metadata for routing and encoding. +#[substreams::handlers::map] +fn map_protocol_components( + params: String, + block: eth::v2::Block, +) -> Result { + let config = serde_qs::from_str(params.as_str())?; + Ok(BlockTransactionProtocolComponents { + tx_components: block + .transactions() + .filter_map(|tx| { + let components = tx + .logs_with_calls() + .filter_map(|(log, call)| { + // TODO: ensure this method is implemented correctly + pool_factories::maybe_create_component( + call.call, + log, + tx, + &config, + ) + }) + .collect::>(); + + if !components.is_empty() { + Some(TransactionProtocolComponents { tx: Some(tx.into()), components }) + } else { + None + } + }) + .collect::>(), + }) +} + +#[substreams::handlers::store] +fn store_protocol_tokens(map_protocol_components: BlockTransactionProtocolComponents, store: StoreSetInt64) { + map_protocol_components.tx_components + .into_iter() + .for_each(|tx_pc| { + tx_pc + .components + .into_iter() + .for_each(|pc| { + pc.tokens.iter().for_each(|token| { + let token_addr_hex = hex::encode(token); + store.set(0, &token_addr_hex, &1); + }) + }) + }); +} + +/// Extracts balance changes per component +/// +/// This template function inspects ERC20 transfer events to/from the singleton contract +/// to extract balance changes. If a transfer to the component is detected, it's +/// balanced is increased and if a balance from the component is detected its balance +/// is decreased. +/// +/// ## Note: +/// Changes are necessary if your protocol uses native ETH or your component burns or +/// mints tokens without emitting transfer events. +/// +/// You may want to ignore LP tokens if your protocol emits transfer events for these +/// here. +#[substreams::handlers::map] +fn map_relative_component_balance(params: String, block: eth::v2::Block, store: StoreGetInt64) -> Result { + let config: DeploymentConfig = serde_qs::from_str(params.as_str())?; + let res = block + .transactions() + .flat_map(|tx| { + tx + .logs_with_calls() + .filter_map(|(log, call)| { + let token_addr_hex = hex::encode(&log.address); + if !store.has_last(&token_addr_hex) { + return None; + } + + crate::abi::erc20::events::Transfer::match_and_decode(log).map(|transfer| { + let to_addr = transfer.to.as_slice(); + let from_addr = transfer.from.as_slice(); + if let Some(component_id) = extract_component_id_from_call(call) { + if to_addr == config.vault_address { + return Some(BalanceDelta { + ord: log.ordinal, + tx: Some(tx.into()), + token: log.address.to_vec(), + delta: transfer.value.to_signed_bytes_be(), + component_id: component_id.encode_to_vec(), + }); + } else if from_addr == config.vault_address { + return Some(BalanceDelta { + ord: log.ordinal, + tx: Some(tx.into()), + token: log.address.to_vec(), + delta: (transfer.value.neg()).to_signed_bytes_be(), + component_id: component_id.encode_to_vec(), + }); + } + } + None + }) + }) + .flatten() + }) + .collect::>(); + + Ok(BlockBalanceDeltas { balance_deltas: res }) +} + +// TODO: given a relevant balance changing call associate it with the respective +// component +fn extract_component_id_from_call(_call: CallView) -> Option { + todo!() +} + +/// Aggregates relative balances values into absolute values +/// +/// Aggregate the relative balances in an additive store since tycho-indexer expects +/// absolute balance inputs. +/// +/// ## Note: +/// This method should usually not require any changes. +#[substreams::handlers::store] +pub fn store_component_balances(deltas: BlockBalanceDeltas, store: StoreAddBigInt) { + tycho_substreams::balances::store_balance_changes(deltas, store); +} + +/// Aggregates protocol components and balance changes by transaction. +/// +/// This is the main method that will aggregate all changes as well as extract all +/// relevant contract storage deltas. +/// +/// ## Note: +/// You may have to change this method if your components have any default dynamic +/// attributes, or if you need any additional static contracts indexed. +#[substreams::handlers::map] +fn map_protocol_changes( + params: String, + block: eth::v2::Block, + new_components: BlockTransactionProtocolComponents, + balance_store: StoreDeltas, + deltas: BlockBalanceDeltas, +) -> Result { + let config: DeploymentConfig = serde_qs::from_str(params.as_str())?; + // 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(); + + // Aggregate newly created components per tx + new_components + .tx_components + .iter() + .for_each(|tx_component| { + // initialise builder if not yet present for this tx + let tx = tx_component.tx.as_ref().unwrap(); + let builder = transaction_changes + .entry(tx.index) + .or_insert_with(|| TransactionChangesBuilder::new(tx)); + + // iterate over individual components created within this tx + tx_component + .components + .iter() + .for_each(|component| { + builder.add_protocol_component(component); + // TODO: In case you require to add any dynamic attributes to the + // component you can do so here: + /* + builder.add_entity_change(&EntityChanges { + component_id: component.id.clone(), + attributes: default_attributes.clone(), + }); + */ + }); + }); + + // Aggregate absolute balances per transaction. + aggregate_balances_changes(balance_store, deltas) + .into_iter() + .for_each(|(_, (tx, balances))| { + let builder = transaction_changes + .entry(tx.index) + .or_insert_with(|| TransactionChangesBuilder::new(&tx)); + let mut contract_changes = InterimContractChange::new(&config.vault_address, false); + balances + .values() + .for_each(|token_bc_map| { + token_bc_map + .values() + .for_each(|bc| { + // track component balance + builder.add_balance_change(bc); + // track vault contract balance + contract_changes.upsert_token_balance(bc.token.as_slice(), bc.balance.as_slice()) + }) + }); + builder.add_contract_changes(&contract_changes); + }); + + + // Extract and insert any storage changes that happened for any of the components. + extract_contract_changes_builder( + &block, + |addr| { + // we assume that the store holds contract addresses as keys and if it + // contains a value, that contract is of relevance. + // TODO: if you have any additional static contracts that need to be indexed, + // please add them here. + addr == config.vault_address + }, + &mut transaction_changes, + ); + + // Process all `transaction_changes` for final output in the `BlockChanges`, + // sorted by transaction index (the key). + Ok(BlockChanges { + block: Some((&block).into()), + changes: transaction_changes + .drain() + .sorted_unstable_by_key(|(index, _)| *index) + .filter_map(|(_, builder)| builder.build()) + .collect::>(), + }) +} diff --git a/substreams/ethereum-template-singleton/src/pool_factories.rs b/substreams/ethereum-template-singleton/src/pool_factories.rs new file mode 100644 index 000000000..f5803f895 --- /dev/null +++ b/substreams/ethereum-template-singleton/src/pool_factories.rs @@ -0,0 +1,50 @@ +use serde::Deserialize; +use substreams_ethereum::pb::eth::v2::{Call, Log, TransactionTrace}; +use tycho_substreams::models::{ChangeType, FinancialType, ImplementationType, ProtocolComponent, ProtocolType}; + + +#[derive(Deserialize)] +#[serde(transparent)] +pub struct DeploymentConfig { + #[serde(with = "hex::serde")] + pub vault_address: Vec, +} + +/// Potentially constructs a new ProtocolComponent given a call +/// +/// This method is given each individual call within a transaction, the corresponding +/// logs emitted during that call as well as the full transaction trace. +/// +/// If this call creates a component in your protocol please contstruct and return it +/// here. Otherwise, simply return None. +pub fn maybe_create_component( + call: &Call, + _log: &Log, + _tx: &TransactionTrace, + config: &DeploymentConfig, +) -> Option { + if call.address == config.vault_address { + // TODO: replace with your logic + Some(ProtocolComponent { + id: "".to_string(), + tokens: vec![ + // TODO: add the components tokens + ], + contracts: vec![ + // TODO: any contracts required during swapping + ], + static_att: vec![ + // TODO: any additional metadata required, e.g. for swap encoding + ], + change: ChangeType::Creation.into(), + protocol_type: Some(ProtocolType { + name: "template".to_string(), + financial_type: FinancialType::Swap.into(), + attribute_schema: vec![], + implementation_type: ImplementationType::Vm.into(), + }), + }) + } else { + None + } +} \ No newline at end of file diff --git a/substreams/ethereum-template-singleton/substreams.yaml b/substreams/ethereum-template-singleton/substreams.yaml new file mode 100644 index 000000000..59dee49c9 --- /dev/null +++ b/substreams/ethereum-template-singleton/substreams.yaml @@ -0,0 +1,73 @@ +specVersion: v0.1.0 +package: + name: "ethereum_template" + version: v0.1.0 + +protobuf: + files: + - tycho/evm/v1/vm.proto + - tycho/evm/v1/common.proto + - tycho/evm/v1/utils.proto + importPaths: + - ../../proto + +binaries: + default: + type: wasm/rust-v1 + file: ../target/wasm32-unknown-unknown/release/ethereum_template.wasm + +network: mainnet +networks: + mainnet: + initialBlock: + map_protocol_components: 1 + store_protocol_components: 1 + map_relative_component_balance: 1 + store_balances: 1 + map_protocol_changes: 1 + params: + map_protocol_components: "vault_address=0000000000000000000000" + map_relative_component_balance: "vault_address=0000000000000000000000" + map_protocol_changes: "vault_address=0000000000000000000000" + +modules: + - name: map_protocol_components + kind: map + inputs: + - source: sf.ethereum.type.v2.Block + output: + type: proto:tycho.evm.v1.BlockTransactionProtocolComponents + + - name: store_protocol_components + kind: store + updatePolicy: set + valueType: string + inputs: + - map: map_protocol_components + + - name: map_relative_component_balance + kind: map + inputs: + - source: sf.ethereum.type.v2.Block + - store: store_components + output: + type: proto:tycho.evm.v1.BlockBalanceDeltas + + - name: store_balances + kind: store + updatePolicy: add + valueType: bigint + inputs: + - map: map_relative_component_balance + + - name: map_protocol_changes + kind: map + inputs: + - source: sf.ethereum.type.v2.Block + - map: map_protocol_components + - map: map_relative_component_balance + - store: store_components + - store: store_balances + mode: deltas + output: + type: proto:tycho.evm.v1.BlockChanges diff --git a/substreams/ethereum-template/substreams.yaml b/substreams/ethereum-template/substreams.yaml deleted file mode 100644 index 903f44a25..000000000 --- a/substreams/ethereum-template/substreams.yaml +++ /dev/null @@ -1,25 +0,0 @@ -specVersion: v0.1.0 -package: - name: "ethereum_template" - version: v0.1.0 - -protobuf: - files: - - tycho/evm/v1/vm.proto - - tycho/evm/v1/common.proto - - tycho/evm/v1/utils.proto - importPaths: - - ../../proto - -binaries: - default: - type: wasm/rust-v1 - file: ../target/wasm32-unknown-unknown/release/ethereum_template.wasm - -modules: - - name: map_protocol_changes - kind: map - inputs: - - source: sf.ethereum.type.v2.Block - output: - type: proto:tycho.evm.state.v1.BlockContractChanges From 1a60898bf0a8aaa24fc38d454779dd9959ca35f2 Mon Sep 17 00:00:00 2001 From: kayibal Date: Thu, 30 Jan 2025 16:30:48 -0300 Subject: [PATCH 3/8] fix: misc fixes in substreams.yaml --- .../ethereum-template-factory/substreams.yaml | 11 +++++--- .../src/modules.rs | 2 +- .../src/pool_factories.rs | 13 +++++++++- .../substreams.yaml | 25 ++++++++++++------- 4 files changed, 36 insertions(+), 15 deletions(-) diff --git a/substreams/ethereum-template-factory/substreams.yaml b/substreams/ethereum-template-factory/substreams.yaml index 5aa8ba7fb..864e9bc8f 100644 --- a/substreams/ethereum-template-factory/substreams.yaml +++ b/substreams/ethereum-template-factory/substreams.yaml @@ -14,7 +14,10 @@ protobuf: binaries: default: type: wasm/rust-v1 - file: ../target/wasm32-unknown-unknown/release/ethereum_template.wasm + file: ../target/wasm32-unknown-unknown/release/ethereum_template_factory.wasm + + +network: mainnet modules: - name: map_protocol_components @@ -38,7 +41,7 @@ modules: initialBlock: 1 inputs: - source: sf.ethereum.type.v2.Block - - store: store_components + - store: store_protocol_components output: type: proto:tycho.evm.v1.BlockBalanceDeltas @@ -52,12 +55,12 @@ modules: - name: map_protocol_changes kind: map - initialBlock: 0 + initialBlock: 1 inputs: - source: sf.ethereum.type.v2.Block - map: map_protocol_components - map: map_relative_component_balance - - store: store_components + - store: store_protocol_components - store: store_balances mode: deltas output: diff --git a/substreams/ethereum-template-singleton/src/modules.rs b/substreams/ethereum-template-singleton/src/modules.rs index b3c523b66..9bdfd1bad 100644 --- a/substreams/ethereum-template-singleton/src/modules.rs +++ b/substreams/ethereum-template-singleton/src/modules.rs @@ -243,4 +243,4 @@ fn map_protocol_changes( .filter_map(|(_, builder)| builder.build()) .collect::>(), }) -} +} \ No newline at end of file diff --git a/substreams/ethereum-template-singleton/src/pool_factories.rs b/substreams/ethereum-template-singleton/src/pool_factories.rs index f5803f895..6b07ef646 100644 --- a/substreams/ethereum-template-singleton/src/pool_factories.rs +++ b/substreams/ethereum-template-singleton/src/pool_factories.rs @@ -4,7 +4,6 @@ use tycho_substreams::models::{ChangeType, FinancialType, ImplementationType, Pr #[derive(Deserialize)] -#[serde(transparent)] pub struct DeploymentConfig { #[serde(with = "hex::serde")] pub vault_address: Vec, @@ -47,4 +46,16 @@ pub fn maybe_create_component( } else { None } +} + + +#[cfg(test)] +mod test { + use super::*; + #[test] + fn test_decode_config() { + let config: DeploymentConfig = serde_qs::from_str("vault_address=0001").unwrap(); + + assert_eq!(config.vault_address, [0u8, 1u8]); + } } \ No newline at end of file diff --git a/substreams/ethereum-template-singleton/substreams.yaml b/substreams/ethereum-template-singleton/substreams.yaml index 59dee49c9..a3eb035fb 100644 --- a/substreams/ethereum-template-singleton/substreams.yaml +++ b/substreams/ethereum-template-singleton/substreams.yaml @@ -14,7 +14,7 @@ protobuf: binaries: default: type: wasm/rust-v1 - file: ../target/wasm32-unknown-unknown/release/ethereum_template.wasm + file: ../target/wasm32-unknown-unknown/release/ethereum_template_singleton.wasm network: mainnet networks: @@ -26,19 +26,25 @@ networks: store_balances: 1 map_protocol_changes: 1 params: - map_protocol_components: "vault_address=0000000000000000000000" - map_relative_component_balance: "vault_address=0000000000000000000000" - map_protocol_changes: "vault_address=0000000000000000000000" + map_protocol_components: "vault_address=0000" + map_relative_component_balance: "vault_address=0000" + map_protocol_changes: "vault_address=0000" + +params: + map_protocol_components: "vault_address=0000" + map_relative_component_balance: "vault_address=0000" + map_protocol_changes: "vault_address=0000" modules: - name: map_protocol_components kind: map inputs: + - params: string - source: sf.ethereum.type.v2.Block output: type: proto:tycho.evm.v1.BlockTransactionProtocolComponents - - name: store_protocol_components + - name: store_protocol_tokens kind: store updatePolicy: set valueType: string @@ -48,12 +54,13 @@ modules: - name: map_relative_component_balance kind: map inputs: + - params: string - source: sf.ethereum.type.v2.Block - - store: store_components + - store: store_protocol_tokens output: type: proto:tycho.evm.v1.BlockBalanceDeltas - - name: store_balances + - name: store_component_balances kind: store updatePolicy: add valueType: bigint @@ -63,11 +70,11 @@ modules: - name: map_protocol_changes kind: map inputs: + - params: string - source: sf.ethereum.type.v2.Block - map: map_protocol_components - map: map_relative_component_balance - - store: store_components - - store: store_balances + - store: store_component_balances mode: deltas output: type: proto:tycho.evm.v1.BlockChanges From 360d61f454ab29259c749fa850452babb6eddfac Mon Sep 17 00:00:00 2001 From: kayibal Date: Sat, 1 Feb 2025 19:23:42 -0300 Subject: [PATCH 4/8] fix: Implement ethereum-ekubo --- substreams/Cargo.lock | 19 + substreams/Cargo.toml | 1 + substreams/ethereum-ekubo/Cargo.toml | 28 + substreams/ethereum-ekubo/abi/core.json | 1598 +++++ substreams/ethereum-ekubo/abi/erc20.json | 222 + substreams/ethereum-ekubo/abi/oracle.json | 1003 ++++ substreams/ethereum-ekubo/buf.gen.yaml | 12 + substreams/ethereum-ekubo/build.rs | 49 + .../integration_test.tycho.yaml | 57 + substreams/ethereum-ekubo/src/abi/core.rs | 5309 +++++++++++++++++ substreams/ethereum-ekubo/src/abi/erc20.rs | 1257 ++++ substreams/ethereum-ekubo/src/abi/mod.rs | 4 + substreams/ethereum-ekubo/src/abi/oracle.rs | 3832 ++++++++++++ substreams/ethereum-ekubo/src/lib.rs | 4 + substreams/ethereum-ekubo/src/modules.rs | 292 + substreams/ethereum-ekubo/src/pb/mod.rs | 52 + .../src/pb/sf.substreams.index.v1.rs | 8 + .../src/pb/sf.substreams.rpc.v2.rs | 340 ++ .../ethereum-ekubo/src/pb/sf.substreams.rs | 14 + .../src/pb/sf.substreams.sink.service.v1.rs | 227 + .../ethereum-ekubo/src/pb/sf.substreams.v1.rs | 324 + .../ethereum-ekubo/src/pb/tycho.evm.v1.rs | 382 ++ .../ethereum-ekubo/src/pool_factories.rs | 105 + substreams/ethereum-ekubo/substreams.yaml | 75 + 24 files changed, 15214 insertions(+) create mode 100644 substreams/ethereum-ekubo/Cargo.toml create mode 100644 substreams/ethereum-ekubo/abi/core.json create mode 100644 substreams/ethereum-ekubo/abi/erc20.json create mode 100644 substreams/ethereum-ekubo/abi/oracle.json create mode 100644 substreams/ethereum-ekubo/buf.gen.yaml create mode 100644 substreams/ethereum-ekubo/build.rs create mode 100644 substreams/ethereum-ekubo/integration_test.tycho.yaml create mode 100644 substreams/ethereum-ekubo/src/abi/core.rs create mode 100644 substreams/ethereum-ekubo/src/abi/erc20.rs create mode 100644 substreams/ethereum-ekubo/src/abi/mod.rs create mode 100644 substreams/ethereum-ekubo/src/abi/oracle.rs create mode 100644 substreams/ethereum-ekubo/src/lib.rs create mode 100644 substreams/ethereum-ekubo/src/modules.rs create mode 100644 substreams/ethereum-ekubo/src/pb/mod.rs create mode 100644 substreams/ethereum-ekubo/src/pb/sf.substreams.index.v1.rs create mode 100644 substreams/ethereum-ekubo/src/pb/sf.substreams.rpc.v2.rs create mode 100644 substreams/ethereum-ekubo/src/pb/sf.substreams.rs create mode 100644 substreams/ethereum-ekubo/src/pb/sf.substreams.sink.service.v1.rs create mode 100644 substreams/ethereum-ekubo/src/pb/sf.substreams.v1.rs create mode 100644 substreams/ethereum-ekubo/src/pb/tycho.evm.v1.rs create mode 100644 substreams/ethereum-ekubo/src/pool_factories.rs create mode 100644 substreams/ethereum-ekubo/substreams.yaml diff --git a/substreams/Cargo.lock b/substreams/Cargo.lock index bb5ec2b6e..241a19098 100644 --- a/substreams/Cargo.lock +++ b/substreams/Cargo.lock @@ -260,6 +260,25 @@ dependencies = [ "tycho-substreams 0.2.0 (git+https://github.com/propeller-heads/tycho-protocol-sdk.git?rev=b8aeaa3)", ] +[[package]] +name = "ethereum-ekubo" +version = "0.1.0" +dependencies = [ + "anyhow", + "ethabi 18.0.0", + "hex", + "itertools 0.10.5", + "num-bigint", + "prost 0.11.9", + "serde", + "serde-sibor", + "serde_qs", + "substreams", + "substreams-ethereum", + "tiny-keccak", + "tycho-substreams 0.2.0 (git+https://github.com/propeller-heads/tycho-protocol-sdk.git?rev=3c08359)", +] + [[package]] name = "ethereum-sfrax" version = "0.1.0" diff --git a/substreams/Cargo.toml b/substreams/Cargo.toml index 1d7dfe528..e2011d6a2 100644 --- a/substreams/Cargo.toml +++ b/substreams/Cargo.toml @@ -12,6 +12,7 @@ members = [ "ethereum-uniswap-v3-logs-only", "ethereum-template-factory", "ethereum-template-singleton", + "ethereum-ekubo", ] resolver = "2" diff --git a/substreams/ethereum-ekubo/Cargo.toml b/substreams/ethereum-ekubo/Cargo.toml new file mode 100644 index 000000000..718a6976f --- /dev/null +++ b/substreams/ethereum-ekubo/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "ethereum-ekubo" +version = "0.1.0" +edition = "2021" + +[lib] +name = "ethereum_ekubo" +crate-type = ["cdylib"] + +[dependencies] +substreams = "0.5.22" +substreams-ethereum = "0.9.9" +prost = "0.11" +tycho-substreams = { git = "https://github.com/propeller-heads/tycho-protocol-sdk.git", rev = "3c08359" } +anyhow = "1.0.95" +ethabi = "18.0.0" +num-bigint = "0.4.6" +hex = { version = "0.4", features = ["serde"] } +itertools = "0.10.5" +serde = "1.0.217" +serde-sibor = "0.1.0" +serde_qs = "0.13.0" +tiny-keccak = "2.0.2" + + +[build-dependencies] +anyhow = "1" +substreams-ethereum = "0.9.9" diff --git a/substreams/ethereum-ekubo/abi/core.json b/substreams/ethereum-ekubo/abi/core.json new file mode 100644 index 000000000..2b8c2ece1 --- /dev/null +++ b/substreams/ethereum-ekubo/abi/core.json @@ -0,0 +1,1598 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "expirationTime", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "receive", + "stateMutability": "payable" + }, + { + "type": "function", + "name": "accumulateAsFees", + "inputs": [ + { + "name": "poolKey", + "type": "tuple", + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "amount0", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "amount1", + "type": "uint128", + "internalType": "uint128" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "cancelOwnershipHandover", + "inputs": [], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "collectFees", + "inputs": [ + { + "name": "poolKey", + "type": "tuple", + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "bounds", + "type": "tuple", + "internalType": "struct Bounds", + "components": [ + { + "name": "lower", + "type": "int32", + "internalType": "int32" + }, + { + "name": "upper", + "type": "int32", + "internalType": "int32" + } + ] + } + ], + "outputs": [ + { + "name": "amount0", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "amount1", + "type": "uint128", + "internalType": "uint128" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "completeOwnershipHandover", + "inputs": [ + { + "name": "pendingOwner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "expirationTime", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "forward", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getPoolFeesPerLiquidityInside", + "inputs": [ + { + "name": "poolId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "bounds", + "type": "tuple", + "internalType": "struct Bounds", + "components": [ + { + "name": "lower", + "type": "int32", + "internalType": "int32" + }, + { + "name": "upper", + "type": "int32", + "internalType": "int32" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct FeesPerLiquidity", + "components": [ + { + "name": "value0", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "value1", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initializePool", + "inputs": [ + { + "name": "poolKey", + "type": "tuple", + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "tick", + "type": "int32", + "internalType": "int32" + } + ], + "outputs": [ + { + "name": "sqrtRatio", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "load", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "amount", + "type": "uint128", + "internalType": "uint128" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "lock", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "nextInitializedTick", + "inputs": [ + { + "name": "poolId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "fromTick", + "type": "int32", + "internalType": "int32" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "skipAhead", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "tick", + "type": "int32", + "internalType": "int32" + }, + { + "name": "isInitialized", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "result", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "ownershipHandoverExpiresAt", + "inputs": [ + { + "name": "pendingOwner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "result", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pay", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "prevInitializedTick", + "inputs": [ + { + "name": "poolId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "fromTick", + "type": "int32", + "internalType": "int32" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "skipAhead", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "tick", + "type": "int32", + "internalType": "int32" + }, + { + "name": "isInitialized", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "registerExtension", + "inputs": [ + { + "name": "expectedCallPoints", + "type": "tuple", + "internalType": "struct CallPoints", + "components": [ + { + "name": "beforeInitializePool", + "type": "bool", + "internalType": "bool" + }, + { + "name": "afterInitializePool", + "type": "bool", + "internalType": "bool" + }, + { + "name": "beforeSwap", + "type": "bool", + "internalType": "bool" + }, + { + "name": "afterSwap", + "type": "bool", + "internalType": "bool" + }, + { + "name": "beforeUpdatePosition", + "type": "bool", + "internalType": "bool" + }, + { + "name": "afterUpdatePosition", + "type": "bool", + "internalType": "bool" + }, + { + "name": "beforeCollectFees", + "type": "bool", + "internalType": "bool" + }, + { + "name": "afterCollectFees", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "renounceOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "requestOwnershipHandover", + "inputs": [], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "save", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "amount", + "type": "uint128", + "internalType": "uint128" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "sload", + "inputs": [ + { + "name": "slot", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "swap", + "inputs": [ + { + "name": "poolKey", + "type": "tuple", + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "params", + "type": "tuple", + "internalType": "struct SwapParameters", + "components": [ + { + "name": "amount", + "type": "int128", + "internalType": "int128" + }, + { + "name": "isToken1", + "type": "bool", + "internalType": "bool" + }, + { + "name": "sqrtRatioLimit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "skipAhead", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ], + "outputs": [ + { + "name": "delta0", + "type": "int128", + "internalType": "int128" + }, + { + "name": "delta1", + "type": "int128", + "internalType": "int128" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "tload", + "inputs": [ + { + "name": "slot", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transferOwnership", + "inputs": [ + { + "name": "newOwner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "updatePosition", + "inputs": [ + { + "name": "poolKey", + "type": "tuple", + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "params", + "type": "tuple", + "internalType": "struct UpdatePositionParameters", + "components": [ + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "bounds", + "type": "tuple", + "internalType": "struct Bounds", + "components": [ + { + "name": "lower", + "type": "int32", + "internalType": "int32" + }, + { + "name": "upper", + "type": "int32", + "internalType": "int32" + } + ] + }, + { + "name": "liquidityDelta", + "type": "int128", + "internalType": "int128" + } + ] + } + ], + "outputs": [ + { + "name": "delta0", + "type": "int128", + "internalType": "int128" + }, + { + "name": "delta1", + "type": "int128", + "internalType": "int128" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "withdraw", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint128", + "internalType": "uint128" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "withdrawProtocolFees", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "ExtensionRegistered", + "inputs": [ + { + "name": "extension", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "FeesAccumulated", + "inputs": [ + { + "name": "poolKey", + "type": "tuple", + "indexed": false, + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "amount0", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + }, + { + "name": "amount1", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LoadedBalance", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "salt", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "amount", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnershipHandoverCanceled", + "inputs": [ + { + "name": "pendingOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnershipHandoverRequested", + "inputs": [ + { + "name": "pendingOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnershipTransferred", + "inputs": [ + { + "name": "oldOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PoolInitialized", + "inputs": [ + { + "name": "poolKey", + "type": "tuple", + "indexed": false, + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "tick", + "type": "int32", + "indexed": false, + "internalType": "int32" + }, + { + "name": "sqrtRatio", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PositionFeesCollected", + "inputs": [ + { + "name": "poolKey", + "type": "tuple", + "indexed": false, + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "positionKey", + "type": "tuple", + "indexed": false, + "internalType": "struct PositionKey", + "components": [ + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "bounds", + "type": "tuple", + "internalType": "struct Bounds", + "components": [ + { + "name": "lower", + "type": "int32", + "internalType": "int32" + }, + { + "name": "upper", + "type": "int32", + "internalType": "int32" + } + ] + } + ] + }, + { + "name": "amount0", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + }, + { + "name": "amount1", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PositionUpdated", + "inputs": [ + { + "name": "locker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "poolKey", + "type": "tuple", + "indexed": false, + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "params", + "type": "tuple", + "indexed": false, + "internalType": "struct UpdatePositionParameters", + "components": [ + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "bounds", + "type": "tuple", + "internalType": "struct Bounds", + "components": [ + { + "name": "lower", + "type": "int32", + "internalType": "int32" + }, + { + "name": "upper", + "type": "int32", + "internalType": "int32" + } + ] + }, + { + "name": "liquidityDelta", + "type": "int128", + "internalType": "int128" + } + ] + }, + { + "name": "delta0", + "type": "int128", + "indexed": false, + "internalType": "int128" + }, + { + "name": "delta1", + "type": "int128", + "indexed": false, + "internalType": "int128" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ProtocolFeesPaid", + "inputs": [ + { + "name": "poolKey", + "type": "tuple", + "indexed": false, + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "positionKey", + "type": "tuple", + "indexed": false, + "internalType": "struct PositionKey", + "components": [ + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "bounds", + "type": "tuple", + "internalType": "struct Bounds", + "components": [ + { + "name": "lower", + "type": "int32", + "internalType": "int32" + }, + { + "name": "upper", + "type": "int32", + "internalType": "int32" + } + ] + } + ] + }, + { + "name": "amount0", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + }, + { + "name": "amount1", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ProtocolFeesWithdrawn", + "inputs": [ + { + "name": "recipient", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SavedBalance", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "salt", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "amount", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Swapped", + "inputs": [ + { + "name": "locker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "poolKey", + "type": "tuple", + "indexed": false, + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "params", + "type": "tuple", + "indexed": false, + "internalType": "struct SwapParameters", + "components": [ + { + "name": "amount", + "type": "int128", + "internalType": "int128" + }, + { + "name": "isToken1", + "type": "bool", + "internalType": "bool" + }, + { + "name": "sqrtRatioLimit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "skipAhead", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "delta0", + "type": "int128", + "indexed": false, + "internalType": "int128" + }, + { + "name": "delta1", + "type": "int128", + "indexed": false, + "internalType": "int128" + }, + { + "name": "sqrtRatioAfter", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "tickAfter", + "type": "int32", + "indexed": false, + "internalType": "int32" + }, + { + "name": "liquidityAfter", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AlreadyInitialized", + "inputs": [] + }, + { + "type": "error", + "name": "Amount0DeltaOverflow", + "inputs": [] + }, + { + "type": "error", + "name": "Amount1DeltaOverflow", + "inputs": [] + }, + { + "type": "error", + "name": "AmountBeforeFeeOverflow", + "inputs": [] + }, + { + "type": "error", + "name": "BoundsOrder", + "inputs": [] + }, + { + "type": "error", + "name": "BoundsTickSpacing", + "inputs": [] + }, + { + "type": "error", + "name": "ContractHasExpired", + "inputs": [] + }, + { + "type": "error", + "name": "DebtsNotZeroed", + "inputs": [ + { + "name": "id", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ExtensionNotRegistered", + "inputs": [] + }, + { + "type": "error", + "name": "FailedRegisterInvalidCallPoints", + "inputs": [] + }, + { + "type": "error", + "name": "InsufficientSavedBalance", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidSqrtRatio", + "inputs": [ + { + "name": "sqrtRatio", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidTick", + "inputs": [ + { + "name": "tick", + "type": "int32", + "internalType": "int32" + } + ] + }, + { + "type": "error", + "name": "InvalidTickSpacing", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidTokens", + "inputs": [] + }, + { + "type": "error", + "name": "LockerOnly", + "inputs": [] + }, + { + "type": "error", + "name": "MinMaxBounds", + "inputs": [] + }, + { + "type": "error", + "name": "MustCollectFeesBeforeWithdrawingAllLiquidity", + "inputs": [] + }, + { + "type": "error", + "name": "NewOwnerIsZeroAddress", + "inputs": [] + }, + { + "type": "error", + "name": "NoHandoverRequest", + "inputs": [] + }, + { + "type": "error", + "name": "NoPaymentMade", + "inputs": [] + }, + { + "type": "error", + "name": "NotLocked", + "inputs": [] + }, + { + "type": "error", + "name": "PaymentOverflow", + "inputs": [] + }, + { + "type": "error", + "name": "PoolAlreadyInitialized", + "inputs": [] + }, + { + "type": "error", + "name": "PoolNotInitialized", + "inputs": [] + }, + { + "type": "error", + "name": "SqrtRatioLimitOutOfRange", + "inputs": [] + }, + { + "type": "error", + "name": "SqrtRatioLimitWrongDirection", + "inputs": [] + }, + { + "type": "error", + "name": "SqrtRatioLimitWrongDirection", + "inputs": [] + }, + { + "type": "error", + "name": "Unauthorized", + "inputs": [] + }, + { + "type": "error", + "name": "ZeroLiquidityNextSqrtRatioFromAmount0", + "inputs": [] + }, + { + "type": "error", + "name": "ZeroLiquidityNextSqrtRatioFromAmount1", + "inputs": [] + }, + { + "type": "error", + "name": "ZeroSqrtRatio", + "inputs": [] + } +] diff --git a/substreams/ethereum-ekubo/abi/erc20.json b/substreams/ethereum-ekubo/abi/erc20.json new file mode 100644 index 000000000..3b0ab2f1a --- /dev/null +++ b/substreams/ethereum-ekubo/abi/erc20.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] \ No newline at end of file diff --git a/substreams/ethereum-ekubo/abi/oracle.json b/substreams/ethereum-ekubo/abi/oracle.json new file mode 100644 index 000000000..25ae45385 --- /dev/null +++ b/substreams/ethereum-ekubo/abi/oracle.json @@ -0,0 +1,1003 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "core", + "type": "address", + "internalType": "contract ICore" + }, + { + "name": "_oracleToken", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "afterCollectFees", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "tuple", + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "", + "type": "tuple", + "internalType": "struct Bounds", + "components": [ + { + "name": "lower", + "type": "int32", + "internalType": "int32" + }, + { + "name": "upper", + "type": "int32", + "internalType": "int32" + } + ] + }, + { + "name": "", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "", + "type": "uint128", + "internalType": "uint128" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "afterInitializePool", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "tuple", + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "", + "type": "int32", + "internalType": "int32" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "afterSwap", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "tuple", + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "", + "type": "tuple", + "internalType": "struct SwapParameters", + "components": [ + { + "name": "amount", + "type": "int128", + "internalType": "int128" + }, + { + "name": "isToken1", + "type": "bool", + "internalType": "bool" + }, + { + "name": "sqrtRatioLimit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "skipAhead", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "", + "type": "int128", + "internalType": "int128" + }, + { + "name": "", + "type": "int128", + "internalType": "int128" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "afterUpdatePosition", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "tuple", + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "", + "type": "tuple", + "internalType": "struct UpdatePositionParameters", + "components": [ + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "bounds", + "type": "tuple", + "internalType": "struct Bounds", + "components": [ + { + "name": "lower", + "type": "int32", + "internalType": "int32" + }, + { + "name": "upper", + "type": "int32", + "internalType": "int32" + } + ] + }, + { + "name": "liquidityDelta", + "type": "int128", + "internalType": "int128" + } + ] + }, + { + "name": "", + "type": "int128", + "internalType": "int128" + }, + { + "name": "", + "type": "int128", + "internalType": "int128" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "beforeCollectFees", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "tuple", + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "", + "type": "tuple", + "internalType": "struct Bounds", + "components": [ + { + "name": "lower", + "type": "int32", + "internalType": "int32" + }, + { + "name": "upper", + "type": "int32", + "internalType": "int32" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "beforeInitializePool", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "key", + "type": "tuple", + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "", + "type": "int32", + "internalType": "int32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "beforeSwap", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "poolKey", + "type": "tuple", + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "params", + "type": "tuple", + "internalType": "struct SwapParameters", + "components": [ + { + "name": "amount", + "type": "int128", + "internalType": "int128" + }, + { + "name": "isToken1", + "type": "bool", + "internalType": "bool" + }, + { + "name": "sqrtRatioLimit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "skipAhead", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "beforeUpdatePosition", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "poolKey", + "type": "tuple", + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "params", + "type": "tuple", + "internalType": "struct UpdatePositionParameters", + "components": [ + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "bounds", + "type": "tuple", + "internalType": "struct Bounds", + "components": [ + { + "name": "lower", + "type": "int32", + "internalType": "int32" + }, + { + "name": "upper", + "type": "int32", + "internalType": "int32" + } + ] + }, + { + "name": "liquidityDelta", + "type": "int128", + "internalType": "int128" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "extrapolateSnapshot", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "atTime", + "type": "uint64", + "internalType": "uint64" + } + ], + "outputs": [ + { + "name": "secondsPerLiquidityCumulative", + "type": "uint160", + "internalType": "uint160" + }, + { + "name": "tickCumulative", + "type": "int64", + "internalType": "int64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "findPreviousSnapshot", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "time", + "type": "uint64", + "internalType": "uint64" + } + ], + "outputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "snapshot", + "type": "tuple", + "internalType": "struct Oracle.Snapshot", + "components": [ + { + "name": "secondsSinceOffset", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "secondsPerLiquidityCumulative", + "type": "uint160", + "internalType": "uint160" + }, + { + "name": "tickCumulative", + "type": "int64", + "internalType": "int64" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getExtrapolatedSnapshotsForSortedTimestamps", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "timestamps", + "type": "uint64[]", + "internalType": "uint64[]" + } + ], + "outputs": [ + { + "name": "observations", + "type": "tuple[]", + "internalType": "struct Oracle.Observation[]", + "components": [ + { + "name": "secondsPerLiquidityCumulative", + "type": "uint160", + "internalType": "uint160" + }, + { + "name": "tickCumulative", + "type": "int64", + "internalType": "int64" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPoolKey", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tickSpacing", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "extension", + "type": "address", + "internalType": "address" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "oracleToken", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "secondsSinceOffset", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint32", + "internalType": "uint32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "secondsSinceOffsetToTimestamp", + "inputs": [ + { + "name": "sso", + "type": "uint32", + "internalType": "uint32" + } + ], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "sload", + "inputs": [ + { + "name": "slot", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "snapshotCount", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "snapshots", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "secondsSinceOffset", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "secondsPerLiquidityCumulative", + "type": "uint160", + "internalType": "uint160" + }, + { + "name": "tickCumulative", + "type": "int64", + "internalType": "int64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "timestampOffset", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "tload", + "inputs": [ + { + "name": "slot", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "SnapshotEvent", + "inputs": [ + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "index", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "timestamp", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + }, + { + "name": "secondsPerLiquidityCumulative", + "type": "uint160", + "indexed": false, + "internalType": "uint160" + }, + { + "name": "tickCumulative", + "type": "int64", + "indexed": false, + "internalType": "int64" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "BoundsMustBeMaximum", + "inputs": [] + }, + { + "type": "error", + "name": "CallPointNotImplemented", + "inputs": [] + }, + { + "type": "error", + "name": "CoreOnly", + "inputs": [] + }, + { + "type": "error", + "name": "EndTimeLessThanStartTime", + "inputs": [] + }, + { + "type": "error", + "name": "FeeMustBeZero", + "inputs": [] + }, + { + "type": "error", + "name": "FutureTime", + "inputs": [] + }, + { + "type": "error", + "name": "NoPreviousSnapshotExists", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "time", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "PairsWithOracleTokenOnly", + "inputs": [] + }, + { + "type": "error", + "name": "TickSpacingMustBeMaximum", + "inputs": [] + }, + { + "type": "error", + "name": "TimestampsNotSorted", + "inputs": [] + }, + { + "type": "error", + "name": "ZeroTimestampsProvided", + "inputs": [] + } +] diff --git a/substreams/ethereum-ekubo/buf.gen.yaml b/substreams/ethereum-ekubo/buf.gen.yaml new file mode 100644 index 000000000..d2e6544e9 --- /dev/null +++ b/substreams/ethereum-ekubo/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-ekubo/build.rs b/substreams/ethereum-ekubo/build.rs new file mode 100644 index 000000000..5e7bd34c5 --- /dev/null +++ b/substreams/ethereum-ekubo/build.rs @@ -0,0 +1,49 @@ +use anyhow::Result; +use std::{fs, io::Write}; +use substreams_ethereum::Abigen; + +fn main() -> Result<()> { + let abi_folder = "abi"; + let output_folder = "src/abi"; + + let abis = fs::read_dir(abi_folder)?; + + let mut files = abis.collect::, _>>()?; + + // Sort the files by their name + files.sort_by_key(|a| a.file_name()); + + let mut mod_rs_content = String::new(); + mod_rs_content.push_str("#![allow(clippy::all)]\n"); + + for file in files { + let file_name = file.file_name(); + let file_name = file_name.to_string_lossy(); + + if !file_name.ends_with(".json") { + continue; + } + + let contract_name = file_name.split('.').next().unwrap(); + + let input_path = format!("{}/{}", abi_folder, file_name); + let output_path = format!("{}/{}.rs", output_folder, contract_name); + + mod_rs_content.push_str(&format!("pub mod {};\n", contract_name)); + + if std::path::Path::new(&output_path).exists() { + continue; + } + + Abigen::new(contract_name, &input_path)? + .generate()? + .write_to_file(&output_path)?; + } + + let mod_rs_path = format!("{}/mod.rs", output_folder); + let mut mod_rs_file = fs::File::create(mod_rs_path)?; + + mod_rs_file.write_all(mod_rs_content.as_bytes())?; + + Ok(()) +} diff --git a/substreams/ethereum-ekubo/integration_test.tycho.yaml b/substreams/ethereum-ekubo/integration_test.tycho.yaml new file mode 100644 index 000000000..bea6aa301 --- /dev/null +++ b/substreams/ethereum-ekubo/integration_test.tycho.yaml @@ -0,0 +1,57 @@ +# Name of the substreams config file in your substreams module. Usually "./substreams.yaml" +substreams_yaml_path: ./substreams.yaml +# Name of the adapter contract, usually: ProtocolSwapAdapter" +adapter_contract: "SwapAdapter" +# Constructor signature of the Adapter contract" +adapter_build_signature: "constructor(address)" +# A comma separated list of args to be passed to the contructor of the Adapter contract" +adapter_build_args: "0x0000000000000000000000000000000000000000" +# Whether or not the testing script should skip checking balances of the protocol components. +# If set to `true` please always add a reason why it's skipped. +skip_balance_check: false +# A list of accounts that need to be indexed to run the tests properly. +# Usually used when there is a global component required by all pools and created before the tested range of blocks. For example a factory or a vault. +# Please note that this component needs to be indexed by your substreams module, this feature is only for testing purpose. +# Also please always add a reason why this account is needed for your tests. +# This will be applied to each test. +initialized_accounts: + - "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84" # Needed for .... +# A list of protocol types names created by your Substreams module. +protocol_type_names: + - "type_name_1" + - "type_name_2" +# A list of tests. +tests: + # Name of the test + - name: test_pool_creation + # Indexed block range + start_block: 123 + stop_block: 456 + # Same as global `initialized_accounts` but only scoped to this test. + initialized_accounts: + - "0x0c0e5f2fF0ff18a3be9b835635039256dC4B4963" # Needed for .... + # A list of expected component indexed in the block range. Each component must match perfectly the `ProtocolComponent` indexed by your subtreams module. + expected_components: + - id: "0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7" + tokens: + - "0xdac17f958d2ee523a2206206994597c13d831ec7" + - "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + - "0x6b175474e89094c44da98b954eedeac495271d0f" + static_attributes: + attr_1: "value" + attr_2: "value" + creation_tx: "0x20793bbf260912aae189d5d261ff003c9b9166da8191d8f9d63ff1c7722f3ac6" + # Whether or not the script should skip trying to simulate a swap on this component. + # If set to `true` please always add a reason why it's skipped. + skip_simulation: false + - name: test_something_else + start_block: 123 + stop_block: 456 + expected_components: + - id: "0xdc24316b9ae028f1497c275eb9192a3ea0f67022" + tokens: + - "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" + - "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84" + static_attributes: null + creation_tx: "0xfac67ecbd423a5b915deff06045ec9343568edaec34ae95c43d35f2c018afdaa" + skip_simulation: true # If true, always add a reason diff --git a/substreams/ethereum-ekubo/src/abi/core.rs b/substreams/ethereum-ekubo/src/abi/core.rs new file mode 100644 index 000000000..191af3383 --- /dev/null +++ b/substreams/ethereum-ekubo/src/abi/core.rs @@ -0,0 +1,5309 @@ + 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 AccumulateAsFees { + pub pool_key: ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + pub amount0: substreams::scalar::BigInt, + pub amount1: substreams::scalar::BigInt, + } + impl AccumulateAsFees { + const METHOD_ID: [u8; 4] = [240u8, 104u8, 44u8, 123u8]; + 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::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), 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 { + pool_key: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .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) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Tuple( + vec![ + ethabi::Token::Address(ethabi::Address::from_slice(& self + .pool_key.0)), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .pool_key.1)), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .pool_key.2.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 + .pool_key.3.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::Address(ethabi::Address::from_slice(& self + .pool_key.4)) + ], + ), + 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(), + ), + ), + ], + ); + 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 AccumulateAsFees { + const NAME: &'static str = "accumulateAsFees"; + 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 CancelOwnershipHandover {} + impl CancelOwnershipHandover { + const METHOD_ID: [u8; 4] = [84u8, 209u8, 241u8, 61u8]; + 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 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 CancelOwnershipHandover { + const NAME: &'static str = "cancelOwnershipHandover"; + 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 CollectFees { + pub pool_key: ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + pub salt: [u8; 32usize], + pub bounds: (substreams::scalar::BigInt, substreams::scalar::BigInt), + } + impl CollectFees { + const METHOD_ID: [u8; 4] = [129u8, 109u8, 213u8, 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::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ], + ), + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Int(32usize), + ethabi::ParamType::Int(32usize) + ], + ), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_key: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + }, + salt: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + bounds: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut v = [0 as u8; 32]; + tuple_elements[0usize] + .clone() + .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]; + tuple_elements[1usize] + .clone() + .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::Tuple( + vec![ + ethabi::Token::Address(ethabi::Address::from_slice(& self + .pool_key.0)), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .pool_key.1)), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .pool_key.2.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 + .pool_key.3.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::Address(ethabi::Address::from_slice(& self + .pool_key.4)) + ], + ), + ethabi::Token::FixedBytes(self.salt.as_ref().to_vec()), + ethabi::Token::Tuple( + vec![ + { let non_full_signed_bytes = self.bounds.0 + .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.bounds.1 + .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), + 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 CollectFees { + const NAME: &'static str = "collectFees"; + 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 CollectFees { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct CompleteOwnershipHandover { + pub pending_owner: Vec, + } + impl CompleteOwnershipHandover { + const METHOD_ID: [u8; 4] = [240u8, 78u8, 40u8, 62u8]; + 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 { + pending_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.pending_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 CompleteOwnershipHandover { + const NAME: &'static str = "completeOwnershipHandover"; + 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 ExpirationTime {} + impl ExpirationTime { + const METHOD_ID: [u8; 4] = [218u8, 40u8, 77u8, 204u8]; + 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 ExpirationTime { + const NAME: &'static str = "expirationTime"; + 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 ExpirationTime { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Forward { + pub to: Vec, + } + impl Forward { + const METHOD_ID: [u8; 4] = [16u8, 30u8, 137u8, 82u8]; + 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 { + to: 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.to))], + ); + 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 Forward { + const NAME: &'static str = "forward"; + 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 GetPoolFeesPerLiquidityInside { + pub pool_id: [u8; 32usize], + pub bounds: (substreams::scalar::BigInt, substreams::scalar::BigInt), + } + impl GetPoolFeesPerLiquidityInside { + const METHOD_ID: [u8; 4] = [147u8, 64u8, 118u8, 82u8]; + 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), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Int(32usize), + ethabi::ParamType::Int(32usize) + ], + ), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_id: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + bounds: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut v = [0 as u8; 32]; + tuple_elements[0usize] + .clone() + .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]; + tuple_elements[1usize] + .clone() + .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::FixedBytes(self.pool_id.as_ref().to_vec()), + ethabi::Token::Tuple( + vec![ + { let non_full_signed_bytes = self.bounds.0 + .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.bounds.1 + .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), + 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::Tuple( + vec![ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize) + ], + ), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let tuple_elements = values + .pop() + .expect("one output data should have existed") + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut v = [0 as u8; 32]; + tuple_elements[0usize] + .clone() + .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]; + tuple_elements[1usize] + .clone() + .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 GetPoolFeesPerLiquidityInside { + const NAME: &'static str = "getPoolFeesPerLiquidityInside"; + 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 GetPoolFeesPerLiquidityInside { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct InitializePool { + pub pool_key: ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + pub tick: substreams::scalar::BigInt, + } + impl InitializePool { + const METHOD_ID: [u8; 4] = [85u8, 108u8, 130u8, 17u8]; + 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::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ], + ), + ethabi::ParamType::Int(32usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_key: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + }, + 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( + &[ + ethabi::Token::Tuple( + vec![ + ethabi::Token::Address(ethabi::Address::from_slice(& self + .pool_key.0)), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .pool_key.1)), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .pool_key.2.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 + .pool_key.3.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::Address(ethabi::Address::from_slice(& self + .pool_key.4)) + ], + ), + { + 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 { + 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 InitializePool { + const NAME: &'static str = "initializePool"; + 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 InitializePool { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Load { + pub token: Vec, + pub salt: [u8; 32usize], + pub amount: substreams::scalar::BigInt, + } + impl Load { + const METHOD_ID: [u8; 4] = [88u8, 53u8, 42u8, 97u8]; + 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::FixedBytes(32usize), + ethabi::ParamType::Uint(128usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + salt: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + 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( + &[ + ethabi::Token::Address(ethabi::Address::from_slice(&self.token)), + ethabi::Token::FixedBytes(self.salt.as_ref().to_vec()), + 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 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 Load { + const NAME: &'static str = "load"; + 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 Lock {} + impl Lock { + const METHOD_ID: [u8; 4] = [248u8, 61u8, 8u8, 186u8]; + 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 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 Lock { + const NAME: &'static str = "lock"; + 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 NextInitializedTick { + pub pool_id: [u8; 32usize], + pub from_tick: substreams::scalar::BigInt, + pub tick_spacing: substreams::scalar::BigInt, + pub skip_ahead: substreams::scalar::BigInt, + } + impl NextInitializedTick { + const METHOD_ID: [u8; 4] = [102u8, 224u8, 100u8, 168u8]; + 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), + ethabi::ParamType::Int(32usize), + ethabi::ParamType::Uint(32usize), + ethabi::ParamType::Uint(256usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_id: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + from_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) + }, + tick_spacing: { + 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) + }, + skip_ahead: { + 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::FixedBytes(self.pool_id.as_ref().to_vec()), + { + let non_full_signed_bytes = self + .from_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()), + ) + }, + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.tick_spacing.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.skip_ahead.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, bool), String> { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result<(substreams::scalar::BigInt, bool), String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Int(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_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_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, 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 NextInitializedTick { + const NAME: &'static str = "nextInitializedTick"; + 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, bool)> + for NextInitializedTick { + fn output( + data: &[u8], + ) -> Result<(substreams::scalar::BigInt, bool), 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 OwnershipHandoverExpiresAt { + pub pending_owner: Vec, + } + impl OwnershipHandoverExpiresAt { + const METHOD_ID: [u8; 4] = [254u8, 232u8, 28u8, 244u8]; + 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 { + pending_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.pending_owner), + ), + ], + ); + 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 OwnershipHandoverExpiresAt { + const NAME: &'static str = "ownershipHandoverExpiresAt"; + 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 OwnershipHandoverExpiresAt { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Pay { + pub token: Vec, + } + impl Pay { + const METHOD_ID: [u8; 4] = [12u8, 17u8, 222u8, 221u8]; + 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 { + token: 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.token))], + ); + 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 Pay { + const NAME: &'static str = "pay"; + 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 PrevInitializedTick { + pub pool_id: [u8; 32usize], + pub from_tick: substreams::scalar::BigInt, + pub tick_spacing: substreams::scalar::BigInt, + pub skip_ahead: substreams::scalar::BigInt, + } + impl PrevInitializedTick { + const METHOD_ID: [u8; 4] = [14u8, 127u8, 38u8, 57u8]; + 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), + ethabi::ParamType::Int(32usize), + ethabi::ParamType::Uint(32usize), + ethabi::ParamType::Uint(256usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_id: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + from_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) + }, + tick_spacing: { + 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) + }, + skip_ahead: { + 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::FixedBytes(self.pool_id.as_ref().to_vec()), + { + let non_full_signed_bytes = self + .from_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()), + ) + }, + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.tick_spacing.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.skip_ahead.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, bool), String> { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result<(substreams::scalar::BigInt, bool), String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Int(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_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_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, 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 PrevInitializedTick { + const NAME: &'static str = "prevInitializedTick"; + 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, bool)> + for PrevInitializedTick { + fn output( + data: &[u8], + ) -> Result<(substreams::scalar::BigInt, bool), String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct RegisterExtension { + pub expected_call_points: (bool, bool, bool, bool, bool, bool, bool, bool), + } + impl RegisterExtension { + const METHOD_ID: [u8; 4] = [222u8, 111u8, 147u8, 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::Tuple( + vec![ + ethabi::ParamType::Bool, ethabi::ParamType::Bool, + ethabi::ParamType::Bool, ethabi::ParamType::Bool, + ethabi::ParamType::Bool, ethabi::ParamType::Bool, + ethabi::ParamType::Bool, ethabi::ParamType::Bool + ], + ), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + expected_call_points: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + tuple_elements[1usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + tuple_elements[2usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + tuple_elements[3usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + tuple_elements[4usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + tuple_elements[5usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + tuple_elements[6usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + tuple_elements[7usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + ) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Tuple( + vec![ + ethabi::Token::Bool(self.expected_call_points.0.clone()), + ethabi::Token::Bool(self.expected_call_points.1.clone()), + ethabi::Token::Bool(self.expected_call_points.2.clone()), + ethabi::Token::Bool(self.expected_call_points.3.clone()), + ethabi::Token::Bool(self.expected_call_points.4.clone()), + ethabi::Token::Bool(self.expected_call_points.5.clone()), + ethabi::Token::Bool(self.expected_call_points.6.clone()), + ethabi::Token::Bool(self.expected_call_points.7.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 RegisterExtension { + const NAME: &'static str = "registerExtension"; + 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 RenounceOwnership {} + impl RenounceOwnership { + const METHOD_ID: [u8; 4] = [113u8, 80u8, 24u8, 166u8]; + 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 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 RenounceOwnership { + const NAME: &'static str = "renounceOwnership"; + 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 RequestOwnershipHandover {} + impl RequestOwnershipHandover { + const METHOD_ID: [u8; 4] = [37u8, 105u8, 41u8, 98u8]; + 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 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 RequestOwnershipHandover { + const NAME: &'static str = "requestOwnershipHandover"; + 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 Save { + pub owner: Vec, + pub token: Vec, + pub salt: [u8; 32usize], + pub amount: substreams::scalar::BigInt, + } + impl Save { + const METHOD_ID: [u8; 4] = [133u8, 50u8, 209u8, 57u8]; + 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::FixedBytes(32usize), + ethabi::ParamType::Uint(128usize), + ], + 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(), + token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + salt: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + 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( + &[ + ethabi::Token::Address(ethabi::Address::from_slice(&self.owner)), + ethabi::Token::Address(ethabi::Address::from_slice(&self.token)), + ethabi::Token::FixedBytes(self.salt.as_ref().to_vec()), + 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 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 Save { + const NAME: &'static str = "save"; + 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 Sload { + pub slot: [u8; 32usize], + } + impl Sload { + const METHOD_ID: [u8; 4] = [244u8, 145u8, 10u8, 115u8]; + 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 { + slot: { + 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.slot.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<[u8; 32usize], String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut result = [0u8; 32]; + let v = values + .pop() + .expect("one output data should have existed") + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }) + } + 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<[u8; 32usize]> { + 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 Sload { + const NAME: &'static str = "sload"; + 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<[u8; 32usize]> for Sload { + fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Swap { + pub pool_key: ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + pub params: ( + substreams::scalar::BigInt, + bool, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + } + impl Swap { + const METHOD_ID: [u8; 4] = [170u8, 55u8, 59u8, 111u8]; + 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::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ], + ), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Int(128usize), ethabi::ParamType::Bool, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize) + ], + ), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_key: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + }, + params: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut v = [0 as u8; 32]; + tuple_elements[0usize] + .clone() + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + tuple_elements[1usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .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::Tuple( + vec![ + ethabi::Token::Address(ethabi::Address::from_slice(& self + .pool_key.0)), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .pool_key.1)), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .pool_key.2.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 + .pool_key.3.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::Address(ethabi::Address::from_slice(& self + .pool_key.4)) + ], + ), + ethabi::Token::Tuple( + vec![ + { let non_full_signed_bytes = self.params.0 + .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::Bool(self.params.1.clone()), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .params.2.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 + .params.3.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::Int(128usize), + ethabi::ParamType::Int(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_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 Tload { + pub slot: [u8; 32usize], + } + impl Tload { + const METHOD_ID: [u8; 4] = [189u8, 46u8, 88u8, 125u8]; + 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 { + slot: { + 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.slot.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<[u8; 32usize], String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut result = [0u8; 32]; + let v = values + .pop() + .expect("one output data should have existed") + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }) + } + 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<[u8; 32usize]> { + 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 Tload { + const NAME: &'static str = "tload"; + 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<[u8; 32usize]> for Tload { + fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct TransferOwnership { + pub new_owner: Vec, + } + impl TransferOwnership { + const METHOD_ID: [u8; 4] = [242u8, 253u8, 227u8, 139u8]; + 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 { + new_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.new_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 TransferOwnership { + const NAME: &'static str = "transferOwnership"; + 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 UpdatePosition { + pub pool_key: ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + pub params: ( + [u8; 32usize], + (substreams::scalar::BigInt, substreams::scalar::BigInt), + substreams::scalar::BigInt, + ), + } + impl UpdatePosition { + const METHOD_ID: [u8; 4] = [165u8, 112u8, 111u8, 58u8]; + 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::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ], + ), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Tuple(vec![ethabi::ParamType::Int(32usize), + ethabi::ParamType::Int(32usize)]), + ethabi::ParamType::Int(128usize) + ], + ), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_key: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + }, + params: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut result = [0u8; 32]; + let v = tuple_elements[0usize] + .clone() + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + { + let tuple_elements = tuple_elements[1usize] + .clone() + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut v = [0 as u8; 32]; + tuple_elements[0usize] + .clone() + .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]; + tuple_elements[1usize] + .clone() + .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]; + tuple_elements[2usize] + .clone() + .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::Tuple( + vec![ + ethabi::Token::Address(ethabi::Address::from_slice(& self + .pool_key.0)), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .pool_key.1)), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .pool_key.2.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 + .pool_key.3.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::Address(ethabi::Address::from_slice(& self + .pool_key.4)) + ], + ), + ethabi::Token::Tuple( + vec![ + ethabi::Token::FixedBytes(self.params.0.as_ref().to_vec()), + ethabi::Token::Tuple(vec![{ let non_full_signed_bytes = self + .params.1.0.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.params.1.1 + .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.params.2 + .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), + 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(128usize), + ethabi::ParamType::Int(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_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 UpdatePosition { + const NAME: &'static str = "updatePosition"; + 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 UpdatePosition { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Withdraw { + pub token: Vec, + pub recipient: Vec, + pub amount: substreams::scalar::BigInt, + } + impl Withdraw { + const METHOD_ID: [u8; 4] = [3u8, 166u8, 90u8, 182u8]; + 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(128usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + recipient: 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) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address(ethabi::Address::from_slice(&self.token)), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.recipient), + ), + 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 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 Withdraw { + const NAME: &'static str = "withdraw"; + 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 WithdrawProtocolFees { + pub recipient: Vec, + pub token: Vec, + pub amount: substreams::scalar::BigInt, + } + impl WithdrawProtocolFees { + const METHOD_ID: [u8; 4] = [61u8, 81u8, 37u8, 20u8]; + 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(256usize), + ], + 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(), + token: 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) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.recipient), + ), + ethabi::Token::Address(ethabi::Address::from_slice(&self.token)), + 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 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 WithdrawProtocolFees { + const NAME: &'static str = "withdrawProtocolFees"; + 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 ExtensionRegistered { + pub extension: Vec, + } + impl ExtensionRegistered { + const TOPIC_ID: [u8; 32] = [ + 236u8, + 18u8, + 86u8, + 38u8, + 110u8, + 71u8, + 10u8, + 187u8, + 134u8, + 134u8, + 32u8, + 200u8, + 81u8, + 246u8, + 189u8, + 226u8, + 163u8, + 255u8, + 96u8, + 37u8, + 73u8, + 220u8, + 173u8, + 49u8, + 138u8, + 185u8, + 204u8, + 252u8, + 178u8, + 151u8, + 127u8, + 20u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 32usize { + 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], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + extension: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + } + impl substreams_ethereum::Event for ExtensionRegistered { + const NAME: &'static str = "ExtensionRegistered"; + 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 FeesAccumulated { + pub pool_key: ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + pub amount0: substreams::scalar::BigInt, + pub amount1: substreams::scalar::BigInt, + } + impl FeesAccumulated { + const TOPIC_ID: [u8; 32] = [ + 59u8, + 179u8, + 81u8, + 188u8, + 245u8, + 129u8, + 151u8, + 154u8, + 78u8, + 90u8, + 77u8, + 90u8, + 109u8, + 26u8, + 153u8, + 147u8, + 32u8, + 226u8, + 213u8, + 190u8, + 51u8, + 44u8, + 219u8, + 55u8, + 89u8, + 11u8, + 181u8, + 159u8, + 24u8, + 177u8, + 131u8, + 81u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 224usize { + 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::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), 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 { + pool_key: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .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 FeesAccumulated { + const NAME: &'static str = "FeesAccumulated"; + 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 LoadedBalance { + pub owner: Vec, + pub token: Vec, + pub salt: [u8; 32usize], + pub amount: substreams::scalar::BigInt, + } + impl LoadedBalance { + const TOPIC_ID: [u8; 32] = [ + 233u8, + 93u8, + 71u8, + 15u8, + 173u8, + 181u8, + 253u8, + 214u8, + 26u8, + 9u8, + 226u8, + 252u8, + 152u8, + 201u8, + 140u8, + 105u8, + 92u8, + 17u8, + 12u8, + 150u8, + 63u8, + 44u8, + 120u8, + 94u8, + 114u8, + 106u8, + 169u8, + 4u8, + 217u8, + 220u8, + 234u8, + 57u8, + ]; + 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::Address, + ethabi::ParamType::Address, + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Uint(128usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + owner: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + salt: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + 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) + }, + }) + } + } + impl substreams_ethereum::Event for LoadedBalance { + const NAME: &'static str = "LoadedBalance"; + 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 OwnershipHandoverCanceled { + pub pending_owner: Vec, + } + impl OwnershipHandoverCanceled { + const TOPIC_ID: [u8; 32] = [ + 250u8, + 123u8, + 142u8, + 171u8, + 125u8, + 166u8, + 127u8, + 65u8, + 44u8, + 201u8, + 87u8, + 94u8, + 212u8, + 52u8, + 100u8, + 70u8, + 143u8, + 155u8, + 251u8, + 174u8, + 137u8, + 209u8, + 103u8, + 89u8, + 23u8, + 52u8, + 108u8, + 166u8, + 216u8, + 254u8, + 60u8, + 146u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 2usize { + 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 { + pending_owner: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pending_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 OwnershipHandoverCanceled { + const NAME: &'static str = "OwnershipHandoverCanceled"; + 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 OwnershipHandoverRequested { + pub pending_owner: Vec, + } + impl OwnershipHandoverRequested { + const TOPIC_ID: [u8; 32] = [ + 219u8, + 243u8, + 106u8, + 16u8, + 125u8, + 161u8, + 158u8, + 73u8, + 82u8, + 122u8, + 113u8, + 118u8, + 161u8, + 186u8, + 191u8, + 150u8, + 59u8, + 75u8, + 15u8, + 248u8, + 205u8, + 227u8, + 94u8, + 227u8, + 93u8, + 108u8, + 216u8, + 241u8, + 249u8, + 172u8, + 126u8, + 29u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 2usize { + 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 { + pending_owner: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pending_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 OwnershipHandoverRequested { + const NAME: &'static str = "OwnershipHandoverRequested"; + 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 OwnershipTransferred { + pub old_owner: Vec, + pub new_owner: Vec, + } + impl OwnershipTransferred { + const TOPIC_ID: [u8; 32] = [ + 139u8, + 224u8, + 7u8, + 156u8, + 83u8, + 22u8, + 89u8, + 20u8, + 19u8, + 68u8, + 205u8, + 31u8, + 208u8, + 164u8, + 242u8, + 132u8, + 25u8, + 73u8, + 127u8, + 151u8, + 34u8, + 163u8, + 218u8, + 175u8, + 227u8, + 180u8, + 24u8, + 111u8, + 107u8, + 100u8, + 87u8, + 224u8, + ]; + 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 OwnershipTransferred { + const NAME: &'static str = "OwnershipTransferred"; + 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 PoolInitialized { + pub pool_key: ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + pub tick: substreams::scalar::BigInt, + pub sqrt_ratio: substreams::scalar::BigInt, + } + impl PoolInitialized { + const TOPIC_ID: [u8; 32] = [ + 207u8, + 101u8, + 187u8, + 230u8, + 204u8, + 27u8, + 117u8, + 110u8, + 35u8, + 165u8, + 60u8, + 101u8, + 216u8, + 28u8, + 156u8, + 139u8, + 129u8, + 25u8, + 165u8, + 237u8, + 70u8, + 89u8, + 163u8, + 252u8, + 38u8, + 96u8, + 145u8, + 117u8, + 6u8, + 56u8, + 231u8, + 221u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 224usize { + 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::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ], + ), + ethabi::ParamType::Int(32usize), + ethabi::ParamType::Uint(256usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_key: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + }, + 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) + }, + sqrt_ratio: { + 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 PoolInitialized { + const NAME: &'static str = "PoolInitialized"; + 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 PositionFeesCollected { + pub pool_key: ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + pub position_key: ( + [u8; 32usize], + Vec, + (substreams::scalar::BigInt, substreams::scalar::BigInt), + ), + pub amount0: substreams::scalar::BigInt, + pub amount1: substreams::scalar::BigInt, + } + impl PositionFeesCollected { + const TOPIC_ID: [u8; 32] = [ + 114u8, + 71u8, + 150u8, + 76u8, + 39u8, + 153u8, + 67u8, + 203u8, + 135u8, + 146u8, + 250u8, + 183u8, + 187u8, + 41u8, + 30u8, + 242u8, + 228u8, + 125u8, + 91u8, + 55u8, + 51u8, + 70u8, + 204u8, + 46u8, + 97u8, + 34u8, + 84u8, + 183u8, + 7u8, + 55u8, + 67u8, + 233u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 352usize { + 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::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ], + ), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Address, + ethabi::ParamType::Tuple(vec![ethabi::ParamType::Int(32usize), + ethabi::ParamType::Int(32usize)]) + ], + ), + 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 { + pool_key: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + }, + position_key: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut result = [0u8; 32]; + let v = tuple_elements[0usize] + .clone() + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let tuple_elements = tuple_elements[2usize] + .clone() + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut v = [0 as u8; 32]; + tuple_elements[0usize] + .clone() + .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]; + tuple_elements[1usize] + .clone() + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_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 PositionFeesCollected { + const NAME: &'static str = "PositionFeesCollected"; + 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 PositionUpdated { + pub locker: Vec, + pub pool_key: ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + pub params: ( + [u8; 32usize], + (substreams::scalar::BigInt, substreams::scalar::BigInt), + substreams::scalar::BigInt, + ), + pub delta0: substreams::scalar::BigInt, + pub delta1: substreams::scalar::BigInt, + } + impl PositionUpdated { + const TOPIC_ID: [u8; 32] = [ + 207u8, + 67u8, + 158u8, + 142u8, + 9u8, + 56u8, + 79u8, + 88u8, + 130u8, + 84u8, + 11u8, + 31u8, + 166u8, + 115u8, + 97u8, + 39u8, + 158u8, + 61u8, + 57u8, + 196u8, + 216u8, + 229u8, + 227u8, + 6u8, + 201u8, + 244u8, + 90u8, + 79u8, + 227u8, + 94u8, + 192u8, + 191u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 384usize { + 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::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ], + ), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Tuple(vec![ethabi::ParamType::Int(32usize), + ethabi::ParamType::Int(32usize)]), + ethabi::ParamType::Int(128usize) + ], + ), + ethabi::ParamType::Int(128usize), + ethabi::ParamType::Int(128usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + locker: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + pool_key: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + }, + params: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut result = [0u8; 32]; + let v = tuple_elements[0usize] + .clone() + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + { + let tuple_elements = tuple_elements[1usize] + .clone() + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut v = [0 as u8; 32]; + tuple_elements[0usize] + .clone() + .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]; + tuple_elements[1usize] + .clone() + .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]; + tuple_elements[2usize] + .clone() + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + ) + }, + delta0: { + 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) + }, + delta1: { + 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 PositionUpdated { + const NAME: &'static str = "PositionUpdated"; + 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 ProtocolFeesPaid { + pub pool_key: ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + pub position_key: ( + [u8; 32usize], + Vec, + (substreams::scalar::BigInt, substreams::scalar::BigInt), + ), + pub amount0: substreams::scalar::BigInt, + pub amount1: substreams::scalar::BigInt, + } + impl ProtocolFeesPaid { + const TOPIC_ID: [u8; 32] = [ + 77u8, + 6u8, + 0u8, + 175u8, + 6u8, + 71u8, + 216u8, + 178u8, + 0u8, + 155u8, + 157u8, + 242u8, + 101u8, + 166u8, + 15u8, + 71u8, + 72u8, + 18u8, + 149u8, + 62u8, + 36u8, + 114u8, + 59u8, + 160u8, + 0u8, + 227u8, + 70u8, + 184u8, + 0u8, + 50u8, + 61u8, + 238u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 352usize { + 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::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ], + ), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Address, + ethabi::ParamType::Tuple(vec![ethabi::ParamType::Int(32usize), + ethabi::ParamType::Int(32usize)]) + ], + ), + 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 { + pool_key: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + }, + position_key: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut result = [0u8; 32]; + let v = tuple_elements[0usize] + .clone() + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let tuple_elements = tuple_elements[2usize] + .clone() + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut v = [0 as u8; 32]; + tuple_elements[0usize] + .clone() + .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]; + tuple_elements[1usize] + .clone() + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_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 ProtocolFeesPaid { + const NAME: &'static str = "ProtocolFeesPaid"; + 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 ProtocolFeesWithdrawn { + pub recipient: Vec, + pub token: Vec, + pub amount: substreams::scalar::BigInt, + } + impl ProtocolFeesWithdrawn { + const TOPIC_ID: [u8; 32] = [ + 143u8, + 194u8, + 65u8, + 48u8, + 143u8, + 252u8, + 23u8, + 129u8, + 126u8, + 106u8, + 140u8, + 106u8, + 82u8, + 168u8, + 247u8, + 205u8, + 73u8, + 49u8, + 223u8, + 202u8, + 12u8, + 83u8, + 159u8, + 211u8, + 90u8, + 99u8, + 3u8, + 17u8, + 199u8, + 228u8, + 197u8, + 123u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + 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::Address, + ethabi::ParamType::Uint(256usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + recipient: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + token: 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) + }, + }) + } + } + impl substreams_ethereum::Event for ProtocolFeesWithdrawn { + const NAME: &'static str = "ProtocolFeesWithdrawn"; + 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 SavedBalance { + pub owner: Vec, + pub token: Vec, + pub salt: [u8; 32usize], + pub amount: substreams::scalar::BigInt, + } + impl SavedBalance { + const TOPIC_ID: [u8; 32] = [ + 174u8, + 210u8, + 149u8, + 31u8, + 166u8, + 91u8, + 95u8, + 239u8, + 236u8, + 236u8, + 23u8, + 0u8, + 103u8, + 193u8, + 210u8, + 138u8, + 178u8, + 101u8, + 226u8, + 13u8, + 26u8, + 232u8, + 189u8, + 96u8, + 134u8, + 5u8, + 95u8, + 80u8, + 182u8, + 20u8, + 99u8, + 88u8, + ]; + 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::Address, + ethabi::ParamType::Address, + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Uint(128usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + owner: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + salt: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + 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) + }, + }) + } + } + impl substreams_ethereum::Event for SavedBalance { + const NAME: &'static str = "SavedBalance"; + 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 Swapped { + pub locker: Vec, + pub pool_key: ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + pub params: ( + substreams::scalar::BigInt, + bool, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + pub delta0: substreams::scalar::BigInt, + pub delta1: substreams::scalar::BigInt, + pub sqrt_ratio_after: substreams::scalar::BigInt, + pub tick_after: substreams::scalar::BigInt, + pub liquidity_after: substreams::scalar::BigInt, + } + impl Swapped { + const TOPIC_ID: [u8; 32] = [ + 21u8, + 3u8, + 18u8, + 134u8, + 146u8, + 8u8, + 74u8, + 3u8, + 167u8, + 33u8, + 144u8, + 144u8, + 135u8, + 236u8, + 34u8, + 229u8, + 231u8, + 1u8, + 88u8, + 58u8, + 81u8, + 189u8, + 162u8, + 125u8, + 45u8, + 35u8, + 14u8, + 67u8, + 98u8, + 69u8, + 198u8, + 160u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 480usize { + 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::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ], + ), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Int(128usize), ethabi::ParamType::Bool, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize) + ], + ), + ethabi::ParamType::Int(128usize), + ethabi::ParamType::Int(128usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Int(32usize), + ethabi::ParamType::Uint(128usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + locker: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + pool_key: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + }, + params: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut v = [0 as u8; 32]; + tuple_elements[0usize] + .clone() + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + tuple_elements[1usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + ) + }, + delta0: { + 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) + }, + delta1: { + 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_ratio_after: { + 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_after: { + 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) + }, + liquidity_after: { + 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 Swapped { + const NAME: &'static str = "Swapped"; + 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-ekubo/src/abi/erc20.rs b/substreams/ethereum-ekubo/src/abi/erc20.rs new file mode 100644 index 000000000..b7b3a395b --- /dev/null +++ b/substreams/ethereum-ekubo/src/abi/erc20.rs @@ -0,0 +1,1257 @@ + 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 Allowance { + pub owner: Vec, + pub spender: Vec, + } + impl Allowance { + const METHOD_ID: [u8; 4] = [221u8, 98u8, 237u8, 62u8]; + 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], + 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(), + spender: 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)), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.spender), + ), + ], + ); + 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 Allowance { + const NAME: &'static str = "allowance"; + 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 Allowance { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Approve { + pub spender: Vec, + pub value: substreams::scalar::BigInt, + } + impl Approve { + const METHOD_ID: [u8; 4] = [9u8, 94u8, 167u8, 179u8]; + 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)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + spender: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + 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.spender), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.value.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::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .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 { + 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 Approve { + const NAME: &'static str = "approve"; + 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 Approve { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct BalanceOf { + pub owner: Vec, + } + impl BalanceOf { + const METHOD_ID: [u8; 4] = [112u8, 160u8, 130u8, 49u8]; + 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 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 BalanceOf { + const NAME: &'static str = "balanceOf"; + 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 BalanceOf { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Decimals {} + impl Decimals { + const METHOD_ID: [u8; 4] = [49u8, 60u8, 229u8, 103u8]; + 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(8usize)], + 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 Decimals { + const NAME: &'static str = "decimals"; + 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 Decimals { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Name {} + impl Name { + const METHOD_ID: [u8; 4] = [6u8, 253u8, 222u8, 3u8]; + 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::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .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 { + 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 Name { + const NAME: &'static str = "name"; + 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 Name { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Symbol {} + impl Symbol { + const METHOD_ID: [u8; 4] = [149u8, 216u8, 155u8, 65u8]; + 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::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .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 { + 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 Symbol { + const NAME: &'static str = "symbol"; + 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 Symbol { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct TotalSupply {} + impl TotalSupply { + const METHOD_ID: [u8; 4] = [24u8, 22u8, 13u8, 221u8]; + 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 TotalSupply { + const NAME: &'static str = "totalSupply"; + 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 TotalSupply { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Transfer { + pub to: Vec, + pub value: substreams::scalar::BigInt, + } + impl Transfer { + const METHOD_ID: [u8; 4] = [169u8, 5u8, 156u8, 187u8]; + 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)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + to: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + 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.to)), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.value.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::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .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 { + 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 Transfer { + const NAME: &'static str = "transfer"; + 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 Transfer { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct TransferFrom { + pub from: Vec, + pub to: Vec, + pub value: substreams::scalar::BigInt, + } + impl TransferFrom { + const METHOD_ID: [u8; 4] = [35u8, 184u8, 114u8, 221u8]; + 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(256usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + from: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + to: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + 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.from)), + ethabi::Token::Address(ethabi::Address::from_slice(&self.to)), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.value.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::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .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 { + 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 TransferFrom { + const NAME: &'static str = "transferFrom"; + 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 TransferFrom { + fn output(data: &[u8]) -> Result { + 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 Approval { + pub owner: Vec, + pub spender: Vec, + pub value: substreams::scalar::BigInt, + } + impl Approval { + const TOPIC_ID: [u8; 32] = [ + 140u8, + 91u8, + 225u8, + 229u8, + 235u8, + 236u8, + 125u8, + 91u8, + 209u8, + 79u8, + 113u8, + 66u8, + 125u8, + 30u8, + 132u8, + 243u8, + 221u8, + 3u8, + 20u8, + 192u8, + 247u8, + 178u8, + 41u8, + 30u8, + 91u8, + 32u8, + 10u8, + 200u8, + 199u8, + 195u8, + 185u8, + 37u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 32usize { + 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)], + 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(), + spender: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'spender' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + 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 Approval { + const NAME: &'static str = "Approval"; + 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 Transfer { + pub from: Vec, + pub to: Vec, + pub value: substreams::scalar::BigInt, + } + impl Transfer { + const TOPIC_ID: [u8; 32] = [ + 221u8, + 242u8, + 82u8, + 173u8, + 27u8, + 226u8, + 200u8, + 155u8, + 105u8, + 194u8, + 176u8, + 104u8, + 252u8, + 55u8, + 141u8, + 170u8, + 149u8, + 43u8, + 167u8, + 241u8, + 99u8, + 196u8, + 161u8, + 22u8, + 40u8, + 245u8, + 90u8, + 77u8, + 245u8, + 35u8, + 179u8, + 239u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 32usize { + 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)], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + from: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'from' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + to: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'to' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + value: { + 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 Transfer { + const NAME: &'static str = "Transfer"; + 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-ekubo/src/abi/mod.rs b/substreams/ethereum-ekubo/src/abi/mod.rs new file mode 100644 index 000000000..6a9b59c2e --- /dev/null +++ b/substreams/ethereum-ekubo/src/abi/mod.rs @@ -0,0 +1,4 @@ +#![allow(clippy::all)] +pub mod core; +pub mod erc20; +pub mod oracle; diff --git a/substreams/ethereum-ekubo/src/abi/oracle.rs b/substreams/ethereum-ekubo/src/abi/oracle.rs new file mode 100644 index 000000000..17f68b388 --- /dev/null +++ b/substreams/ethereum-ekubo/src/abi/oracle.rs @@ -0,0 +1,3832 @@ + 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 AfterCollectFees { + pub param0: Vec, + pub param1: ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + pub param2: [u8; 32usize], + pub param3: (substreams::scalar::BigInt, substreams::scalar::BigInt), + pub param4: substreams::scalar::BigInt, + pub param5: substreams::scalar::BigInt, + } + impl AfterCollectFees { + const METHOD_ID: [u8; 4] = [167u8, 70u8, 163u8, 111u8]; + 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::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ], + ), + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Int(32usize), + ethabi::ParamType::Int(32usize) + ], + ), + 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 { + param0: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + param1: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + }, + param2: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + param3: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut v = [0 as u8; 32]; + tuple_elements[0usize] + .clone() + .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]; + tuple_elements[1usize] + .clone() + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + ) + }, + param4: { + 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) + }, + param5: { + 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.param0), + ), + ethabi::Token::Tuple( + vec![ + ethabi::Token::Address(ethabi::Address::from_slice(& self + .param1.0)), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .param1.1)), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .param1.2.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 + .param1.3.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::Address(ethabi::Address::from_slice(& self + .param1.4)) + ], + ), + ethabi::Token::FixedBytes(self.param2.as_ref().to_vec()), + ethabi::Token::Tuple( + vec![ + { let non_full_signed_bytes = self.param3.0 + .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.param3.1 + .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.param4.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.param5.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 AfterCollectFees { + const NAME: &'static str = "afterCollectFees"; + 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 AfterInitializePool { + pub param0: Vec, + pub param1: ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + pub param2: substreams::scalar::BigInt, + pub param3: substreams::scalar::BigInt, + } + impl AfterInitializePool { + const METHOD_ID: [u8; 4] = [236u8, 55u8, 17u8, 245u8]; + 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::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ], + ), + ethabi::ParamType::Int(32usize), + ethabi::ParamType::Uint(256usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + param0: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + param1: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + }, + param2: { + 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) + }, + param3: { + 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.param0), + ), + ethabi::Token::Tuple( + vec![ + ethabi::Token::Address(ethabi::Address::from_slice(& self + .param1.0)), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .param1.1)), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .param1.2.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 + .param1.3.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::Address(ethabi::Address::from_slice(& self + .param1.4)) + ], + ), + { + let non_full_signed_bytes = self.param2.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.param3.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 AfterInitializePool { + const NAME: &'static str = "afterInitializePool"; + 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 AfterSwap { + pub param0: Vec, + pub param1: ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + pub param2: ( + substreams::scalar::BigInt, + bool, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + pub param3: substreams::scalar::BigInt, + pub param4: substreams::scalar::BigInt, + } + impl AfterSwap { + const METHOD_ID: [u8; 4] = [50u8, 150u8, 96u8, 155u8]; + 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::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ], + ), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Int(128usize), ethabi::ParamType::Bool, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize) + ], + ), + ethabi::ParamType::Int(128usize), + ethabi::ParamType::Int(128usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + param0: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + param1: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + }, + param2: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut v = [0 as u8; 32]; + tuple_elements[0usize] + .clone() + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + tuple_elements[1usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + ) + }, + param3: { + 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) + }, + param4: { + 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::Address( + ethabi::Address::from_slice(&self.param0), + ), + ethabi::Token::Tuple( + vec![ + ethabi::Token::Address(ethabi::Address::from_slice(& self + .param1.0)), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .param1.1)), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .param1.2.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 + .param1.3.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::Address(ethabi::Address::from_slice(& self + .param1.4)) + ], + ), + ethabi::Token::Tuple( + vec![ + { let non_full_signed_bytes = self.param2.0 + .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::Bool(self.param2.1.clone()), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .param2.2.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 + .param2.3.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.param3.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.param4.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 AfterSwap { + const NAME: &'static str = "afterSwap"; + 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 AfterUpdatePosition { + pub param0: Vec, + pub param1: ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + pub param2: ( + [u8; 32usize], + (substreams::scalar::BigInt, substreams::scalar::BigInt), + substreams::scalar::BigInt, + ), + pub param3: substreams::scalar::BigInt, + pub param4: substreams::scalar::BigInt, + } + impl AfterUpdatePosition { + const METHOD_ID: [u8; 4] = [106u8, 243u8, 56u8, 139u8]; + 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::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ], + ), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Tuple(vec![ethabi::ParamType::Int(32usize), + ethabi::ParamType::Int(32usize)]), + ethabi::ParamType::Int(128usize) + ], + ), + ethabi::ParamType::Int(128usize), + ethabi::ParamType::Int(128usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + param0: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + param1: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + }, + param2: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut result = [0u8; 32]; + let v = tuple_elements[0usize] + .clone() + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + { + let tuple_elements = tuple_elements[1usize] + .clone() + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut v = [0 as u8; 32]; + tuple_elements[0usize] + .clone() + .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]; + tuple_elements[1usize] + .clone() + .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]; + tuple_elements[2usize] + .clone() + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + ) + }, + param3: { + 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) + }, + param4: { + 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::Address( + ethabi::Address::from_slice(&self.param0), + ), + ethabi::Token::Tuple( + vec![ + ethabi::Token::Address(ethabi::Address::from_slice(& self + .param1.0)), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .param1.1)), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .param1.2.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 + .param1.3.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::Address(ethabi::Address::from_slice(& self + .param1.4)) + ], + ), + ethabi::Token::Tuple( + vec![ + ethabi::Token::FixedBytes(self.param2.0.as_ref().to_vec()), + ethabi::Token::Tuple(vec![{ let non_full_signed_bytes = self + .param2.1.0.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.param2.1.1 + .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.param2.2 + .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.param3.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.param4.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 AfterUpdatePosition { + const NAME: &'static str = "afterUpdatePosition"; + 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 BeforeCollectFees { + pub param0: Vec, + pub param1: ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + pub param2: [u8; 32usize], + pub param3: (substreams::scalar::BigInt, substreams::scalar::BigInt), + } + impl BeforeCollectFees { + const METHOD_ID: [u8; 4] = [200u8, 130u8, 64u8, 21u8]; + 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::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ], + ), + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Int(32usize), + ethabi::ParamType::Int(32usize) + ], + ), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + param0: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + param1: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + }, + param2: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + param3: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut v = [0 as u8; 32]; + tuple_elements[0usize] + .clone() + .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]; + tuple_elements[1usize] + .clone() + .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::Address( + ethabi::Address::from_slice(&self.param0), + ), + ethabi::Token::Tuple( + vec![ + ethabi::Token::Address(ethabi::Address::from_slice(& self + .param1.0)), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .param1.1)), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .param1.2.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 + .param1.3.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::Address(ethabi::Address::from_slice(& self + .param1.4)) + ], + ), + ethabi::Token::FixedBytes(self.param2.as_ref().to_vec()), + ethabi::Token::Tuple( + vec![ + { let non_full_signed_bytes = self.param3.0 + .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.param3.1 + .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 BeforeCollectFees { + const NAME: &'static str = "beforeCollectFees"; + 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 BeforeInitializePool { + pub param0: Vec, + pub key: ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + pub param2: substreams::scalar::BigInt, + } + impl BeforeInitializePool { + const METHOD_ID: [u8; 4] = [158u8, 63u8, 119u8, 38u8]; + 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::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ], + ), + ethabi::ParamType::Int(32usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + param0: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + key: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + }, + param2: { + 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::Address( + ethabi::Address::from_slice(&self.param0), + ), + ethabi::Token::Tuple( + vec![ + ethabi::Token::Address(ethabi::Address::from_slice(& self + .key.0)), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .key.1)), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .key.2.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 + .key.3.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::Address(ethabi::Address::from_slice(& self + .key.4)) + ], + ), + { + let non_full_signed_bytes = self.param2.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 BeforeInitializePool { + const NAME: &'static str = "beforeInitializePool"; + 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 BeforeSwap { + pub param0: Vec, + pub pool_key: ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + pub params: ( + substreams::scalar::BigInt, + bool, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + } + impl BeforeSwap { + const METHOD_ID: [u8; 4] = [8u8, 17u8, 38u8, 31u8]; + 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::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ], + ), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Int(128usize), ethabi::ParamType::Bool, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize) + ], + ), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + param0: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + pool_key: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + }, + params: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut v = [0 as u8; 32]; + tuple_elements[0usize] + .clone() + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + tuple_elements[1usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .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.param0), + ), + ethabi::Token::Tuple( + vec![ + ethabi::Token::Address(ethabi::Address::from_slice(& self + .pool_key.0)), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .pool_key.1)), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .pool_key.2.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 + .pool_key.3.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::Address(ethabi::Address::from_slice(& self + .pool_key.4)) + ], + ), + ethabi::Token::Tuple( + vec![ + { let non_full_signed_bytes = self.params.0 + .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::Bool(self.params.1.clone()), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .params.2.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 + .params.3.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 BeforeSwap { + const NAME: &'static str = "beforeSwap"; + 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 BeforeUpdatePosition { + pub param0: Vec, + pub pool_key: ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + pub params: ( + [u8; 32usize], + (substreams::scalar::BigInt, substreams::scalar::BigInt), + substreams::scalar::BigInt, + ), + } + impl BeforeUpdatePosition { + const METHOD_ID: [u8; 4] = [12u8, 182u8, 178u8, 21u8]; + 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::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ], + ), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Tuple(vec![ethabi::ParamType::Int(32usize), + ethabi::ParamType::Int(32usize)]), + ethabi::ParamType::Int(128usize) + ], + ), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + param0: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + pool_key: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + }, + params: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut result = [0u8; 32]; + let v = tuple_elements[0usize] + .clone() + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + { + let tuple_elements = tuple_elements[1usize] + .clone() + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut v = [0 as u8; 32]; + tuple_elements[0usize] + .clone() + .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]; + tuple_elements[1usize] + .clone() + .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]; + tuple_elements[2usize] + .clone() + .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::Address( + ethabi::Address::from_slice(&self.param0), + ), + ethabi::Token::Tuple( + vec![ + ethabi::Token::Address(ethabi::Address::from_slice(& self + .pool_key.0)), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .pool_key.1)), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .pool_key.2.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 + .pool_key.3.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::Address(ethabi::Address::from_slice(& self + .pool_key.4)) + ], + ), + ethabi::Token::Tuple( + vec![ + ethabi::Token::FixedBytes(self.params.0.as_ref().to_vec()), + ethabi::Token::Tuple(vec![{ let non_full_signed_bytes = self + .params.1.0.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.params.1.1 + .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.params.2 + .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 BeforeUpdatePosition { + const NAME: &'static str = "beforeUpdatePosition"; + 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 ExtrapolateSnapshot { + pub token: Vec, + pub at_time: substreams::scalar::BigInt, + } + impl ExtrapolateSnapshot { + const METHOD_ID: [u8; 4] = [201u8, 221u8, 26u8, 131u8]; + 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(64usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + at_time: { + 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)), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.at_time.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(160usize), + ethabi::ParamType::Int(64usize), + ], + 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) + }, + )) + } + 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 ExtrapolateSnapshot { + const NAME: &'static str = "extrapolateSnapshot"; + 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 ExtrapolateSnapshot { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct FindPreviousSnapshot { + pub token: Vec, + pub time: substreams::scalar::BigInt, + } + impl FindPreviousSnapshot { + const METHOD_ID: [u8; 4] = [147u8, 148u8, 118u8, 78u8]; + 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(64usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + time: { + 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)), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.time.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, + 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(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Uint(32usize), + ethabi::ParamType::Uint(160usize), + ethabi::ParamType::Int(64usize) + ], + ), + ], + 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 tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut v = [0 as u8; 32]; + tuple_elements[0usize] + .clone() + .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]; + tuple_elements[1usize] + .clone() + .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]; + tuple_elements[2usize] + .clone() + .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, + ( + 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 FindPreviousSnapshot { + const NAME: &'static str = "findPreviousSnapshot"; + 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 FindPreviousSnapshot { + 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 GetExtrapolatedSnapshotsForSortedTimestamps { + pub token: Vec, + pub timestamps: Vec, + } + impl GetExtrapolatedSnapshotsForSortedTimestamps { + const METHOD_ID: [u8; 4] = [93u8, 44u8, 205u8, 73u8]; + 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::Array( + Box::new(ethabi::ParamType::Uint(64usize)), + ), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + timestamps: 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( + &[ + ethabi::Token::Address(ethabi::Address::from_slice(&self.token)), + { + let v = self + .timestamps + .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<(substreams::scalar::BigInt, substreams::scalar::BigInt)>, + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + Vec<(substreams::scalar::BigInt, substreams::scalar::BigInt)>, + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Array( + Box::new( + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Uint(160usize), + ethabi::ParamType::Int(64usize) + ], + ), + ), + ), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let tuple_elements = inner.into_tuple().expect(INTERNAL_ERR); + ( + { + let mut v = [0 as u8; 32]; + tuple_elements[0usize] + .clone() + .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]; + tuple_elements[1usize] + .clone() + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_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> { + 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 GetExtrapolatedSnapshotsForSortedTimestamps { + const NAME: &'static str = "getExtrapolatedSnapshotsForSortedTimestamps"; + 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<(substreams::scalar::BigInt, substreams::scalar::BigInt)>, + > for GetExtrapolatedSnapshotsForSortedTimestamps { + fn output( + data: &[u8], + ) -> Result< + Vec<(substreams::scalar::BigInt, substreams::scalar::BigInt)>, + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPoolKey { + pub token: Vec, + } + impl GetPoolKey { + const METHOD_ID: [u8; 4] = [110u8, 127u8, 253u8, 75u8]; + 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 { + token: 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.token))], + ); + 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, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(128usize), + ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ], + ), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let tuple_elements = values + .pop() + .expect("one output data should have existed") + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .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]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .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< + ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + 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 GetPoolKey { + const NAME: &'static str = "getPoolKey"; + 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, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + > for GetPoolKey { + fn output( + data: &[u8], + ) -> Result< + ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct OracleToken {} + impl OracleToken { + const METHOD_ID: [u8; 4] = [131u8, 71u8, 47u8, 207u8]; + 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 OracleToken { + const NAME: &'static str = "oracleToken"; + 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 OracleToken { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct SecondsSinceOffset {} + impl SecondsSinceOffset { + const METHOD_ID: [u8; 4] = [124u8, 142u8, 40u8, 16u8]; + 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(32usize)], + 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 SecondsSinceOffset { + const NAME: &'static str = "secondsSinceOffset"; + 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 SecondsSinceOffset { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct SecondsSinceOffsetToTimestamp { + pub sso: substreams::scalar::BigInt, + } + impl SecondsSinceOffsetToTimestamp { + const METHOD_ID: [u8; 4] = [140u8, 182u8, 183u8, 72u8]; + 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(32usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + sso: { + 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.sso.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::Uint(64usize)], + 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 SecondsSinceOffsetToTimestamp { + const NAME: &'static str = "secondsSinceOffsetToTimestamp"; + 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 SecondsSinceOffsetToTimestamp { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Sload { + pub slot: [u8; 32usize], + } + impl Sload { + const METHOD_ID: [u8; 4] = [244u8, 145u8, 10u8, 115u8]; + 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 { + slot: { + 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.slot.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<[u8; 32usize], String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut result = [0u8; 32]; + let v = values + .pop() + .expect("one output data should have existed") + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }) + } + 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<[u8; 32usize]> { + 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 Sload { + const NAME: &'static str = "sload"; + 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<[u8; 32usize]> for Sload { + fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct SnapshotCount { + pub token: Vec, + } + impl SnapshotCount { + const METHOD_ID: [u8; 4] = [212u8, 3u8, 32u8, 174u8]; + 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 { + token: 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.token))], + ); + 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 SnapshotCount { + const NAME: &'static str = "snapshotCount"; + 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 SnapshotCount { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Snapshots { + pub token: Vec, + pub index: substreams::scalar::BigInt, + } + impl Snapshots { + const METHOD_ID: [u8; 4] = [219u8, 85u8, 23u8, 176u8]; + 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)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + 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::Address(ethabi::Address::from_slice(&self.token)), + 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, + ), + 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::Uint(32usize), + ethabi::ParamType::Uint(160usize), + ethabi::ParamType::Int(64usize), + ], + 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_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, + 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 Snapshots { + const NAME: &'static str = "snapshots"; + 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 Snapshots { + fn output( + data: &[u8], + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct TimestampOffset {} + impl TimestampOffset { + const METHOD_ID: [u8; 4] = [210u8, 246u8, 128u8, 53u8]; + 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(64usize)], + 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 TimestampOffset { + const NAME: &'static str = "timestampOffset"; + 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 TimestampOffset { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Tload { + pub slot: [u8; 32usize], + } + impl Tload { + const METHOD_ID: [u8; 4] = [189u8, 46u8, 88u8, 125u8]; + 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 { + slot: { + 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.slot.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<[u8; 32usize], String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut result = [0u8; 32]; + let v = values + .pop() + .expect("one output data should have existed") + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }) + } + 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<[u8; 32usize]> { + 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 Tload { + const NAME: &'static str = "tload"; + 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<[u8; 32usize]> for Tload { + fn output(data: &[u8]) -> Result<[u8; 32usize], 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 SnapshotEvent { + pub token: Vec, + pub index: substreams::scalar::BigInt, + pub timestamp: substreams::scalar::BigInt, + pub seconds_per_liquidity_cumulative: substreams::scalar::BigInt, + pub tick_cumulative: substreams::scalar::BigInt, + } + impl SnapshotEvent { + const TOPIC_ID: [u8; 32] = [ + 84u8, + 1u8, + 11u8, + 213u8, + 93u8, + 37u8, + 184u8, + 58u8, + 113u8, + 51u8, + 193u8, + 29u8, + 139u8, + 54u8, + 217u8, + 240u8, + 51u8, + 149u8, + 163u8, + 147u8, + 220u8, + 224u8, + 31u8, + 115u8, + 117u8, + 177u8, + 191u8, + 40u8, + 225u8, + 75u8, + 240u8, + 109u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + 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::Address, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(64usize), + ethabi::ParamType::Uint(160usize), + ethabi::ParamType::Int(64usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + 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) + }, + timestamp: { + 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) + }, + seconds_per_liquidity_cumulative: { + 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_cumulative: { + 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 SnapshotEvent { + const NAME: &'static str = "SnapshotEvent"; + 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-ekubo/src/lib.rs b/substreams/ethereum-ekubo/src/lib.rs new file mode 100644 index 000000000..83bc58617 --- /dev/null +++ b/substreams/ethereum-ekubo/src/lib.rs @@ -0,0 +1,4 @@ +mod abi; +mod pool_factories; +mod modules; + diff --git a/substreams/ethereum-ekubo/src/modules.rs b/substreams/ethereum-ekubo/src/modules.rs new file mode 100644 index 000000000..f798d26a3 --- /dev/null +++ b/substreams/ethereum-ekubo/src/modules.rs @@ -0,0 +1,292 @@ +//! Template for Protocols with singleton contract +//! +//! +use std::collections::HashMap; +use anyhow::Result; +use substreams::pb::substreams::StoreDeltas; +use substreams::prelude::*; +use substreams_ethereum::Event; +use substreams_ethereum::pb::eth; +use tycho_substreams::balances::aggregate_balances_changes; +use tycho_substreams::contract::extract_contract_changes_builder; +use tycho_substreams::prelude::*; +use itertools::Itertools; +use crate::pool_factories; +use crate::pool_factories::{hash_pool_key, DeploymentConfig}; +use crate::abi::core::events as core_events; + +/// Find and create all relevant protocol components +/// +/// This method maps over blocks and instantiates ProtocolComponents with a unique ids +/// as well as all necessary metadata for routing and encoding. +#[substreams::handlers::map] +fn map_protocol_components( + params: String, + block: eth::v2::Block, +) -> Result { + let config = serde_qs::from_str(params.as_str())?; + Ok(BlockTransactionProtocolComponents { + tx_components: block + .transactions() + .filter_map(|tx| { + let components = tx + .logs_with_calls() + .filter_map(|(log, call)| { + pool_factories::maybe_create_component( + call.call, + log, + tx, + &config, + ) + }) + .collect::>(); + + if !components.is_empty() { + Some(TransactionProtocolComponents { tx: Some(tx.into()), components }) + } else { + None + } + }) + .collect::>(), + }) +} + +#[substreams::handlers::store] +fn store_protocol_components(map_protocol_components: BlockTransactionProtocolComponents, store: StoreSetRaw) { + map_protocol_components.tx_components + .into_iter() + .for_each(|tx_pc| { + tx_pc + .components + .into_iter() + .for_each(|pc| { + let tokens = serde_sibor::to_bytes(&pc.tokens).expect("Sibor encoding protocol component tokens failed"); + store.set(0, &pc.id, &tokens); + }) + }); +} + +/// Extracts balance changes per component +/// +/// This template function inspects ERC20 transfer events to/from the singleton contract +/// to extract balance changes. If a transfer to the component is detected, it's +/// balanced is increased and if a balance from the component is detected its balance +/// is decreased. +/// +/// ## Note: +/// Changes are necessary if your protocol uses native ETH or your component burns or +/// mints tokens without emitting transfer events. +/// +/// You may want to ignore LP tokens if your protocol emits transfer events for these +/// here. +#[substreams::handlers::map] +fn map_relative_component_balance(params: String, block: eth::v2::Block, store: StoreGetRaw) -> Result { + let config: DeploymentConfig = serde_qs::from_str(params.as_str())?; + let res = block + .transactions() + .flat_map(|tx| { + tx.logs_with_calls() + .map(|(log, _)| { + if log.address != config.core { + return vec![]; + } + if let Some(ev) = core_events::PositionUpdated::match_and_decode(log) { + let pool_id = hash_pool_key(&ev.pool_key); + // TODO better error handling + let pool_tokens: Vec> = serde_sibor::from_bytes( + &store.get_last(&pool_id).expect("Missing protocol component") + ).expect("Decoding component tokens failed"); + + vec![ + BalanceDelta { + ord: log.ordinal, + tx: Some(tx.into()), + token: pool_tokens[0].clone(), + delta: ev.delta0.to_signed_bytes_be(), + component_id: pool_id.clone().into(), + }, + BalanceDelta { + ord: log.ordinal, + tx: Some(tx.into()), + token: pool_tokens[1].clone(), + delta: ev.delta1.to_signed_bytes_be(), + component_id: pool_id.into(), + } + ] + } else if let Some(ev) = core_events::PositionFeesCollected::match_and_decode(log) { + let pool_id = hash_pool_key(&ev.pool_key); + // TODO better error handling + let pool_tokens: Vec> = serde_sibor::from_bytes( + &store.get_last(&pool_id).expect("Missing protocol component") + ).expect("Decoding component tokens failed"); + + vec![ + BalanceDelta { + ord: log.ordinal, + tx: Some(tx.into()), + token: pool_tokens[0].clone(), + delta: ev.amount0.neg().to_signed_bytes_be(), + component_id: pool_id.clone().into(), + }, + BalanceDelta { + ord: log.ordinal, + tx: Some(tx.into()), + token: pool_tokens[1].clone(), + delta: ev.amount1.neg().to_signed_bytes_be(), + component_id: pool_id.into(), + } + ] + } else if let Some(ev) = core_events::Swapped::match_and_decode(log) { + let pool_id = hash_pool_key(&ev.pool_key); + // TODO better error handling + let pool_tokens: Vec> = serde_sibor::from_bytes( + &store.get_last(&pool_id).expect("Missing protocol component") + ).expect("Decoding component tokens failed"); + + vec![ + BalanceDelta { + ord: log.ordinal, + tx: Some(tx.into()), + token: pool_tokens[0].clone(), + delta: ev.delta0.to_signed_bytes_be(), + component_id: pool_id.clone().into(), + }, + BalanceDelta { + ord: log.ordinal, + tx: Some(tx.into()), + token: pool_tokens[1].clone(), + delta: ev.delta1.to_signed_bytes_be(), + component_id: pool_id.into(), + } + ] + } else if let Some(ev) = core_events::FeesAccumulated::match_and_decode(log) { + let pool_id = hash_pool_key(&ev.pool_key); + // TODO better error handling + let pool_tokens: Vec> = serde_sibor::from_bytes( + &store.get_last(&pool_id).expect("Missing protocol component") + ).expect("Decoding component tokens failed"); + + vec![ + BalanceDelta { + ord: log.ordinal, + tx: Some(tx.into()), + token: pool_tokens[0].clone(), + delta: ev.amount0.to_signed_bytes_be(), + component_id: pool_id.clone().into(), + }, + BalanceDelta { + ord: log.ordinal, + tx: Some(tx.into()), + token: pool_tokens[1].clone(), + delta: ev.amount1.to_signed_bytes_be(), + component_id: pool_id.into(), + } + ] + } else { + vec![] + } + }) + }) + .flatten() + .collect::>(); + + Ok(BlockBalanceDeltas { balance_deltas: res }) +} + +/// Aggregates relative balances values into absolute values +/// +/// Aggregate the relative balances in an additive store since tycho-indexer expects +/// absolute balance inputs. +/// +/// ## Note: +/// This method should usually not require any changes. +#[substreams::handlers::store] +pub fn store_component_balances(deltas: BlockBalanceDeltas, store: StoreAddBigInt) { + tycho_substreams::balances::store_balance_changes(deltas, store); +} + +/// Aggregates protocol components and balance changes by transaction. +/// +/// This is the main method that will aggregate all changes as well as extract all +/// relevant contract storage deltas. +/// +/// ## Note: +/// You may have to change this method if your components have any default dynamic +/// attributes, or if you need any additional static contracts indexed. +#[substreams::handlers::map] +fn map_protocol_changes( + params: String, + block: eth::v2::Block, + new_components: BlockTransactionProtocolComponents, + deltas: BlockBalanceDeltas, + balance_store: StoreDeltas, +) -> Result { + let config: DeploymentConfig = serde_qs::from_str(params.as_str())?; + // 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(); + + // Aggregate newly created components per tx + new_components + .tx_components + .iter() + .for_each(|tx_component| { + // initialise builder if not yet present for this tx + let tx = tx_component.tx.as_ref().unwrap(); + let builder = transaction_changes + .entry(tx.index) + .or_insert_with(|| TransactionChangesBuilder::new(tx)); + + // iterate over individual components created within this tx + tx_component + .components + .iter() + .for_each(|component| { + builder.add_protocol_component(component); + }); + }); + + // Aggregate absolute balances per transaction. + aggregate_balances_changes(balance_store, deltas) + .into_iter() + .for_each(|(_, (tx, balances))| { + let builder = transaction_changes + .entry(tx.index) + .or_insert_with(|| TransactionChangesBuilder::new(&tx)); + let mut contract_changes = InterimContractChange::new(&config.core, false); + balances + .values() + .for_each(|token_bc_map| { + token_bc_map + .values() + .for_each(|bc| { + // track component balance + builder.add_balance_change(bc); + // track vault contract balance + contract_changes.upsert_token_balance(bc.token.as_slice(), bc.balance.as_slice()) + }) + }); + builder.add_contract_changes(&contract_changes); + }); + + + // Extract and insert any storage changes that happened for any of the components. + extract_contract_changes_builder( + &block, + |addr| { + (addr == config.core) || (addr == config.oracle) + }, + &mut transaction_changes, + ); + + // Process all `transaction_changes` for final output in the `BlockChanges`, + // sorted by transaction index (the key). + Ok(BlockChanges { + block: Some((&block).into()), + changes: transaction_changes + .drain() + .sorted_unstable_by_key(|(index, _)| *index) + .filter_map(|(_, builder)| builder.build()) + .collect::>(), + }) +} \ No newline at end of file diff --git a/substreams/ethereum-ekubo/src/pb/mod.rs b/substreams/ethereum-ekubo/src/pb/mod.rs new file mode 100644 index 000000000..a231da221 --- /dev/null +++ b/substreams/ethereum-ekubo/src/pb/mod.rs @@ -0,0 +1,52 @@ +// @generated +pub mod google { + // @@protoc_insertion_point(attribute:google.protobuf) + pub mod protobuf { + include!("google.protobuf.rs"); + // @@protoc_insertion_point(google.protobuf) + } +} +pub mod sf { + // @@protoc_insertion_point(attribute:sf.substreams) + pub mod substreams { + include!("sf.substreams.rs"); + // @@protoc_insertion_point(sf.substreams) + pub mod index { + // @@protoc_insertion_point(attribute:sf.substreams.index.v1) + pub mod v1 { + include!("sf.substreams.index.v1.rs"); + // @@protoc_insertion_point(sf.substreams.index.v1) + } + } + pub mod rpc { + // @@protoc_insertion_point(attribute:sf.substreams.rpc.v2) + pub mod v2 { + include!("sf.substreams.rpc.v2.rs"); + // @@protoc_insertion_point(sf.substreams.rpc.v2) + } + } + pub mod sink { + pub mod service { + // @@protoc_insertion_point(attribute:sf.substreams.sink.service.v1) + pub mod v1 { + include!("sf.substreams.sink.service.v1.rs"); + // @@protoc_insertion_point(sf.substreams.sink.service.v1) + } + } + } + // @@protoc_insertion_point(attribute:sf.substreams.v1) + pub mod v1 { + include!("sf.substreams.v1.rs"); + // @@protoc_insertion_point(sf.substreams.v1) + } + } +} +pub mod tycho { + pub mod evm { + // @@protoc_insertion_point(attribute:tycho.evm.v1) + pub mod v1 { + include!("tycho.evm.v1.rs"); + // @@protoc_insertion_point(tycho.evm.v1) + } + } +} diff --git a/substreams/ethereum-ekubo/src/pb/sf.substreams.index.v1.rs b/substreams/ethereum-ekubo/src/pb/sf.substreams.index.v1.rs new file mode 100644 index 000000000..a9543652c --- /dev/null +++ b/substreams/ethereum-ekubo/src/pb/sf.substreams.index.v1.rs @@ -0,0 +1,8 @@ +// @generated +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Keys { + #[prost(string, repeated, tag="1")] + pub keys: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, +} +// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-ekubo/src/pb/sf.substreams.rpc.v2.rs b/substreams/ethereum-ekubo/src/pb/sf.substreams.rpc.v2.rs new file mode 100644 index 000000000..96df02286 --- /dev/null +++ b/substreams/ethereum-ekubo/src/pb/sf.substreams.rpc.v2.rs @@ -0,0 +1,340 @@ +// @generated +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Request { + #[prost(int64, tag="1")] + pub start_block_num: i64, + #[prost(string, tag="2")] + pub start_cursor: ::prost::alloc::string::String, + #[prost(uint64, tag="3")] + pub stop_block_num: u64, + /// With final_block_only, you only receive blocks that are irreversible: + /// 'final_block_height' will be equal to current block and no 'undo_signal' will ever be sent + #[prost(bool, tag="4")] + pub final_blocks_only: bool, + /// Substreams has two mode when executing your module(s) either development mode or production + /// mode. Development and production modes impact the execution of Substreams, important aspects + /// of execution include: + /// * The time required to reach the first byte. + /// * The speed that large ranges get executed. + /// * The module logs and outputs sent back to the client. + /// + /// By default, the engine runs in developer mode, with richer and deeper output. Differences + /// between production and development modes include: + /// * Forward parallel execution is enabled in production mode and disabled in development mode + /// * The time required to reach the first byte in development mode is faster than in production mode. + /// + /// Specific attributes of development mode include: + /// * The client will receive all of the executed module's logs. + /// * It's possible to request specific store snapshots in the execution tree (via `debug_initial_store_snapshot_for_modules`). + /// * Multiple module's output is possible. + /// + /// With production mode`, however, you trade off functionality for high speed enabling forward + /// parallel execution of module ahead of time. + #[prost(bool, tag="5")] + pub production_mode: bool, + #[prost(string, tag="6")] + pub output_module: ::prost::alloc::string::String, + #[prost(message, optional, tag="7")] + pub modules: ::core::option::Option, + /// Available only in developer mode + #[prost(string, repeated, tag="10")] + pub debug_initial_store_snapshot_for_modules: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Response { + #[prost(oneof="response::Message", tags="1, 2, 3, 4, 5, 10, 11")] + pub message: ::core::option::Option, +} +/// Nested message and enum types in `Response`. +pub mod response { + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Message { + /// Always sent first + #[prost(message, tag="1")] + Session(super::SessionInit), + /// Progress of data preparation, before sending in the stream of `data` events. + #[prost(message, tag="2")] + Progress(super::ModulesProgress), + #[prost(message, tag="3")] + BlockScopedData(super::BlockScopedData), + #[prost(message, tag="4")] + BlockUndoSignal(super::BlockUndoSignal), + #[prost(message, tag="5")] + FatalError(super::Error), + /// Available only in developer mode, and only if `debug_initial_store_snapshot_for_modules` is set. + #[prost(message, tag="10")] + DebugSnapshotData(super::InitialSnapshotData), + /// Available only in developer mode, and only if `debug_initial_store_snapshot_for_modules` is set. + #[prost(message, tag="11")] + DebugSnapshotComplete(super::InitialSnapshotComplete), + } +} +/// BlockUndoSignal informs you that every bit of data +/// with a block number above 'last_valid_block' has been reverted +/// on-chain. Delete that data and restart from 'last_valid_cursor' +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockUndoSignal { + #[prost(message, optional, tag="1")] + pub last_valid_block: ::core::option::Option, + #[prost(string, tag="2")] + pub last_valid_cursor: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockScopedData { + #[prost(message, optional, tag="1")] + pub output: ::core::option::Option, + #[prost(message, optional, tag="2")] + pub clock: ::core::option::Option, + #[prost(string, tag="3")] + pub cursor: ::prost::alloc::string::String, + /// Non-deterministic, allows substreams-sink to let go of their undo data. + #[prost(uint64, tag="4")] + pub final_block_height: u64, + #[prost(message, repeated, tag="10")] + pub debug_map_outputs: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="11")] + pub debug_store_outputs: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SessionInit { + #[prost(string, tag="1")] + pub trace_id: ::prost::alloc::string::String, + #[prost(uint64, tag="2")] + pub resolved_start_block: u64, + #[prost(uint64, tag="3")] + pub linear_handoff_block: u64, + #[prost(uint64, tag="4")] + pub max_parallel_workers: u64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct InitialSnapshotComplete { + #[prost(string, tag="1")] + pub cursor: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct InitialSnapshotData { + #[prost(string, tag="1")] + pub module_name: ::prost::alloc::string::String, + #[prost(message, repeated, tag="2")] + pub deltas: ::prost::alloc::vec::Vec, + #[prost(uint64, tag="4")] + pub sent_keys: u64, + #[prost(uint64, tag="3")] + pub total_keys: u64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MapModuleOutput { + #[prost(string, tag="1")] + pub name: ::prost::alloc::string::String, + #[prost(message, optional, tag="2")] + pub map_output: ::core::option::Option<::prost_types::Any>, + /// DebugOutputInfo is available in non-production mode only + #[prost(message, optional, tag="10")] + pub debug_info: ::core::option::Option, +} +/// StoreModuleOutput are produced for store modules in development mode. +/// It is not possible to retrieve store models in production, with parallelization +/// enabled. If you need the deltas directly, write a pass through mapper module +/// that will get them down to you. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StoreModuleOutput { + #[prost(string, tag="1")] + pub name: ::prost::alloc::string::String, + #[prost(message, repeated, tag="2")] + pub debug_store_deltas: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag="10")] + pub debug_info: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OutputDebugInfo { + #[prost(string, repeated, tag="1")] + pub logs: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + /// LogsTruncated is a flag that tells you if you received all the logs or if they + /// were truncated because you logged too much (fixed limit currently is set to 128 KiB). + #[prost(bool, tag="2")] + pub logs_truncated: bool, + #[prost(bool, tag="3")] + pub cached: bool, +} +/// ModulesProgress is a message that is sent every 500ms +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ModulesProgress { + /// List of jobs running on tier2 servers + #[prost(message, repeated, tag="2")] + pub running_jobs: ::prost::alloc::vec::Vec, + /// Execution statistics for each module + #[prost(message, repeated, tag="3")] + pub modules_stats: ::prost::alloc::vec::Vec, + /// Stages definition and completed block ranges + #[prost(message, repeated, tag="4")] + pub stages: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag="5")] + pub processed_bytes: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProcessedBytes { + #[prost(uint64, tag="1")] + pub total_bytes_read: u64, + #[prost(uint64, tag="2")] + pub total_bytes_written: u64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Error { + #[prost(string, tag="1")] + pub module: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub reason: ::prost::alloc::string::String, + #[prost(string, repeated, tag="3")] + pub logs: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + /// FailureLogsTruncated is a flag that tells you if you received all the logs or if they + /// were truncated because you logged too much (fixed limit currently is set to 128 KiB). + #[prost(bool, tag="4")] + pub logs_truncated: bool, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Job { + #[prost(uint32, tag="1")] + pub stage: u32, + #[prost(uint64, tag="2")] + pub start_block: u64, + #[prost(uint64, tag="3")] + pub stop_block: u64, + #[prost(uint64, tag="4")] + pub processed_blocks: u64, + #[prost(uint64, tag="5")] + pub duration_ms: u64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Stage { + #[prost(string, repeated, tag="1")] + pub modules: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + #[prost(message, repeated, tag="2")] + pub completed_ranges: ::prost::alloc::vec::Vec, +} +/// ModuleStats gathers metrics and statistics from each module, running on tier1 or tier2 +/// All the 'count' and 'time_ms' values may include duplicate for each stage going over that module +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ModuleStats { + /// name of the module + #[prost(string, tag="1")] + pub name: ::prost::alloc::string::String, + /// total_processed_blocks is the sum of blocks sent to that module code + #[prost(uint64, tag="2")] + pub total_processed_block_count: u64, + /// total_processing_time_ms is the sum of all time spent running that module code + #[prost(uint64, tag="3")] + pub total_processing_time_ms: u64, + /// // external_calls are chain-specific intrinsics, like "Ethereum RPC calls". + #[prost(message, repeated, tag="4")] + pub external_call_metrics: ::prost::alloc::vec::Vec, + /// total_store_operation_time_ms is the sum of all time spent running that module code waiting for a store operation (ex: read, write, delete...) + #[prost(uint64, tag="5")] + pub total_store_operation_time_ms: u64, + /// total_store_read_count is the sum of all the store Read operations called from that module code + #[prost(uint64, tag="6")] + pub total_store_read_count: u64, + /// total_store_write_count is the sum of all store Write operations called from that module code (store-only) + #[prost(uint64, tag="10")] + pub total_store_write_count: u64, + /// total_store_deleteprefix_count is the sum of all store DeletePrefix operations called from that module code (store-only) + /// note that DeletePrefix can be a costly operation on large stores + #[prost(uint64, tag="11")] + pub total_store_deleteprefix_count: u64, + /// store_size_bytes is the uncompressed size of the full KV store for that module, from the last 'merge' operation (store-only) + #[prost(uint64, tag="12")] + pub store_size_bytes: u64, + /// total_store_merging_time_ms is the time spent merging partial stores into a full KV store for that module (store-only) + #[prost(uint64, tag="13")] + pub total_store_merging_time_ms: u64, + /// store_currently_merging is true if there is a merging operation (partial store to full KV store) on the way. + #[prost(bool, tag="14")] + pub store_currently_merging: bool, + /// highest_contiguous_block is the highest block in the highest merged full KV store of that module (store-only) + #[prost(uint64, tag="15")] + pub highest_contiguous_block: u64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ExternalCallMetric { + #[prost(string, tag="1")] + pub name: ::prost::alloc::string::String, + #[prost(uint64, tag="2")] + pub count: u64, + #[prost(uint64, tag="3")] + pub time_ms: u64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StoreDelta { + #[prost(enumeration="store_delta::Operation", tag="1")] + pub operation: i32, + #[prost(uint64, tag="2")] + pub ordinal: u64, + #[prost(string, tag="3")] + pub key: ::prost::alloc::string::String, + #[prost(bytes="vec", tag="4")] + pub old_value: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="5")] + pub new_value: ::prost::alloc::vec::Vec, +} +/// Nested message and enum types in `StoreDelta`. +pub mod store_delta { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] + #[repr(i32)] + pub enum Operation { + Unset = 0, + Create = 1, + Update = 2, + Delete = 3, + } + impl Operation { + /// 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 { + Operation::Unset => "UNSET", + Operation::Create => "CREATE", + Operation::Update => "UPDATE", + Operation::Delete => "DELETE", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "UNSET" => Some(Self::Unset), + "CREATE" => Some(Self::Create), + "UPDATE" => Some(Self::Update), + "DELETE" => Some(Self::Delete), + _ => None, + } + } + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockRange { + #[prost(uint64, tag="2")] + pub start_block: u64, + #[prost(uint64, tag="3")] + pub end_block: u64, +} +// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-ekubo/src/pb/sf.substreams.rs b/substreams/ethereum-ekubo/src/pb/sf.substreams.rs new file mode 100644 index 000000000..ffc5f78da --- /dev/null +++ b/substreams/ethereum-ekubo/src/pb/sf.substreams.rs @@ -0,0 +1,14 @@ +// @generated +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct FieldOptions { + /// this option informs the `substreams pack` command that it should treat the corresponding manifest value as a path to a file, putting its content as bytes in this field. + /// must be applied to a `bytes` or `string` field + #[prost(bool, tag="1")] + pub load_from_file: bool, + /// this option informs the `substreams pack` command that it should treat the corresponding manifest value as a path to a folder, zipping its content and putting the zip content as bytes in this field. + /// must be applied to a `bytes` field + #[prost(bool, tag="2")] + pub zip_from_folder: bool, +} +// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-ekubo/src/pb/sf.substreams.sink.service.v1.rs b/substreams/ethereum-ekubo/src/pb/sf.substreams.sink.service.v1.rs new file mode 100644 index 000000000..d1c643dd2 --- /dev/null +++ b/substreams/ethereum-ekubo/src/pb/sf.substreams.sink.service.v1.rs @@ -0,0 +1,227 @@ +// @generated +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DeployRequest { + #[prost(message, optional, tag="1")] + pub substreams_package: ::core::option::Option, + #[prost(bool, tag="2")] + pub development_mode: bool, + #[prost(message, repeated, tag="3")] + pub parameters: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Parameter { + #[prost(string, tag="1")] + pub key: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub value: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DeployResponse { + #[prost(enumeration="DeploymentStatus", tag="1")] + pub status: i32, + /// deployment_id is a short name (max 8 characters) that uniquely identifies your deployment + #[prost(string, tag="2")] + pub deployment_id: ::prost::alloc::string::String, + #[prost(map="string, string", tag="3")] + pub services: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, + #[prost(string, tag="4")] + pub reason: ::prost::alloc::string::String, + #[prost(string, tag="5")] + pub motd: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UpdateRequest { + #[prost(message, optional, tag="1")] + pub substreams_package: ::core::option::Option, + #[prost(string, tag="2")] + pub deployment_id: ::prost::alloc::string::String, + #[prost(bool, tag="3")] + pub reset: bool, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UpdateResponse { + #[prost(enumeration="DeploymentStatus", tag="1")] + pub status: i32, + #[prost(map="string, string", tag="2")] + pub services: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, + #[prost(string, tag="3")] + pub reason: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub motd: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct InfoRequest { + #[prost(string, tag="1")] + pub deployment_id: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct InfoResponse { + #[prost(enumeration="DeploymentStatus", tag="1")] + pub status: i32, + #[prost(map="string, string", tag="2")] + pub services: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, + #[prost(string, tag="3")] + pub reason: ::prost::alloc::string::String, + #[prost(message, optional, tag="4")] + pub package_info: ::core::option::Option, + #[prost(message, optional, tag="5")] + pub progress: ::core::option::Option, + #[prost(string, tag="6")] + pub motd: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SinkProgress { + #[prost(uint64, tag="1")] + pub last_processed_block: u64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PackageInfo { + #[prost(string, tag="1")] + pub name: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub version: ::prost::alloc::string::String, + #[prost(string, tag="3")] + pub output_module_name: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub output_module_hash: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListRequest { +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListResponse { + #[prost(message, repeated, tag="1")] + pub deployments: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DeploymentWithStatus { + #[prost(string, tag="1")] + pub id: ::prost::alloc::string::String, + #[prost(enumeration="DeploymentStatus", tag="2")] + pub status: i32, + #[prost(string, tag="3")] + pub reason: ::prost::alloc::string::String, + #[prost(message, optional, tag="4")] + pub package_info: ::core::option::Option, + #[prost(message, optional, tag="5")] + pub progress: ::core::option::Option, + #[prost(string, tag="6")] + pub motd: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RemoveRequest { + #[prost(string, tag="1")] + pub deployment_id: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RemoveResponse { + #[prost(enumeration="DeploymentStatus", tag="1")] + pub previous_status: i32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PauseRequest { + #[prost(string, tag="1")] + pub deployment_id: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PauseResponse { + #[prost(enumeration="DeploymentStatus", tag="1")] + pub previous_status: i32, + #[prost(enumeration="DeploymentStatus", tag="2")] + pub new_status: i32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StopRequest { + #[prost(string, tag="1")] + pub deployment_id: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StopResponse { + #[prost(enumeration="DeploymentStatus", tag="1")] + pub previous_status: i32, + #[prost(enumeration="DeploymentStatus", tag="2")] + pub new_status: i32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResumeRequest { + #[prost(string, tag="1")] + pub deployment_id: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResumeResponse { + #[prost(enumeration="DeploymentStatus", tag="1")] + pub previous_status: i32, + #[prost(enumeration="DeploymentStatus", tag="2")] + pub new_status: i32, +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum DeploymentStatus { + Unknown = 0, + Running = 1, + Failing = 2, + Paused = 3, + Stopped = 4, + Starting = 5, + Pausing = 6, + Stopping = 7, + Removing = 8, + Resuming = 9, +} +impl DeploymentStatus { + /// 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 { + DeploymentStatus::Unknown => "UNKNOWN", + DeploymentStatus::Running => "RUNNING", + DeploymentStatus::Failing => "FAILING", + DeploymentStatus::Paused => "PAUSED", + DeploymentStatus::Stopped => "STOPPED", + DeploymentStatus::Starting => "STARTING", + DeploymentStatus::Pausing => "PAUSING", + DeploymentStatus::Stopping => "STOPPING", + DeploymentStatus::Removing => "REMOVING", + DeploymentStatus::Resuming => "RESUMING", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "UNKNOWN" => Some(Self::Unknown), + "RUNNING" => Some(Self::Running), + "FAILING" => Some(Self::Failing), + "PAUSED" => Some(Self::Paused), + "STOPPED" => Some(Self::Stopped), + "STARTING" => Some(Self::Starting), + "PAUSING" => Some(Self::Pausing), + "STOPPING" => Some(Self::Stopping), + "REMOVING" => Some(Self::Removing), + "RESUMING" => Some(Self::Resuming), + _ => None, + } + } +} +// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-ekubo/src/pb/sf.substreams.v1.rs b/substreams/ethereum-ekubo/src/pb/sf.substreams.v1.rs new file mode 100644 index 000000000..dc86dac23 --- /dev/null +++ b/substreams/ethereum-ekubo/src/pb/sf.substreams.v1.rs @@ -0,0 +1,324 @@ +// @generated +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Modules { + #[prost(message, repeated, tag="1")] + pub modules: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="2")] + pub binaries: ::prost::alloc::vec::Vec, +} +/// Binary represents some code compiled to its binary form. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Binary { + #[prost(string, tag="1")] + pub r#type: ::prost::alloc::string::String, + #[prost(bytes="vec", tag="2")] + pub content: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Module { + #[prost(string, tag="1")] + pub name: ::prost::alloc::string::String, + #[prost(uint32, tag="4")] + pub binary_index: u32, + #[prost(string, tag="5")] + pub binary_entrypoint: ::prost::alloc::string::String, + #[prost(message, repeated, tag="6")] + pub inputs: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag="7")] + pub output: ::core::option::Option, + #[prost(uint64, tag="8")] + pub initial_block: u64, + #[prost(message, optional, tag="9")] + pub block_filter: ::core::option::Option, + #[prost(oneof="module::Kind", tags="2, 3, 10")] + pub kind: ::core::option::Option, +} +/// Nested message and enum types in `Module`. +pub mod module { + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct BlockFilter { + #[prost(string, tag="1")] + pub module: ::prost::alloc::string::String, + #[prost(oneof="block_filter::Query", tags="2, 3")] + pub query: ::core::option::Option, + } + /// Nested message and enum types in `BlockFilter`. + pub mod block_filter { + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Query { + #[prost(string, tag="2")] + QueryString(::prost::alloc::string::String), + /// QueryFromStore query_from_store_keys = 3; + #[prost(message, tag="3")] + QueryFromParams(super::QueryFromParams), + } + } + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct QueryFromParams { + } + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct KindMap { + #[prost(string, tag="1")] + pub output_type: ::prost::alloc::string::String, + } + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct KindStore { + /// The `update_policy` determines the functions available to mutate the store + /// (like `set()`, `set_if_not_exists()` or `sum()`, etc..) in + /// order to ensure that parallel operations are possible and deterministic + /// + /// Say a store cumulates keys from block 0 to 1M, and a second store + /// cumulates keys from block 1M to 2M. When we want to use this + /// store as a dependency for a downstream module, we will merge the + /// two stores according to this policy. + #[prost(enumeration="kind_store::UpdatePolicy", tag="1")] + pub update_policy: i32, + #[prost(string, tag="2")] + pub value_type: ::prost::alloc::string::String, + } + /// Nested message and enum types in `KindStore`. + pub mod kind_store { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] + #[repr(i32)] + pub enum UpdatePolicy { + Unset = 0, + /// Provides a store where you can `set()` keys, and the latest key wins + Set = 1, + /// Provides a store where you can `set_if_not_exists()` keys, and the first key wins + SetIfNotExists = 2, + /// Provides a store where you can `add_*()` keys, where two stores merge by summing its values. + Add = 3, + /// Provides a store where you can `min_*()` keys, where two stores merge by leaving the minimum value. + Min = 4, + /// Provides a store where you can `max_*()` keys, where two stores merge by leaving the maximum value. + Max = 5, + /// Provides a store where you can `append()` keys, where two stores merge by concatenating the bytes in order. + Append = 6, + /// Provides a store with both `set()` and `sum()` functions. + SetSum = 7, + } + impl UpdatePolicy { + /// 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 { + UpdatePolicy::Unset => "UPDATE_POLICY_UNSET", + UpdatePolicy::Set => "UPDATE_POLICY_SET", + UpdatePolicy::SetIfNotExists => "UPDATE_POLICY_SET_IF_NOT_EXISTS", + UpdatePolicy::Add => "UPDATE_POLICY_ADD", + UpdatePolicy::Min => "UPDATE_POLICY_MIN", + UpdatePolicy::Max => "UPDATE_POLICY_MAX", + UpdatePolicy::Append => "UPDATE_POLICY_APPEND", + UpdatePolicy::SetSum => "UPDATE_POLICY_SET_SUM", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "UPDATE_POLICY_UNSET" => Some(Self::Unset), + "UPDATE_POLICY_SET" => Some(Self::Set), + "UPDATE_POLICY_SET_IF_NOT_EXISTS" => Some(Self::SetIfNotExists), + "UPDATE_POLICY_ADD" => Some(Self::Add), + "UPDATE_POLICY_MIN" => Some(Self::Min), + "UPDATE_POLICY_MAX" => Some(Self::Max), + "UPDATE_POLICY_APPEND" => Some(Self::Append), + "UPDATE_POLICY_SET_SUM" => Some(Self::SetSum), + _ => None, + } + } + } + } + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct KindBlockIndex { + #[prost(string, tag="1")] + pub output_type: ::prost::alloc::string::String, + } + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct Input { + #[prost(oneof="input::Input", tags="1, 2, 3, 4")] + pub input: ::core::option::Option, + } + /// Nested message and enum types in `Input`. + pub mod input { + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct Source { + /// ex: "sf.ethereum.type.v1.Block" + #[prost(string, tag="1")] + pub r#type: ::prost::alloc::string::String, + } + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct Map { + /// ex: "block_to_pairs" + #[prost(string, tag="1")] + pub module_name: ::prost::alloc::string::String, + } + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct Store { + #[prost(string, tag="1")] + pub module_name: ::prost::alloc::string::String, + #[prost(enumeration="store::Mode", tag="2")] + pub mode: i32, + } + /// Nested message and enum types in `Store`. + pub mod store { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] + #[repr(i32)] + pub enum Mode { + Unset = 0, + Get = 1, + Deltas = 2, + } + impl Mode { + /// 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 { + Mode::Unset => "UNSET", + Mode::Get => "GET", + Mode::Deltas => "DELTAS", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "UNSET" => Some(Self::Unset), + "GET" => Some(Self::Get), + "DELTAS" => Some(Self::Deltas), + _ => None, + } + } + } + } + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct Params { + #[prost(string, tag="1")] + pub value: ::prost::alloc::string::String, + } + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Input { + #[prost(message, tag="1")] + Source(Source), + #[prost(message, tag="2")] + Map(Map), + #[prost(message, tag="3")] + Store(Store), + #[prost(message, tag="4")] + Params(Params), + } + } + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct Output { + #[prost(string, tag="1")] + pub r#type: ::prost::alloc::string::String, + } + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Kind { + #[prost(message, tag="2")] + KindMap(KindMap), + #[prost(message, tag="3")] + KindStore(KindStore), + #[prost(message, tag="10")] + KindBlockIndex(KindBlockIndex), + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Package { + /// Needs to be one so this file can be used _directly_ as a + /// buf `Image` andor a ProtoSet for grpcurl and other tools + #[prost(message, repeated, tag="1")] + pub proto_files: ::prost::alloc::vec::Vec<::prost_types::FileDescriptorProto>, + #[prost(uint64, tag="5")] + pub version: u64, + #[prost(message, optional, tag="6")] + pub modules: ::core::option::Option, + #[prost(message, repeated, tag="7")] + pub module_meta: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="8")] + pub package_meta: ::prost::alloc::vec::Vec, + /// Source network for Substreams to fetch its data from. + #[prost(string, tag="9")] + pub network: ::prost::alloc::string::String, + #[prost(message, optional, tag="10")] + pub sink_config: ::core::option::Option<::prost_types::Any>, + #[prost(string, tag="11")] + pub sink_module: ::prost::alloc::string::String, + /// image is the bytes to a JPEG, WebP or PNG file. Max size is 2 MiB + #[prost(bytes="vec", tag="12")] + pub image: ::prost::alloc::vec::Vec, + #[prost(map="string, message", tag="13")] + pub networks: ::std::collections::HashMap<::prost::alloc::string::String, NetworkParams>, + #[prost(map="string, string", tag="14")] + pub block_filters: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct NetworkParams { + #[prost(map="string, uint64", tag="1")] + pub initial_blocks: ::std::collections::HashMap<::prost::alloc::string::String, u64>, + #[prost(map="string, string", tag="2")] + pub params: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PackageMetadata { + #[prost(string, tag="1")] + pub version: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub url: ::prost::alloc::string::String, + #[prost(string, tag="3")] + pub name: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub doc: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ModuleMetadata { + /// Corresponds to the index in `Package.metadata.package_meta` + #[prost(uint64, tag="1")] + pub package_index: u64, + #[prost(string, tag="2")] + pub doc: ::prost::alloc::string::String, +} +/// Clock is a pointer to a block with added timestamp +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Clock { + #[prost(string, tag="1")] + pub id: ::prost::alloc::string::String, + #[prost(uint64, tag="2")] + pub number: u64, + #[prost(message, optional, tag="3")] + pub timestamp: ::core::option::Option<::prost_types::Timestamp>, +} +/// BlockRef is a pointer to a block to which we don't know the timestamp +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockRef { + #[prost(string, tag="1")] + pub id: ::prost::alloc::string::String, + #[prost(uint64, tag="2")] + pub number: u64, +} +// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-ekubo/src/pb/tycho.evm.v1.rs b/substreams/ethereum-ekubo/src/pb/tycho.evm.v1.rs new file mode 100644 index 000000000..6365bd489 --- /dev/null +++ b/substreams/ethereum-ekubo/src/pb/tycho.evm.v1.rs @@ -0,0 +1,382 @@ +// @generated +// This file contains the proto definitions for Substreams common to all integrations. + +/// A struct describing a block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Block { + /// The blocks hash. + #[prost(bytes="vec", tag="1")] + pub hash: ::prost::alloc::vec::Vec, + /// The parent blocks hash. + #[prost(bytes="vec", tag="2")] + pub parent_hash: ::prost::alloc::vec::Vec, + /// The block number. + #[prost(uint64, tag="3")] + pub number: u64, + /// The block timestamp. + #[prost(uint64, tag="4")] + pub ts: u64, +} +/// 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. + /// TODO: should this be uint32? to match the type from the native substream type? + #[prost(uint64, tag="4")] + pub index: u64, +} +/// A custom struct representing an arbitrary attribute of a protocol component. +/// This is mainly used by the native integration to track the necessary information about the protocol. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Attribute { + /// The name of the attribute. + #[prost(string, tag="1")] + pub name: ::prost::alloc::string::String, + /// The value of the attribute. + #[prost(bytes="vec", tag="2")] + pub value: ::prost::alloc::vec::Vec, + /// The type of change the attribute underwent. + #[prost(enumeration="ChangeType", tag="3")] + pub change: i32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtocolType { + #[prost(string, tag="1")] + pub name: ::prost::alloc::string::String, + #[prost(enumeration="FinancialType", tag="2")] + pub financial_type: i32, + #[prost(message, repeated, tag="3")] + pub attribute_schema: ::prost::alloc::vec::Vec, + #[prost(enumeration="ImplementationType", tag="4")] + pub implementation_type: i32, +} +/// A struct describing a part of the protocol. +/// Note: For example this can be a UniswapV2 pair, that tracks the two ERC20 tokens used by the pair, +/// the component would represent a single contract. In case of VM integration, such component would +/// not need any attributes, because all the relevant info would be tracked via storage slots and balance changes. +/// It can also be a wrapping contract, like WETH, that has a constant price, but it allows swapping tokens. +/// This is why the name ProtocolComponent is used instead of "Pool" or "Pair". +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtocolComponent { + /// A unique identifier for the component within the protocol. + /// Can be e.g. a stringified address or a string describing the trading pair. + #[prost(string, tag="1")] + pub id: ::prost::alloc::string::String, + /// Addresses of the ERC20 tokens used by the component. + #[prost(bytes="vec", repeated, tag="2")] + pub tokens: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + /// Addresses of the contracts used by the component. + /// Usually it is a single contract, but some protocols use multiple contracts. + #[prost(bytes="vec", repeated, tag="3")] + pub contracts: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + /// Static attributes of the component. + /// These attributes MUST be immutable. If it can ever change, it should be given as an EntityChanges for this component id. + /// The inner ChangeType of the attribute has to match the ChangeType of the ProtocolComponent. + #[prost(message, repeated, tag="4")] + pub static_att: ::prost::alloc::vec::Vec, + /// Type of change the component underwent. + #[prost(enumeration="ChangeType", tag="5")] + pub change: i32, + /// / Represents the functionality of the component. + #[prost(message, optional, tag="6")] + pub protocol_type: ::core::option::Option, +} +/// A struct for following the changes of Total Value Locked (TVL) of a protocol component. +/// Note that if a ProtocolComponent contains multiple contracts, the TVL is tracked for the component as a whole. +/// E.g. for UniswapV2 pair WETH/USDC, this tracks the USDC and WETH balance of the pair contract. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BalanceChange { + /// The address of the ERC20 token whose balance changed. + #[prost(bytes="vec", tag="1")] + pub token: ::prost::alloc::vec::Vec, + /// The new balance of the token. Note: it must be a big endian encoded int. + #[prost(bytes="vec", tag="2")] + pub balance: ::prost::alloc::vec::Vec, + /// The id of the component whose TVL is tracked. Note: This MUST be utf8 encoded. + /// If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. + #[prost(bytes="vec", tag="3")] + pub component_id: ::prost::alloc::vec::Vec, +} +// Native entities + +/// A component is a set of attributes that are associated with a custom entity. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EntityChanges { + /// A unique identifier of the entity within the protocol. + #[prost(string, tag="1")] + pub component_id: ::prost::alloc::string::String, + /// The set of attributes that are associated with the entity. + #[prost(message, repeated, tag="2")] + pub attributes: ::prost::alloc::vec::Vec, +} +// VM entities + +/// A key value entry into contract storage. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ContractSlot { + /// A contract's storage slot. + #[prost(bytes="vec", tag="2")] + pub slot: ::prost::alloc::vec::Vec, + /// The new value for this storage slot. + #[prost(bytes="vec", tag="3")] + pub value: ::prost::alloc::vec::Vec, +} +/// A struct for following the token balance changes for a contract. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AccountBalanceChange { + /// The address of the ERC20 token whose balance changed. + #[prost(bytes="vec", tag="1")] + pub token: ::prost::alloc::vec::Vec, + /// The new balance of the token. Note: it must be a big endian encoded int. + #[prost(bytes="vec", tag="2")] + pub balance: ::prost::alloc::vec::Vec, +} +/// Changes made to a single contract's state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ContractChange { + /// The contract's address + #[prost(bytes="vec", tag="1")] + pub address: ::prost::alloc::vec::Vec, + /// The new balance of the contract, empty bytes indicates no change. + #[prost(bytes="vec", tag="2")] + pub balance: ::prost::alloc::vec::Vec, + /// The new code of the contract, empty bytes indicates no change. + #[prost(bytes="vec", tag="3")] + pub code: ::prost::alloc::vec::Vec, + /// The changes to this contract's slots, empty sequence indicates no change. + #[prost(message, repeated, tag="4")] + pub slots: ::prost::alloc::vec::Vec, + /// Whether this is an update, a creation or a deletion. + #[prost(enumeration="ChangeType", tag="5")] + pub change: i32, + /// The new ERC20 balances of the contract. + #[prost(message, repeated, tag="6")] + pub token_balances: ::prost::alloc::vec::Vec, +} +// Aggregate entities + +/// A set of changes aggregated by transaction. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransactionChanges { + /// The transaction instance that results in the changes. + #[prost(message, optional, tag="1")] + pub tx: ::core::option::Option, + /// Contains the changes induced by the above transaction, aggregated on a per-contract basis. + /// Contains the contract changes induced by the above transaction, usually for tracking VM components. + #[prost(message, repeated, tag="2")] + pub contract_changes: ::prost::alloc::vec::Vec, + /// Contains the entity changes induced by the above transaction. + /// Usually for tracking native components or used for VM extensions (plugins). + #[prost(message, repeated, tag="3")] + pub entity_changes: ::prost::alloc::vec::Vec, + /// An array of newly added components. + #[prost(message, repeated, tag="4")] + pub component_changes: ::prost::alloc::vec::Vec, + /// An array of balance changes to components. + #[prost(message, repeated, tag="5")] + pub balance_changes: ::prost::alloc::vec::Vec, +} +/// A set of transaction changes within a single block. +/// This message must be the output of your substreams module. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockChanges { + /// The block for which these changes are collectively computed. + #[prost(message, optional, tag="1")] + pub block: ::core::option::Option, + /// The set of transaction changes observed in the specified block. + #[prost(message, repeated, tag="2")] + pub changes: ::prost::alloc::vec::Vec, +} +/// Enum to specify the type of a change. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum ChangeType { + Unspecified = 0, + Update = 1, + Creation = 2, + Deletion = 3, +} +impl ChangeType { + /// 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 { + ChangeType::Unspecified => "CHANGE_TYPE_UNSPECIFIED", + ChangeType::Update => "CHANGE_TYPE_UPDATE", + ChangeType::Creation => "CHANGE_TYPE_CREATION", + ChangeType::Deletion => "CHANGE_TYPE_DELETION", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "CHANGE_TYPE_UNSPECIFIED" => Some(Self::Unspecified), + "CHANGE_TYPE_UPDATE" => Some(Self::Update), + "CHANGE_TYPE_CREATION" => Some(Self::Creation), + "CHANGE_TYPE_DELETION" => Some(Self::Deletion), + _ => None, + } + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum FinancialType { + Swap = 0, + Lend = 1, + Leverage = 2, + Psm = 3, +} +impl FinancialType { + /// 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 { + FinancialType::Swap => "SWAP", + FinancialType::Lend => "LEND", + FinancialType::Leverage => "LEVERAGE", + FinancialType::Psm => "PSM", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "SWAP" => Some(Self::Swap), + "LEND" => Some(Self::Lend), + "LEVERAGE" => Some(Self::Leverage), + "PSM" => Some(Self::Psm), + _ => None, + } + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum ImplementationType { + Vm = 0, + Custom = 1, +} +impl ImplementationType { + /// 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 { + ImplementationType::Vm => "VM", + ImplementationType::Custom => "CUSTOM", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "VM" => Some(Self::Vm), + "CUSTOM" => Some(Self::Custom), + _ => None, + } + } +} +// WARNING: DEPRECATED. Please use common.proto's TransactionChanges and BlockChanges instead. +// This file contains proto definitions specific to the VM integration. + +/// A set of changes aggregated by transaction. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransactionContractChanges { + /// The transaction instance that results in the changes. + #[prost(message, optional, tag="1")] + pub tx: ::core::option::Option, + /// Contains the changes induced by the above transaction, aggregated on a per-contract basis. + #[prost(message, repeated, tag="2")] + pub contract_changes: ::prost::alloc::vec::Vec, + /// An array of newly added components. + #[prost(message, repeated, tag="3")] + pub component_changes: ::prost::alloc::vec::Vec, + /// An array of balance changes to components. + #[prost(message, repeated, tag="4")] + pub balance_changes: ::prost::alloc::vec::Vec, +} +/// A set of transaction changes within a single block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockContractChanges { + /// The block for which these changes are collectively computed. + #[prost(message, optional, tag="1")] + pub block: ::core::option::Option, + /// The set of transaction changes observed in the specified block. + #[prost(message, repeated, tag="2")] + pub changes: ::prost::alloc::vec::Vec, +} +/// A message containing relative balance changes. +/// +/// Used to track token balances of protocol components in case they are only +/// available as relative values within a block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BalanceDelta { + /// The ordinal of the balance change. Must be unique & deterministic over all balances + /// changes within a block. + #[prost(uint64, tag="1")] + pub ord: u64, + /// The tx hash of the transaction that caused the balance change. + #[prost(message, optional, tag="2")] + pub tx: ::core::option::Option, + /// The address of the ERC20 token whose balance changed. + #[prost(bytes="vec", tag="3")] + pub token: ::prost::alloc::vec::Vec, + /// The delta balance of the token. + #[prost(bytes="vec", tag="4")] + pub delta: ::prost::alloc::vec::Vec, + /// The id of the component whose TVL is tracked. + /// If the protocol component includes multiple contracts, the balance change must be + /// aggregated to reflect how much tokens can be traded. + #[prost(bytes="vec", tag="5")] + pub component_id: ::prost::alloc::vec::Vec, +} +/// A set of balances deltas, usually a group of changes within a single block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockBalanceDeltas { + #[prost(message, repeated, tag="1")] + pub balance_deltas: ::prost::alloc::vec::Vec, +} +/// A message containing protocol components that were created by a single tx. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransactionProtocolComponents { + #[prost(message, optional, tag="1")] + pub tx: ::core::option::Option, + #[prost(message, repeated, tag="2")] + pub components: ::prost::alloc::vec::Vec, +} +/// All protocol components that were created within a block with their corresponding tx. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockTransactionProtocolComponents { + #[prost(message, repeated, tag="1")] + pub tx_components: ::prost::alloc::vec::Vec, +} +// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-ekubo/src/pool_factories.rs b/substreams/ethereum-ekubo/src/pool_factories.rs new file mode 100644 index 000000000..07426eceb --- /dev/null +++ b/substreams/ethereum-ekubo/src/pool_factories.rs @@ -0,0 +1,105 @@ +use serde::Deserialize; +use substreams_ethereum::Event; +use substreams_ethereum::pb::eth::v2::{Call, Log, TransactionTrace}; +use tiny_keccak::{Hasher, Keccak}; +use tycho_substreams::models::{ChangeType, FinancialType, ImplementationType, ProtocolComponent, ProtocolType}; +use tycho_substreams::prelude::Attribute; + +#[derive(Deserialize)] +pub struct DeploymentConfig { + #[serde(with = "hex::serde")] + pub core: Vec, + #[serde(with = "hex::serde")] + pub oracle: Vec, +} + +/// Potentially constructs a new ProtocolComponent given a call +/// +/// This method is given each individual call within a transaction, the corresponding +/// logs emitted during that call as well as the full transaction trace. +/// +/// If this call creates a component in your protocol please contstruct and return it +/// here. Otherwise, simply return None. +pub fn maybe_create_component( + call: &Call, + log: &Log, + _tx: &TransactionTrace, + config: &DeploymentConfig, +) -> Option { + if call.address == config.core { + if let Some(pi) = crate::abi::core::events::PoolInitialized::match_and_decode(log) { + let pool_id = hash_pool_key(&pi.pool_key); + + return Some(ProtocolComponent { + id: pool_id, + tokens: vec![pi.pool_key.0.clone(), pi.pool_key.1.clone()], + contracts: if config.oracle == pi.pool_key.4 { + vec![ + config.oracle.clone(), + config.core.clone(), + ] + } else { + vec![config.core.clone()] + }, + change: ChangeType::Creation.into(), + protocol_type: Some(ProtocolType { + name: "EKUBO".to_string(), + financial_type: FinancialType::Swap.into(), + implementation_type: ImplementationType::Vm.into(), + attribute_schema: vec![], + }), + static_att: vec![ + Attribute { + change: ChangeType::Creation.into(), + name: "token0".to_string(), + value: pi.pool_key.0, + }, + Attribute { + change: ChangeType::Creation.into(), + name: "token1".to_string(), + value: pi.pool_key.1, + }, + Attribute { + change: ChangeType::Creation.into(), + name: "fee".to_string(), + value: pi.pool_key.2.to_bytes_be().1, + }, + Attribute { + change: ChangeType::Creation.into(), + name: "tick_spacing".to_string(), + value: pi.pool_key.3.to_bytes_be().1, + }, + Attribute { + change: ChangeType::Creation.into(), + name: "extension".to_string(), + value: pi.pool_key.4, + }, + ], + }); + } + }; + + None +} + + +pub type PoolKey = ( + Vec, + Vec, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, +); + +pub fn hash_pool_key(pool_key: &PoolKey) -> String { + let mut hasher = Keccak::v256(); + hasher.update(pool_key.0.as_slice()); + hasher.update(pool_key.1.as_slice()); + hasher.update(pool_key.2.to_signed_bytes_be().as_slice()); + hasher.update(pool_key.3.to_signed_bytes_be().as_slice()); + hasher.update(pool_key.4.as_slice()); + + let mut output = [0u8; 32]; + hasher.finalize(&mut output); + hex::encode(output) +} \ No newline at end of file diff --git a/substreams/ethereum-ekubo/substreams.yaml b/substreams/ethereum-ekubo/substreams.yaml new file mode 100644 index 000000000..871b23ccb --- /dev/null +++ b/substreams/ethereum-ekubo/substreams.yaml @@ -0,0 +1,75 @@ +specVersion: v0.1.0 +package: + name: "ethereum_ekubo" + version: v0.1.0 + +protobuf: + files: + - tycho/evm/v1/vm.proto + - tycho/evm/v1/common.proto + - tycho/evm/v1/utils.proto + importPaths: + - ../../proto + +binaries: + default: + type: wasm/rust-v1 + file: ../target/wasm32-unknown-unknown/release/ethereum_ekubo.wasm + +network: mainnet +networks: + mainnet: + initialBlock: + map_protocol_components: 21739334 + store_protocol_components: 21739334 + map_relative_component_balance: 21739334 + store_balances: 21739334 + map_protocol_changes: 21739334 + params: + map_protocol_components: "core=39d8ab62fcaa5b466eb8397187732b6ba455aaa8&oracle=51ee1902db6d5640163506b9e178a21ff027282c" + map_relative_component_balance: "core=39d8ab62fcaa5b466eb8397187732b6ba455aaa8&oracle=51ee1902db6d5640163506b9e178a21ff027282c" + map_protocol_changes: "core=39d8ab62fcaa5b466eb8397187732b6ba455aaa8&oracle=51ee1902db6d5640163506b9e178a21ff027282c" + +modules: + - name: map_protocol_components + kind: map + inputs: + - params: string + - source: sf.ethereum.type.v2.Block + output: + type: proto:tycho.evm.v1.BlockTransactionProtocolComponents + + - name: store_protocol_components + kind: store + updatePolicy: set + valueType: string + inputs: + - map: map_protocol_components + + - name: map_relative_component_balance + kind: map + inputs: + - params: string + - source: sf.ethereum.type.v2.Block + - store: store_protocol_components + output: + type: proto:tycho.evm.v1.BlockBalanceDeltas + + - name: store_component_balances + kind: store + updatePolicy: add + valueType: bigint + inputs: + - map: map_relative_component_balance + + - name: map_protocol_changes + kind: map + inputs: + - params: string + - source: sf.ethereum.type.v2.Block + - map: map_protocol_components + - map: map_relative_component_balance + - store: store_component_balances + mode: deltas + output: + type: proto:tycho.evm.v1.BlockChanges From 42b6f8cc6972df1737dfac1231c0ad235ad44dab Mon Sep 17 00:00:00 2001 From: kayibal Date: Sat, 1 Feb 2025 19:38:04 -0300 Subject: [PATCH 5/8] fix: Remove unnecessary store --- substreams/ethereum-ekubo/src/modules.rs | 70 ++++------------------- substreams/ethereum-ekubo/substreams.yaml | 9 --- 2 files changed, 10 insertions(+), 69 deletions(-) diff --git a/substreams/ethereum-ekubo/src/modules.rs b/substreams/ethereum-ekubo/src/modules.rs index f798d26a3..2e8390ec0 100644 --- a/substreams/ethereum-ekubo/src/modules.rs +++ b/substreams/ethereum-ekubo/src/modules.rs @@ -51,36 +51,11 @@ fn map_protocol_components( }) } -#[substreams::handlers::store] -fn store_protocol_components(map_protocol_components: BlockTransactionProtocolComponents, store: StoreSetRaw) { - map_protocol_components.tx_components - .into_iter() - .for_each(|tx_pc| { - tx_pc - .components - .into_iter() - .for_each(|pc| { - let tokens = serde_sibor::to_bytes(&pc.tokens).expect("Sibor encoding protocol component tokens failed"); - store.set(0, &pc.id, &tokens); - }) - }); -} - /// Extracts balance changes per component /// -/// This template function inspects ERC20 transfer events to/from the singleton contract -/// to extract balance changes. If a transfer to the component is detected, it's -/// balanced is increased and if a balance from the component is detected its balance -/// is decreased. -/// -/// ## Note: -/// Changes are necessary if your protocol uses native ETH or your component burns or -/// mints tokens without emitting transfer events. -/// -/// You may want to ignore LP tokens if your protocol emits transfer events for these -/// here. +/// Indexes balance changes according to Ekubo core events. #[substreams::handlers::map] -fn map_relative_component_balance(params: String, block: eth::v2::Block, store: StoreGetRaw) -> Result { +fn map_relative_component_balance(params: String, block: eth::v2::Block) -> Result { let config: DeploymentConfig = serde_qs::from_str(params.as_str())?; let res = block .transactions() @@ -92,92 +67,74 @@ fn map_relative_component_balance(params: String, block: eth::v2::Block, store: } if let Some(ev) = core_events::PositionUpdated::match_and_decode(log) { let pool_id = hash_pool_key(&ev.pool_key); - // TODO better error handling - let pool_tokens: Vec> = serde_sibor::from_bytes( - &store.get_last(&pool_id).expect("Missing protocol component") - ).expect("Decoding component tokens failed"); vec![ BalanceDelta { ord: log.ordinal, tx: Some(tx.into()), - token: pool_tokens[0].clone(), + token: ev.pool_key.0.clone(), delta: ev.delta0.to_signed_bytes_be(), component_id: pool_id.clone().into(), }, BalanceDelta { ord: log.ordinal, tx: Some(tx.into()), - token: pool_tokens[1].clone(), + token: ev.pool_key.1.clone(), delta: ev.delta1.to_signed_bytes_be(), component_id: pool_id.into(), } ] } else if let Some(ev) = core_events::PositionFeesCollected::match_and_decode(log) { let pool_id = hash_pool_key(&ev.pool_key); - // TODO better error handling - let pool_tokens: Vec> = serde_sibor::from_bytes( - &store.get_last(&pool_id).expect("Missing protocol component") - ).expect("Decoding component tokens failed"); vec![ BalanceDelta { ord: log.ordinal, tx: Some(tx.into()), - token: pool_tokens[0].clone(), + token: ev.pool_key.0.clone(), delta: ev.amount0.neg().to_signed_bytes_be(), component_id: pool_id.clone().into(), }, BalanceDelta { ord: log.ordinal, tx: Some(tx.into()), - token: pool_tokens[1].clone(), + token: ev.pool_key.1.clone(), delta: ev.amount1.neg().to_signed_bytes_be(), component_id: pool_id.into(), } ] } else if let Some(ev) = core_events::Swapped::match_and_decode(log) { let pool_id = hash_pool_key(&ev.pool_key); - // TODO better error handling - let pool_tokens: Vec> = serde_sibor::from_bytes( - &store.get_last(&pool_id).expect("Missing protocol component") - ).expect("Decoding component tokens failed"); - vec![ BalanceDelta { ord: log.ordinal, tx: Some(tx.into()), - token: pool_tokens[0].clone(), + token: ev.pool_key.0.clone(), delta: ev.delta0.to_signed_bytes_be(), component_id: pool_id.clone().into(), }, BalanceDelta { ord: log.ordinal, tx: Some(tx.into()), - token: pool_tokens[1].clone(), + token: ev.pool_key.1.clone(), delta: ev.delta1.to_signed_bytes_be(), component_id: pool_id.into(), } ] } else if let Some(ev) = core_events::FeesAccumulated::match_and_decode(log) { let pool_id = hash_pool_key(&ev.pool_key); - // TODO better error handling - let pool_tokens: Vec> = serde_sibor::from_bytes( - &store.get_last(&pool_id).expect("Missing protocol component") - ).expect("Decoding component tokens failed"); - vec![ BalanceDelta { ord: log.ordinal, tx: Some(tx.into()), - token: pool_tokens[0].clone(), + token: ev.pool_key.0.clone(), delta: ev.amount0.to_signed_bytes_be(), component_id: pool_id.clone().into(), }, BalanceDelta { ord: log.ordinal, tx: Some(tx.into()), - token: pool_tokens[1].clone(), + token: ev.pool_key.1.clone(), delta: ev.amount1.to_signed_bytes_be(), component_id: pool_id.into(), } @@ -197,9 +154,6 @@ fn map_relative_component_balance(params: String, block: eth::v2::Block, store: /// /// Aggregate the relative balances in an additive store since tycho-indexer expects /// absolute balance inputs. -/// -/// ## Note: -/// This method should usually not require any changes. #[substreams::handlers::store] pub fn store_component_balances(deltas: BlockBalanceDeltas, store: StoreAddBigInt) { tycho_substreams::balances::store_balance_changes(deltas, store); @@ -209,10 +163,6 @@ pub fn store_component_balances(deltas: BlockBalanceDeltas, store: StoreAddBigIn /// /// This is the main method that will aggregate all changes as well as extract all /// relevant contract storage deltas. -/// -/// ## Note: -/// You may have to change this method if your components have any default dynamic -/// attributes, or if you need any additional static contracts indexed. #[substreams::handlers::map] fn map_protocol_changes( params: String, diff --git a/substreams/ethereum-ekubo/substreams.yaml b/substreams/ethereum-ekubo/substreams.yaml index 871b23ccb..116f992ae 100644 --- a/substreams/ethereum-ekubo/substreams.yaml +++ b/substreams/ethereum-ekubo/substreams.yaml @@ -21,7 +21,6 @@ networks: mainnet: initialBlock: map_protocol_components: 21739334 - store_protocol_components: 21739334 map_relative_component_balance: 21739334 store_balances: 21739334 map_protocol_changes: 21739334 @@ -39,19 +38,11 @@ modules: output: type: proto:tycho.evm.v1.BlockTransactionProtocolComponents - - name: store_protocol_components - kind: store - updatePolicy: set - valueType: string - inputs: - - map: map_protocol_components - - name: map_relative_component_balance kind: map inputs: - params: string - source: sf.ethereum.type.v2.Block - - store: store_protocol_components output: type: proto:tycho.evm.v1.BlockBalanceDeltas From a85265930a94c7b1bc982eef3c74ee743eab1a8b Mon Sep 17 00:00:00 2001 From: kayibal Date: Tue, 4 Feb 2025 18:48:35 -0600 Subject: [PATCH 6/8] fix: Correct balance accounting --- substreams/ethereum-ekubo/src/modules.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/substreams/ethereum-ekubo/src/modules.rs b/substreams/ethereum-ekubo/src/modules.rs index 2e8390ec0..6707acf1d 100644 --- a/substreams/ethereum-ekubo/src/modules.rs +++ b/substreams/ethereum-ekubo/src/modules.rs @@ -11,6 +11,7 @@ use tycho_substreams::balances::aggregate_balances_changes; use tycho_substreams::contract::extract_contract_changes_builder; use tycho_substreams::prelude::*; use itertools::Itertools; +use substreams::hex; use crate::pool_factories; use crate::pool_factories::{hash_pool_key, DeploymentConfig}; use crate::abi::core::events as core_events; @@ -110,14 +111,14 @@ fn map_relative_component_balance(params: String, block: eth::v2::Block) -> Resu ord: log.ordinal, tx: Some(tx.into()), token: ev.pool_key.0.clone(), - delta: ev.delta0.to_signed_bytes_be(), + delta: adjust_delta_by_fee(&ev.delta0, &ev.pool_key.3).to_signed_bytes_be(), component_id: pool_id.clone().into(), }, BalanceDelta { ord: log.ordinal, tx: Some(tx.into()), token: ev.pool_key.1.clone(), - delta: ev.delta1.to_signed_bytes_be(), + delta: adjust_delta_by_fee(&ev.delta1, &ev.pool_key.3).to_signed_bytes_be(), component_id: pool_id.into(), } ] @@ -150,6 +151,16 @@ fn map_relative_component_balance(params: String, block: eth::v2::Block) -> Resu Ok(BlockBalanceDeltas { balance_deltas: res }) } + +fn adjust_delta_by_fee(delta: &BigInt, fee: &BigInt) -> BigInt { + if delta < &BigInt::zero() { + let denom = BigInt::from_signed_bytes_be(&hex!("0100000000000000000000000000000000")); + (delta * denom.clone()) / (denom - fee) + } else { + delta.clone() + } +} + /// Aggregates relative balances values into absolute values /// /// Aggregate the relative balances in an additive store since tycho-indexer expects From 37b58e7c232576bbcd9bd4ea9b57a205e21bca1c Mon Sep 17 00:00:00 2001 From: kayibal Date: Wed, 5 Feb 2025 18:00:55 -0600 Subject: [PATCH 7/8] Adjust deltas by fee at PositionUpdated event --- substreams/ethereum-ekubo/src/modules.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/substreams/ethereum-ekubo/src/modules.rs b/substreams/ethereum-ekubo/src/modules.rs index 6707acf1d..7c436bc94 100644 --- a/substreams/ethereum-ekubo/src/modules.rs +++ b/substreams/ethereum-ekubo/src/modules.rs @@ -74,14 +74,14 @@ fn map_relative_component_balance(params: String, block: eth::v2::Block) -> Resu ord: log.ordinal, tx: Some(tx.into()), token: ev.pool_key.0.clone(), - delta: ev.delta0.to_signed_bytes_be(), + delta: adjust_delta_by_fee(&ev.delta0, &ev.pool_key.3).to_signed_bytes_be(), component_id: pool_id.clone().into(), }, BalanceDelta { ord: log.ordinal, tx: Some(tx.into()), token: ev.pool_key.1.clone(), - delta: ev.delta1.to_signed_bytes_be(), + delta: adjust_delta_by_fee(&ev.delta1, &ev.pool_key.3).to_signed_bytes_be(), component_id: pool_id.into(), } ] @@ -111,14 +111,14 @@ fn map_relative_component_balance(params: String, block: eth::v2::Block) -> Resu ord: log.ordinal, tx: Some(tx.into()), token: ev.pool_key.0.clone(), - delta: adjust_delta_by_fee(&ev.delta0, &ev.pool_key.3).to_signed_bytes_be(), + delta: ev.delta0.to_signed_bytes_be(), component_id: pool_id.clone().into(), }, BalanceDelta { ord: log.ordinal, tx: Some(tx.into()), token: ev.pool_key.1.clone(), - delta: adjust_delta_by_fee(&ev.delta1, &ev.pool_key.3).to_signed_bytes_be(), + delta: &ev.delta1.to_signed_bytes_be(), component_id: pool_id.into(), } ] From 9094325edcf527f082c0d38222fed9680f1719f1 Mon Sep 17 00:00:00 2001 From: die-herdplatte <173669014+die-herdplatte@users.noreply.github.com> Date: Thu, 6 Mar 2025 17:08:39 +0100 Subject: [PATCH 8/8] Add partial Ekubo integration --- evm/src/ekubo/EkuboSwapAdapter.sol | 463 ++++++ evm/src/ekubo/SqrtRatio.sol | 33 + evm/src/ekubo/manifest.yaml | 30 + evm/src/interfaces/ISwapAdapterV2.sol | 125 ++ substreams/Cargo.lock | 1 - substreams/ethereum-ekubo/Cargo.toml | 1 - substreams/ethereum-ekubo/abi/core.json | 498 +----- substreams/ethereum-ekubo/abi/oracle.json | 292 +--- .../integration_test.tycho.yaml | 64 +- substreams/ethereum-ekubo/proto/ekubo.proto | 9 + substreams/ethereum-ekubo/src/abi/core.rs | 1452 ++++------------- substreams/ethereum-ekubo/src/abi/oracle.rs | 1331 ++++++--------- substreams/ethereum-ekubo/src/identifiers.rs | 35 + substreams/ethereum-ekubo/src/lib.rs | 3 +- substreams/ethereum-ekubo/src/modules.rs | 145 +- substreams/ethereum-ekubo/src/pb/ekubo.rs | 12 + substreams/ethereum-ekubo/src/pb/mod.rs | 45 +- .../src/pb/sf.substreams.index.v1.rs | 8 - .../src/pb/sf.substreams.rpc.v2.rs | 340 ---- .../ethereum-ekubo/src/pb/sf.substreams.rs | 14 - .../src/pb/sf.substreams.sink.service.v1.rs | 227 --- .../ethereum-ekubo/src/pb/sf.substreams.v1.rs | 324 ---- .../ethereum-ekubo/src/pool_factories.rs | 61 +- substreams/ethereum-ekubo/substreams.yaml | 26 +- 24 files changed, 1843 insertions(+), 3696 deletions(-) create mode 100644 evm/src/ekubo/EkuboSwapAdapter.sol create mode 100644 evm/src/ekubo/SqrtRatio.sol create mode 100644 evm/src/ekubo/manifest.yaml create mode 100644 evm/src/interfaces/ISwapAdapterV2.sol create mode 100644 substreams/ethereum-ekubo/proto/ekubo.proto create mode 100644 substreams/ethereum-ekubo/src/identifiers.rs create mode 100644 substreams/ethereum-ekubo/src/pb/ekubo.rs delete mode 100644 substreams/ethereum-ekubo/src/pb/sf.substreams.index.v1.rs delete mode 100644 substreams/ethereum-ekubo/src/pb/sf.substreams.rpc.v2.rs delete mode 100644 substreams/ethereum-ekubo/src/pb/sf.substreams.rs delete mode 100644 substreams/ethereum-ekubo/src/pb/sf.substreams.sink.service.v1.rs delete mode 100644 substreams/ethereum-ekubo/src/pb/sf.substreams.v1.rs diff --git a/evm/src/ekubo/EkuboSwapAdapter.sol b/evm/src/ekubo/EkuboSwapAdapter.sol new file mode 100644 index 000000000..cc92abdf0 --- /dev/null +++ b/evm/src/ekubo/EkuboSwapAdapter.sol @@ -0,0 +1,463 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +pragma solidity ^0.8.13; + +import {ISwapAdapterV2} from "src/interfaces/ISwapAdapterV2.sol"; +import { + IERC20, + SafeERC20 +} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; +import {SqrtRatioFloat, MIN_SQRT_RATIO, MAX_SQRT_RATIO} from "./SqrtRatio.sol"; + +struct PoolKey { + address token0; + address token1; + bytes32 config; +} + +interface ILocker { + function locked(uint256 id) external; +} + +interface IPayer { + function payCallback(uint256 id, address token) external; +} + +address constant NATIVE_TOKEN_ADDRESS = + address(0x0000000000000000000000000000eeEEee000000); + +interface IFlashAccountant { + function lock() external; + + function pay(address token) external; + + function withdraw(address token, address recipient, uint128 amount) + external; + + receive() external payable; +} + +interface IExposedStorage { + function sload(bytes32 slot) external view returns (bytes32 result); + function tload(bytes32 slot) external view returns (bytes32 result); +} + +function isPriceIncreasing(int128 amount, bool isToken1) pure returns (bool increasing) { + assembly ("memory-safe") { + increasing := xor(isToken1, slt(amount, 0)) + } +} + +library ExposedStorageLib { + function unsafeRead(IExposedStorage target, bytes32 slot) + internal + view + returns (bytes32 result) + { + assembly ("memory-safe") { + mstore(0, shl(224, 0xf4910a73)) + mstore(4, slot) + + pop(staticcall(gas(), target, 0, 36, 0, 32)) + + result := mload(0) + } + } + + function unsafeReadTransient(IExposedStorage target, bytes32 slot) + internal + view + returns (bytes32 result) + { + assembly ("memory-safe") { + mstore(0, shl(224, 0xbd2e587d)) + mstore(4, slot) + + pop(staticcall(gas(), target, 0, 36, 0, 32)) + + result := mload(0) + } + } +} + +library CoreLib { + using ExposedStorageLib for *; + + function poolPrice(ICore core, bytes32 poolId) + internal + view + returns (SqrtRatioFloat sqrtRatio) + { + bytes32 key; + assembly ("memory-safe") { + mstore(0, poolId) + mstore(32, 2) + key := keccak256(0, 64) + } + + bytes32 p = core.unsafeRead(key); + + assembly ("memory-safe") { + sqrtRatio := and(p, 0xffffffffffffffffffffffff) + } + } +} + +struct SwapParameters { + int128 amount; + bool isToken1; + uint96 sqrtRatioLimit; + uint256 skipAhead; +} + +interface ICore is IFlashAccountant, IExposedStorage { + // Loads from the saved balance of the contract to pay in the current lock + // context. + function load(address token, bytes32 salt, uint128 amount) external; + + // Saves an amount of a token to be used later. + function save(address owner, address token, bytes32 salt, uint128 amount) + external; + + function swap(PoolKey memory poolKey, SwapParameters memory params) + external + returns (int128 delta0, int128 delta1); +} + +abstract contract BaseLocker is ILocker, IPayer { + using SafeERC20 for IERC20; + + error BaseLockerAccountantOnly(); + + IFlashAccountant internal immutable accountant; + + constructor(IFlashAccountant _accountant) { + accountant = _accountant; + } + + /// CALLBACK HANDLERS + + function locked(uint256 id) external { + if (msg.sender != address(accountant)) { + revert BaseLockerAccountantOnly(); + } + + bytes memory data = msg.data[36:]; + + bytes memory result = handleLockData(id, data); + + assembly ("memory-safe") { + // raw return whatever the handler sent + return(add(result, 32), mload(result)) + } + } + + function payCallback(uint256, address token) external { + if (msg.sender != address(accountant)) { + revert BaseLockerAccountantOnly(); + } + + address from; + uint256 amount; + assembly ("memory-safe") { + from := calldataload(68) + amount := calldataload(100) + } + + if (from != address(this)) { + IERC20(token).safeTransferFrom(from, address(accountant), amount); + } else { + IERC20(token).safeTransfer(address(accountant), amount); + } + } + + /// INTERNAL FUNCTIONS + + function lock(bytes memory data) internal returns (bytes memory result) { + address target = address(accountant); + + assembly ("memory-safe") { + // We will store result where the free memory pointer is now, ... + result := mload(0x40) + + // But first use it to store the calldata + + // Selector of lock() + mstore(result, shl(224, 0xf83d08ba)) + + // We only copy the data, not the length, because the length is read + // from the calldata size + let len := mload(data) + mcopy(add(result, 4), add(data, 32), len) + + // If the call failed, pass through the revert + if iszero(call(gas(), target, 0, result, add(len, 36), 0, 0)) { + returndatacopy(0, 0, returndatasize()) + revert(0, returndatasize()) + } + + // Copy the entire return data into the space where the result is + // pointing + mstore(result, returndatasize()) + returndatacopy(add(result, 32), 0, returndatasize()) + + // Update the free memory pointer to be after the end of the data, + // aligned to the next 32 byte word + mstore( + 0x40, + and(add(add(result, add(32, returndatasize())), 31), not(31)) + ) + } + } + + error ExpectedRevertWithinLock(); + + function lockAndExpectRevert(bytes memory data) + internal + returns (bytes memory result) + { + address target = address(accountant); + + assembly ("memory-safe") { + // We will store result where the free memory pointer is now, ... + result := mload(0x40) + + // But first use it to store the calldata + + // Selector of lock() + mstore(result, shl(224, 0xf83d08ba)) + + // We only copy the data, not the length, because the length is read + // from the calldata size + let len := mload(data) + mcopy(add(result, 4), add(data, 32), len) + + // If the call succeeded, revert with + // ExpectedRevertWithinLock.selector + if call(gas(), target, 0, result, add(len, 36), 0, 0) { + mstore(0, shl(224, 0x4c816e2b)) + revert(0, 0) + } + + // Copy the entire revert data into the space where the result is + // pointing + mstore(result, returndatasize()) + returndatacopy(add(result, 32), 0, returndatasize()) + + // Update the free memory pointer to be after the end of the data, + // aligned to the next 32 byte word + mstore( + 0x40, + and(add(add(result, add(32, returndatasize())), 31), not(31)) + ) + } + } + + function pay(address from, address token, uint256 amount) internal { + address target = address(accountant); + + if (amount > 0) { + if (token == NATIVE_TOKEN_ADDRESS) { + address(accountant).call{value: amount}(""); + } else { + assembly ("memory-safe") { + let free := mload(0x40) + // selector of pay(address) + mstore(free, shl(224, 0x0c11dedd)) + mstore(add(free, 4), token) + mstore(add(free, 36), from) + mstore(add(free, 68), amount) + + // if it failed, pass through revert + if iszero(call(gas(), target, 0, free, 100, 0, 0)) { + returndatacopy(0, 0, returndatasize()) + revert(0, returndatasize()) + } + } + } + } + } + + function withdraw(address token, uint128 amount, address recipient) + internal + { + if (amount > 0) { + accountant.withdraw(token, recipient, amount); + } + } + + function handleLockData(uint256 id, bytes memory data) + internal + virtual + returns (bytes memory result); +} + +contract EkuboSwapAdapter is ISwapAdapterV2, BaseLocker { + using SafeERC20 for IERC20; + using CoreLib for ICore; + + uint256 private constant TWO_POW_127 = 1 << 127; + uint256 private constant INT128_MAX = TWO_POW_127 - 1; + + ICore immutable core; + + constructor(ICore core_) BaseLocker(core_) { + core = core_; + } + + /// @inheritdoc ISwapAdapterV2 + function price( + bytes memory /*poolId*/, + address /*sellToken*/, + address /*buyToken*/, + uint256[] memory /*specifiedAmounts*/, + bytes memory /*data*/ + ) external pure override returns (Fraction[] memory /*prices*/) { + revert NotImplemented("not supported with view"); + } + + /// @inheritdoc ISwapAdapterV2 + function swap( + bytes memory poolId, + address sellToken, + address buyToken, + OrderSide side, + uint256 specifiedAmount, + bytes memory data + ) external override returns (Trade memory trade) { + PoolKey memory poolKey = decodePoolKey(poolId); + uint256 skipAhead = abi.decode(data, (uint256)); + + int128 amount; + bool isToken1; + SqrtRatioFloat sqrtRatioLimit; + + if (side == OrderSide.Sell) { + if (specifiedAmount > INT128_MAX) { + revert AmountOverflow(); + } + + amount = int128(uint128(specifiedAmount)); + isToken1 = poolKey.token1 == sellToken; + sqrtRatioLimit = isToken1 ? MAX_SQRT_RATIO : MIN_SQRT_RATIO; + } else { + if (specifiedAmount > TWO_POW_127) { + revert AmountOverflow(); + } + + amount = int128(-int256(specifiedAmount)); + isToken1 = poolKey.token0 == buyToken; + sqrtRatioLimit = isToken1 ? MIN_SQRT_RATIO : MAX_SQRT_RATIO; + } + + bytes memory res = lock(abi.encode( + msg.sender, + poolKey, + SwapParameters( + amount, + isToken1, + SqrtRatioFloat.unwrap(sqrtRatioLimit), + skipAhead + ) + )); + + (uint256 gasUsed, uint256 calculatedAmount) = abi.decode(res, (uint256, uint256)); + + SqrtRatioFloat sqrtRatioAfter = core.poolPrice(computePoolId(poolKey)); + + trade = Trade( + calculatedAmount, + gasUsed, + sqrtRatioAfter.toFixed().toRational() + ); + } + + /// @inheritdoc ISwapAdapterV2 + function getLimits(bytes memory /*poolId*/, address /*sellToken*/, address /*buyToken*/, bytes memory /*data*/) + external + pure + override + returns (uint256[] memory /*limits*/) + { + revert NotImplemented("not supported with view"); + } + + /// @inheritdoc ISwapAdapterV2 + function getCapabilities(bytes memory, address, address) + external + pure + override + returns (Capability[] memory capabilities) + { + capabilities = new Capability[](4); + capabilities[0] = Capability.SellOrder; + capabilities[1] = Capability.BuyOrder; + capabilities[2] = Capability.MarginalPrice; + capabilities[3] = Capability.FeeOnTransfer; + } + + /// @inheritdoc ISwapAdapterV2 + function getTokens(bytes memory poolId) + external + pure + override + returns (address[] memory tokens) + { + PoolKey memory poolKey = decodePoolKey(poolId); + + tokens = new address[](2); + tokens[0] = poolKey.token0; + tokens[1] = poolKey.token1; + } + + /// @inheritdoc ISwapAdapterV2 + function getPoolIds(uint256, uint256) + external + pure + override + returns (bytes32[] memory) + { + revert NotImplemented("infinite possible pools"); + } + + function handleLockData(uint256, bytes memory data) + internal + override + returns (bytes memory res) + { + ( + address swapper, + PoolKey memory poolKey, + SwapParameters memory swapParameters + ) = abi.decode(data, (address, PoolKey, SwapParameters)); + + uint256 gasLeftBefore = gasleft(); + (int128 delta0, int128 delta1) = core.swap(poolKey, swapParameters); + uint256 swapGasUsed = gasLeftBefore - gasleft(); + + if (isPriceIncreasing(swapParameters.amount, swapParameters.isToken1)) { + withdraw(poolKey.token0, uint128(-delta0), swapper); + pay(swapper, poolKey.token1, uint128(delta1)); + } else { + withdraw(poolKey.token1, uint128(-delta1), swapper); + pay(swapper, poolKey.token0, uint128(delta0)); + } + + res = abi.encode(swapGasUsed); + } + + function decodePoolKey(bytes memory enc) internal pure returns (PoolKey memory poolKey) { + poolKey = abi.decode(enc, (PoolKey)); + } + + function computePoolId(PoolKey memory poolKey) internal pure returns (bytes32 poolId) { + poolId = keccak256( + abi.encode( + poolKey.token0, + poolKey.token1, + poolKey.config + ) + ); + } + + error AmountOverflow(); +} diff --git a/evm/src/ekubo/SqrtRatio.sol b/evm/src/ekubo/SqrtRatio.sol new file mode 100644 index 000000000..0edd453d5 --- /dev/null +++ b/evm/src/ekubo/SqrtRatio.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +pragma solidity ^0.8.13; + +import {ISwapAdapterTypes} from "src/interfaces/ISwapAdapterTypes.sol"; + +type SqrtRatioFloat is uint96; +type SqrtRatioFixed is uint192; + +uint192 constant BIT_MASK = 0xc00000000000000000000000; +uint192 constant NOT_BIT_MASK = 0x3fffffffffffffffffffffff; + +uint256 constant TWO_POW_128 = 1 << 128; + +SqrtRatioFloat constant MIN_SQRT_RATIO = SqrtRatioFloat.wrap(0); +SqrtRatioFloat constant MAX_SQRT_RATIO = SqrtRatioFloat.wrap(type(uint96).max); + +function toFixed(SqrtRatioFloat sqrtRatioFloat) pure returns (SqrtRatioFixed sqrtRatioFixed) { + uint96 f = SqrtRatioFloat.unwrap(sqrtRatioFloat); + + sqrtRatioFixed = SqrtRatioFixed.wrap( + (f & NOT_BIT_MASK) << (2 + ((f & BIT_MASK) >> 89)) + ); +} + +function toRational(SqrtRatioFixed sqrtRatioFixed) pure returns (ISwapAdapterTypes.Fraction memory price) { + price = ISwapAdapterTypes.Fraction( + SqrtRatioFixed.unwrap(sqrtRatioFixed), + TWO_POW_128 + ); +} + +using {toFixed} for SqrtRatioFloat global; +using {toRational} for SqrtRatioFixed global; diff --git a/evm/src/ekubo/manifest.yaml b/evm/src/ekubo/manifest.yaml new file mode 100644 index 000000000..88c04e0a9 --- /dev/null +++ b/evm/src/ekubo/manifest.yaml @@ -0,0 +1,30 @@ +constants: + protocol_gas: 80000 + # Minimum capabilities we can expect, individual pools may extend these + capabilities: + - SellSide + - BuySide + - PriceFunction + +# The file containing the adapter contract +contract: EkuboSwapAdapter.sol + +# Deployment instances used to generate chain specific bytecode. +instances: + - chain: + name: sepolia + id: 11155111 + arguments: + - "0xBA12222222228d8Ba445958a75a0704d566BF2C8" + +# Specify some automatic test cases in case getPoolIds and +# getTokens are not implemented. +#tests: +# instances: + # - pool_id: "0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc" + # sell_token: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" + # buy_token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" + # block: 17000000 + # chain: + # name: mainnet + # id: 1 diff --git a/evm/src/interfaces/ISwapAdapterV2.sol b/evm/src/interfaces/ISwapAdapterV2.sol new file mode 100644 index 000000000..ddab547e4 --- /dev/null +++ b/evm/src/interfaces/ISwapAdapterV2.sol @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +pragma solidity ^0.8.13; + +import {ISwapAdapterTypes} from "src/interfaces/ISwapAdapterTypes.sol"; + +/// @title ISwapAdapter +/// @dev Implement this interface to support Propeller routing through your +/// pools. Before implementing the interface we need to introduce some function +/// for a given pool. The main one, the swap(x) function, implements a sell +/// order of a specified token. +/// The gas function simply +/// returns the estimated gas cost given a specified amount x. Last but not +/// least, the price function is the derivative of the swap function. It +/// represents the best possible price a user can get from a pool after swapping +/// x of the specified token. During calls to swap and getLimits, the caller can +/// be assumed to have the required sell or buy token balance as well as +/// unlimited approvals to this contract. +interface ISwapAdapterV2 is ISwapAdapterTypes { + /// @notice Calculates pool prices for specified amounts (optional). + /// @dev The returned prices should include all dex fees. In case the fee is + /// dynamic, the returned price is expected to include the minimum fee. + /// Ideally this method should be implemented, although it is optional as + /// the price function can be numerically estimated from the swap function. + /// In case it is not available, it should be flagged via capabilities and + /// calling it should revert using the `NotImplemented` error. The method + /// needs to be implemented as view as this is usually more efficient and + /// can be run in parallel. + /// @param poolId The ID of the trading pool. + /// @param sellToken The token being sold. + /// @param buyToken The token being bought. + /// @param specifiedAmounts The specified amounts used for price + /// calculation. + /// @param data Any additional data required, that does not fit the + /// interface + /// @return prices array of prices as fractions corresponding to the + /// provided amounts. + function price( + bytes memory poolId, + address sellToken, + address buyToken, + uint256[] memory specifiedAmounts, + bytes memory data + ) external returns (Fraction[] memory prices); + + /** + * @notice Simulates swapping tokens on a given pool. + * @dev This function should be state modifying, meaning it should actually + * execute the swap and change the state of the EVM accordingly. Please + * include a gas usage estimate for each amount. This can be achieved e.g. by + * using the `gasleft()` function. The return type `Trade` has an attribute + * called price which should contain the value of `price(specifiedAmount)`. + * As this is optional, defined via `Capability.PriceFunction`, it is valid + * to return a Fraction(0, 0) value for this price. In that case the price + * will be estimated numerically. + * @param poolId The ID of the trading pool. + * @param sellToken The token being sold. + * @param buyToken The token being bought. + * @param side The side of the trade (Sell or Buy). + * @param specifiedAmount The amount to be traded. + * @param data Any additional data required, that does not fit the interface + * @return trade Trade struct representing the executed trade. + */ + function swap( + bytes memory poolId, + address sellToken, + address buyToken, + OrderSide side, + uint256 specifiedAmount, + bytes memory data + ) external returns (Trade memory trade); + + /// @notice Retrieves the limits for each token. + /// @dev Retrieve the maximum limits of a token that can be traded. The + /// limit is reached when the change in the received amounts is zero or + /// close to zero or when the swap fails because of the pools restrictions. + /// Overestimate if in doubt rather than underestimate. The + /// swap function should not error with `LimitExceeded` if called with + /// amounts below the limit. + /// @param poolId The ID of the trading pool. + /// @param sellToken The token being sold. + /// @param buyToken The token being bought. + /// @param data Any additional data required, that does not fit the + /// interface + /// @return limits An array of size two indicating the limit amount for the + /// sell + /// token (maximum the pool is willing to buy in sell token) as well as + /// the limit + /// amount of the buy token (maximum the pool is willing to sell in buy + /// token). + function getLimits( + bytes memory poolId, + address sellToken, + address buyToken, + bytes memory data + ) external returns (uint256[] memory limits); + + /// @notice Retrieves the capabilities of the selected pool. + /// @param poolId The ID of the trading pool. + /// @return capabilities An array of Capability. + function getCapabilities( + bytes memory poolId, + address sellToken, + address buyToken + ) external returns (Capability[] memory capabilities); + + /// @notice Retrieves the tokens in the selected pool. + /// @dev Mainly used for testing as this is redundant with the required + /// substreams implementation. + /// @param poolId The ID of the trading pool. + /// @return tokens An array of address contracts. + function getTokens(bytes memory poolId) + external + returns (address[] memory tokens); + + /// @notice Retrieves a range of pool IDs. + /// @dev Mainly used for testing. It is alright to not return all available + /// pools here. Nevertheless, this is useful to test against the substreams + /// implementation. If implemented, it saves time writing custom tests. + /// @param offset The starting index from which to retrieve pool IDs. + /// @param limit The maximum number of pool IDs to retrieve. + /// @return ids An array of pool IDs. + function getPoolIds(uint256 offset, uint256 limit) + external + returns (bytes32[] memory ids); +} diff --git a/substreams/Cargo.lock b/substreams/Cargo.lock index 241a19098..071c7047c 100644 --- a/substreams/Cargo.lock +++ b/substreams/Cargo.lock @@ -275,7 +275,6 @@ dependencies = [ "serde_qs", "substreams", "substreams-ethereum", - "tiny-keccak", "tycho-substreams 0.2.0 (git+https://github.com/propeller-heads/tycho-protocol-sdk.git?rev=3c08359)", ] diff --git a/substreams/ethereum-ekubo/Cargo.toml b/substreams/ethereum-ekubo/Cargo.toml index 718a6976f..a9858a222 100644 --- a/substreams/ethereum-ekubo/Cargo.toml +++ b/substreams/ethereum-ekubo/Cargo.toml @@ -20,7 +20,6 @@ itertools = "0.10.5" serde = "1.0.217" serde-sibor = "0.1.0" serde_qs = "0.13.0" -tiny-keccak = "2.0.2" [build-dependencies] diff --git a/substreams/ethereum-ekubo/abi/core.json b/substreams/ethereum-ekubo/abi/core.json index 2b8c2ece1..c3d430044 100644 --- a/substreams/ethereum-ekubo/abi/core.json +++ b/substreams/ethereum-ekubo/abi/core.json @@ -6,11 +6,6 @@ "name": "owner", "type": "address", "internalType": "address" - }, - { - "name": "expirationTime", - "type": "uint256", - "internalType": "uint256" } ], "stateMutability": "nonpayable" @@ -39,19 +34,9 @@ "internalType": "address" }, { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" + "name": "config", + "type": "bytes32", + "internalType": "Config" } ] }, @@ -67,7 +52,7 @@ } ], "outputs": [], - "stateMutability": "nonpayable" + "stateMutability": "payable" }, { "type": "function", @@ -96,19 +81,9 @@ "internalType": "address" }, { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" + "name": "config", + "type": "bytes32", + "internalType": "Config" } ] }, @@ -162,19 +137,6 @@ "outputs": [], "stateMutability": "payable" }, - { - "type": "function", - "name": "expirationTime", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, { "type": "function", "name": "forward", @@ -193,9 +155,26 @@ "name": "getPoolFeesPerLiquidityInside", "inputs": [ { - "name": "poolId", - "type": "bytes32", - "internalType": "bytes32" + "name": "poolKey", + "type": "tuple", + "internalType": "struct PoolKey", + "components": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "config", + "type": "bytes32", + "internalType": "Config" + } + ] }, { "name": "bounds", @@ -256,19 +235,9 @@ "internalType": "address" }, { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" + "name": "config", + "type": "bytes32", + "internalType": "Config" } ] }, @@ -281,8 +250,8 @@ "outputs": [ { "name": "sqrtRatio", - "type": "uint256", - "internalType": "uint256" + "type": "uint96", + "internalType": "SqrtRatio" } ], "stateMutability": "nonpayable" @@ -398,7 +367,13 @@ "internalType": "address" } ], - "outputs": [], + "outputs": [ + { + "name": "payment", + "type": "uint128", + "internalType": "uint128" + } + ], "stateMutability": "nonpayable" }, { @@ -535,7 +510,7 @@ } ], "outputs": [], - "stateMutability": "nonpayable" + "stateMutability": "payable" }, { "type": "function", @@ -576,19 +551,9 @@ "internalType": "address" }, { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" + "name": "config", + "type": "bytes32", + "internalType": "Config" } ] }, @@ -609,8 +574,8 @@ }, { "name": "sqrtRatioLimit", - "type": "uint256", - "internalType": "uint256" + "type": "uint96", + "internalType": "SqrtRatio" }, { "name": "skipAhead", @@ -632,7 +597,7 @@ "internalType": "int128" } ], - "stateMutability": "nonpayable" + "stateMutability": "payable" }, { "type": "function", @@ -686,19 +651,9 @@ "internalType": "address" }, { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" + "name": "config", + "type": "bytes32", + "internalType": "Config" } ] }, @@ -749,7 +704,7 @@ "internalType": "int128" } ], - "stateMutability": "nonpayable" + "stateMutability": "payable" }, { "type": "function", @@ -815,37 +770,10 @@ "name": "FeesAccumulated", "inputs": [ { - "name": "poolKey", - "type": "tuple", + "name": "poolId", + "type": "bytes32", "indexed": false, - "internalType": "struct PoolKey", - "components": [ - { - "name": "token0", - "type": "address", - "internalType": "address" - }, - { - "name": "token1", - "type": "address", - "internalType": "address" - }, - { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" - } - ] + "internalType": "bytes32" }, { "name": "amount0", @@ -942,6 +870,12 @@ "type": "event", "name": "PoolInitialized", "inputs": [ + { + "name": "poolId", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, { "name": "poolKey", "type": "tuple", @@ -959,19 +893,9 @@ "internalType": "address" }, { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" + "name": "config", + "type": "bytes32", + "internalType": "Config" } ] }, @@ -983,9 +907,9 @@ }, { "name": "sqrtRatio", - "type": "uint256", + "type": "uint96", "indexed": false, - "internalType": "uint256" + "internalType": "SqrtRatio" } ], "anonymous": false @@ -995,37 +919,10 @@ "name": "PositionFeesCollected", "inputs": [ { - "name": "poolKey", - "type": "tuple", + "name": "poolId", + "type": "bytes32", "indexed": false, - "internalType": "struct PoolKey", - "components": [ - { - "name": "token0", - "type": "address", - "internalType": "address" - }, - { - "name": "token1", - "type": "address", - "internalType": "address" - }, - { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" - } - ] + "internalType": "bytes32" }, { "name": "positionKey", @@ -1088,37 +985,10 @@ "internalType": "address" }, { - "name": "poolKey", - "type": "tuple", + "name": "poolId", + "type": "bytes32", "indexed": false, - "internalType": "struct PoolKey", - "components": [ - { - "name": "token0", - "type": "address", - "internalType": "address" - }, - { - "name": "token1", - "type": "address", - "internalType": "address" - }, - { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" - } - ] + "internalType": "bytes32" }, { "name": "params", @@ -1170,93 +1040,6 @@ ], "anonymous": false }, - { - "type": "event", - "name": "ProtocolFeesPaid", - "inputs": [ - { - "name": "poolKey", - "type": "tuple", - "indexed": false, - "internalType": "struct PoolKey", - "components": [ - { - "name": "token0", - "type": "address", - "internalType": "address" - }, - { - "name": "token1", - "type": "address", - "internalType": "address" - }, - { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" - } - ] - }, - { - "name": "positionKey", - "type": "tuple", - "indexed": false, - "internalType": "struct PositionKey", - "components": [ - { - "name": "salt", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "owner", - "type": "address", - "internalType": "address" - }, - { - "name": "bounds", - "type": "tuple", - "internalType": "struct Bounds", - "components": [ - { - "name": "lower", - "type": "int32", - "internalType": "int32" - }, - { - "name": "upper", - "type": "int32", - "internalType": "int32" - } - ] - } - ] - }, - { - "name": "amount0", - "type": "uint128", - "indexed": false, - "internalType": "uint128" - }, - { - "name": "amount1", - "type": "uint128", - "indexed": false, - "internalType": "uint128" - } - ], - "anonymous": false - }, { "type": "event", "name": "ProtocolFeesWithdrawn", @@ -1313,110 +1096,6 @@ ], "anonymous": false }, - { - "type": "event", - "name": "Swapped", - "inputs": [ - { - "name": "locker", - "type": "address", - "indexed": false, - "internalType": "address" - }, - { - "name": "poolKey", - "type": "tuple", - "indexed": false, - "internalType": "struct PoolKey", - "components": [ - { - "name": "token0", - "type": "address", - "internalType": "address" - }, - { - "name": "token1", - "type": "address", - "internalType": "address" - }, - { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" - } - ] - }, - { - "name": "params", - "type": "tuple", - "indexed": false, - "internalType": "struct SwapParameters", - "components": [ - { - "name": "amount", - "type": "int128", - "internalType": "int128" - }, - { - "name": "isToken1", - "type": "bool", - "internalType": "bool" - }, - { - "name": "sqrtRatioLimit", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "skipAhead", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "name": "delta0", - "type": "int128", - "indexed": false, - "internalType": "int128" - }, - { - "name": "delta1", - "type": "int128", - "indexed": false, - "internalType": "int128" - }, - { - "name": "sqrtRatioAfter", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - }, - { - "name": "tickAfter", - "type": "int32", - "indexed": false, - "internalType": "int32" - }, - { - "name": "liquidityAfter", - "type": "uint128", - "indexed": false, - "internalType": "uint128" - } - ], - "anonymous": false - }, { "type": "error", "name": "AlreadyInitialized", @@ -1447,11 +1126,6 @@ "name": "BoundsTickSpacing", "inputs": [] }, - { - "type": "error", - "name": "ContractHasExpired", - "inputs": [] - }, { "type": "error", "name": "DebtsNotZeroed", @@ -1463,6 +1137,11 @@ } ] }, + { + "type": "error", + "name": "ExtensionAlreadyRegistered", + "inputs": [] + }, { "type": "error", "name": "ExtensionNotRegistered", @@ -1473,6 +1152,11 @@ "name": "FailedRegisterInvalidCallPoints", "inputs": [] }, + { + "type": "error", + "name": "FullRangeOnlyPool", + "inputs": [] + }, { "type": "error", "name": "InsufficientSavedBalance", @@ -1480,14 +1164,8 @@ }, { "type": "error", - "name": "InvalidSqrtRatio", - "inputs": [ - { - "name": "sqrtRatio", - "type": "uint256", - "internalType": "uint256" - } - ] + "name": "InvalidSqrtRatioLimit", + "inputs": [] }, { "type": "error", @@ -1505,11 +1183,6 @@ "name": "InvalidTickSpacing", "inputs": [] }, - { - "type": "error", - "name": "InvalidTokens", - "inputs": [] - }, { "type": "error", "name": "LockerOnly", @@ -1572,7 +1245,7 @@ }, { "type": "error", - "name": "SqrtRatioLimitWrongDirection", + "name": "TokensMustBeSorted", "inputs": [] }, { @@ -1589,10 +1262,5 @@ "type": "error", "name": "ZeroLiquidityNextSqrtRatioFromAmount1", "inputs": [] - }, - { - "type": "error", - "name": "ZeroSqrtRatio", - "inputs": [] } ] diff --git a/substreams/ethereum-ekubo/abi/oracle.json b/substreams/ethereum-ekubo/abi/oracle.json index 25ae45385..876c11b0a 100644 --- a/substreams/ethereum-ekubo/abi/oracle.json +++ b/substreams/ethereum-ekubo/abi/oracle.json @@ -6,11 +6,6 @@ "name": "core", "type": "address", "internalType": "contract ICore" - }, - { - "name": "_oracleToken", - "type": "address", - "internalType": "address" } ], "stateMutability": "nonpayable" @@ -40,19 +35,9 @@ "internalType": "address" }, { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" + "name": "config", + "type": "bytes32", + "internalType": "Config" } ] }, @@ -117,19 +102,9 @@ "internalType": "address" }, { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" + "name": "config", + "type": "bytes32", + "internalType": "Config" } ] }, @@ -140,8 +115,8 @@ }, { "name": "", - "type": "uint256", - "internalType": "uint256" + "type": "uint96", + "internalType": "SqrtRatio" } ], "outputs": [], @@ -172,19 +147,9 @@ "internalType": "address" }, { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" + "name": "config", + "type": "bytes32", + "internalType": "Config" } ] }, @@ -205,8 +170,8 @@ }, { "name": "sqrtRatioLimit", - "type": "uint256", - "internalType": "uint256" + "type": "uint96", + "internalType": "SqrtRatio" }, { "name": "skipAhead", @@ -254,19 +219,9 @@ "internalType": "address" }, { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" + "name": "config", + "type": "bytes32", + "internalType": "Config" } ] }, @@ -343,19 +298,9 @@ "internalType": "address" }, { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" + "name": "config", + "type": "bytes32", + "internalType": "Config" } ] }, @@ -410,19 +355,9 @@ "internalType": "address" }, { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" + "name": "config", + "type": "bytes32", + "internalType": "Config" } ] }, @@ -460,19 +395,9 @@ "internalType": "address" }, { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" + "name": "config", + "type": "bytes32", + "internalType": "Config" } ] }, @@ -493,8 +418,8 @@ }, { "name": "sqrtRatioLimit", - "type": "uint256", - "internalType": "uint256" + "type": "uint96", + "internalType": "SqrtRatio" }, { "name": "skipAhead", @@ -532,19 +457,9 @@ "internalType": "address" }, { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" + "name": "config", + "type": "bytes32", + "internalType": "Config" } ] }, @@ -586,6 +501,59 @@ "outputs": [], "stateMutability": "nonpayable" }, + { + "type": "function", + "name": "counts", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "index", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "count", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "capacity", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "expandCapacity", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "minCapacity", + "type": "uint64", + "internalType": "uint64" + } + ], + "outputs": [ + { + "name": "capacity", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "nonpayable" + }, { "type": "function", "name": "extrapolateSnapshot", @@ -637,7 +605,7 @@ "internalType": "uint256" }, { - "name": "index", + "name": "logicalIndex", "type": "uint256", "internalType": "uint256" }, @@ -729,38 +697,15 @@ "internalType": "address" }, { - "name": "fee", - "type": "uint128", - "internalType": "uint128" - }, - { - "name": "tickSpacing", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "extension", - "type": "address", - "internalType": "address" + "name": "config", + "type": "bytes32", + "internalType": "Config" } ] } ], "stateMutability": "view" }, - { - "type": "function", - "name": "oracleToken", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, { "type": "function", "name": "secondsSinceOffset", @@ -812,25 +757,6 @@ ], "stateMutability": "view" }, - { - "type": "function", - "name": "snapshotCount", - "inputs": [ - { - "name": "token", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "count", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, { "type": "function", "name": "snapshots", @@ -897,48 +823,6 @@ ], "stateMutability": "view" }, - { - "type": "event", - "name": "SnapshotEvent", - "inputs": [ - { - "name": "token", - "type": "address", - "indexed": false, - "internalType": "address" - }, - { - "name": "index", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - }, - { - "name": "timestamp", - "type": "uint64", - "indexed": false, - "internalType": "uint64" - }, - { - "name": "secondsPerLiquidityCumulative", - "type": "uint160", - "indexed": false, - "internalType": "uint160" - }, - { - "name": "tickCumulative", - "type": "int64", - "indexed": false, - "internalType": "int64" - } - ], - "anonymous": false - }, - { - "type": "error", - "name": "BoundsMustBeMaximum", - "inputs": [] - }, { "type": "error", "name": "CallPointNotImplemented", @@ -982,7 +866,7 @@ }, { "type": "error", - "name": "PairsWithOracleTokenOnly", + "name": "PairsWithNativeTokenOnly", "inputs": [] }, { diff --git a/substreams/ethereum-ekubo/integration_test.tycho.yaml b/substreams/ethereum-ekubo/integration_test.tycho.yaml index bea6aa301..76187beac 100644 --- a/substreams/ethereum-ekubo/integration_test.tycho.yaml +++ b/substreams/ethereum-ekubo/integration_test.tycho.yaml @@ -1,57 +1,23 @@ -# Name of the substreams config file in your substreams module. Usually "./substreams.yaml" -substreams_yaml_path: ./substreams.yaml -# Name of the adapter contract, usually: ProtocolSwapAdapter" -adapter_contract: "SwapAdapter" -# Constructor signature of the Adapter contract" +adapter_contract: "EkuboSwapAdapter" adapter_build_signature: "constructor(address)" -# A comma separated list of args to be passed to the contructor of the Adapter contract" -adapter_build_args: "0x0000000000000000000000000000000000000000" -# Whether or not the testing script should skip checking balances of the protocol components. -# If set to `true` please always add a reason why it's skipped. -skip_balance_check: false -# A list of accounts that need to be indexed to run the tests properly. -# Usually used when there is a global component required by all pools and created before the tested range of blocks. For example a factory or a vault. -# Please note that this component needs to be indexed by your substreams module, this feature is only for testing purpose. -# Also please always add a reason why this account is needed for your tests. -# This will be applied to each test. -initialized_accounts: - - "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84" # Needed for .... -# A list of protocol types names created by your Substreams module. +adapter_build_args: "0x16e186ecdc94083fff53ef2a41d46b92a54f61e2" +skip_balance_check: true # This seems to fail because testing/src/runner:TestRunner.validate_state tries to interpret the component id as an Ethereum address? protocol_type_names: - - "type_name_1" - - "type_name_2" -# A list of tests. + - "ekubo" tests: - # Name of the test - name: test_pool_creation - # Indexed block range - start_block: 123 - stop_block: 456 - # Same as global `initialized_accounts` but only scoped to this test. - initialized_accounts: - - "0x0c0e5f2fF0ff18a3be9b835635039256dC4B4963" # Needed for .... - # A list of expected component indexed in the block range. Each component must match perfectly the `ProtocolComponent` indexed by your subtreams module. + start_block: 7811236 + stop_block: 7811283 expected_components: - - id: "0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7" + - id: "0xae76f216ce250b7b9a388d59cbbf92407d7ccee71a99b27ad521508b1c74681f" tokens: - - "0xdac17f958d2ee523a2206206994597c13d831ec7" - - "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" - - "0x6b175474e89094c44da98b954eedeac495271d0f" + - "0x0000000000000000000000000000000000000000" + - "0xb1b388f2ef1bb1f7979f009381f797f94b90c094" static_attributes: - attr_1: "value" - attr_2: "value" - creation_tx: "0x20793bbf260912aae189d5d261ff003c9b9166da8191d8f9d63ff1c7722f3ac6" - # Whether or not the script should skip trying to simulate a swap on this component. - # If set to `true` please always add a reason why it's skipped. + token0: "0x0000000000000000000000000000000000000000" + token1: "0xb1b388f2ef1bb1f7979f009381f797f94b90c094" + fee: "0x00c49ba5e353f7ce" + tick_spacing: "0x0000175e" + extension: "0x0000000000000000000000000000000000000000" + creation_tx: "0x4b39d41ae3b823409ba6a92e2937f52f545acfd9cb7ecf7fb8eb7ea2e3b9985e" skip_simulation: false - - name: test_something_else - start_block: 123 - stop_block: 456 - expected_components: - - id: "0xdc24316b9ae028f1497c275eb9192a3ea0f67022" - tokens: - - "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" - - "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84" - static_attributes: null - creation_tx: "0xfac67ecbd423a5b915deff06045ec9343568edaec34ae95c43d35f2c018afdaa" - skip_simulation: true # If true, always add a reason diff --git a/substreams/ethereum-ekubo/proto/ekubo.proto b/substreams/ethereum-ekubo/proto/ekubo.proto new file mode 100644 index 000000000..79356766e --- /dev/null +++ b/substreams/ethereum-ekubo/proto/ekubo.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +package ekubo; + +message PoolDetails { + bytes token0 = 1; + bytes token1 = 2; + fixed64 fee = 3; +} diff --git a/substreams/ethereum-ekubo/src/abi/core.rs b/substreams/ethereum-ekubo/src/abi/core.rs index 191af3383..ed16428ff 100644 --- a/substreams/ethereum-ekubo/src/abi/core.rs +++ b/substreams/ethereum-ekubo/src/abi/core.rs @@ -5,18 +5,12 @@ use super::INTERNAL_ERR; #[derive(Debug, Clone, PartialEq)] pub struct AccumulateAsFees { - pub pool_key: ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), + pub pool_key: (Vec, Vec, [u8; 32usize]), pub amount0: substreams::scalar::BigInt, pub amount1: substreams::scalar::BigInt, } impl AccumulateAsFees { - const METHOD_ID: [u8; 4] = [240u8, 104u8, 44u8, 123u8]; + const METHOD_ID: [u8; 4] = [233u8, 100u8, 4u8, 248u8]; pub fn decode( call: &substreams_ethereum::pb::eth::v2::Call, ) -> Result { @@ -29,8 +23,7 @@ ethabi::ParamType::Tuple( vec![ ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ethabi::ParamType::FixedBytes(32usize) ], ), ethabi::ParamType::Uint(128usize), @@ -61,29 +54,14 @@ .as_bytes() .to_vec(), { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] + let mut result = [0u8; 32]; + let v = tuple_elements[2usize] .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result }, - tuple_elements[4usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), ) }, amount0: { @@ -116,21 +94,8 @@ ethabi::Token::Address(ethabi::Address::from_slice(& self .pool_key.0)), ethabi::Token::Address(ethabi::Address::from_slice(& self - .pool_key.1)), - ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self - .pool_key.2.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 - .pool_key.3.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::Address(ethabi::Address::from_slice(& self - .pool_key.4)) + .pool_key.1)), ethabi::Token::FixedBytes(self.pool_key.2 + .as_ref().to_vec()) ], ), ethabi::Token::Uint( @@ -224,18 +189,12 @@ } #[derive(Debug, Clone, PartialEq)] pub struct CollectFees { - pub pool_key: ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), + pub pool_key: (Vec, Vec, [u8; 32usize]), pub salt: [u8; 32usize], pub bounds: (substreams::scalar::BigInt, substreams::scalar::BigInt), } impl CollectFees { - const METHOD_ID: [u8; 4] = [129u8, 109u8, 213u8, 103u8]; + const METHOD_ID: [u8; 4] = [100u8, 94u8, 201u8, 181u8]; pub fn decode( call: &substreams_ethereum::pb::eth::v2::Call, ) -> Result { @@ -248,8 +207,7 @@ ethabi::ParamType::Tuple( vec![ ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ethabi::ParamType::FixedBytes(32usize) ], ), ethabi::ParamType::FixedBytes(32usize), @@ -285,29 +243,14 @@ .as_bytes() .to_vec(), { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] + let mut result = [0u8; 32]; + let v = tuple_elements[2usize] .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result }, - tuple_elements[4usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), ) }, salt: { @@ -357,21 +300,8 @@ ethabi::Token::Address(ethabi::Address::from_slice(& self .pool_key.0)), ethabi::Token::Address(ethabi::Address::from_slice(& self - .pool_key.1)), - ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self - .pool_key.2.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 - .pool_key.3.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::Address(ethabi::Address::from_slice(& self - .pool_key.4)) + .pool_key.1)), ethabi::Token::FixedBytes(self.pool_key.2 + .as_ref().to_vec()) ], ), ethabi::Token::FixedBytes(self.salt.as_ref().to_vec()), @@ -573,97 +503,6 @@ } } #[derive(Debug, Clone, PartialEq)] - pub struct ExpirationTime {} - impl ExpirationTime { - const METHOD_ID: [u8; 4] = [218u8, 40u8, 77u8, 204u8]; - 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 ExpirationTime { - const NAME: &'static str = "expirationTime"; - 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 ExpirationTime { - fn output(data: &[u8]) -> Result { - Self::output(data) - } - } - #[derive(Debug, Clone, PartialEq)] pub struct Forward { pub to: Vec, } @@ -724,11 +563,11 @@ } #[derive(Debug, Clone, PartialEq)] pub struct GetPoolFeesPerLiquidityInside { - pub pool_id: [u8; 32usize], + pub pool_key: (Vec, Vec, [u8; 32usize]), pub bounds: (substreams::scalar::BigInt, substreams::scalar::BigInt), } impl GetPoolFeesPerLiquidityInside { - const METHOD_ID: [u8; 4] = [147u8, 64u8, 118u8, 82u8]; + const METHOD_ID: [u8; 4] = [5u8, 215u8, 230u8, 148u8]; pub fn decode( call: &substreams_ethereum::pb::eth::v2::Call, ) -> Result { @@ -738,7 +577,12 @@ } let mut values = ethabi::decode( &[ - ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::FixedBytes(32usize) + ], + ), ethabi::ParamType::Tuple( vec![ ethabi::ParamType::Int(32usize), @@ -751,15 +595,35 @@ .map_err(|e| format!("unable to decode call.input: {:?}", e))?; values.reverse(); Ok(Self { - pool_id: { - let mut result = [0u8; 32]; - let v = values + pool_key: { + let tuple_elements = values .pop() .expect(INTERNAL_ERR) - .into_fixed_bytes() + .into_tuple() .expect(INTERNAL_ERR); - result.copy_from_slice(&v); - result + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut result = [0u8; 32]; + let v = tuple_elements[2usize] + .clone() + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + ) }, bounds: { let tuple_elements = values @@ -793,7 +657,15 @@ pub fn encode(&self) -> Vec { let data = ethabi::encode( &[ - ethabi::Token::FixedBytes(self.pool_id.as_ref().to_vec()), + ethabi::Token::Tuple( + vec![ + ethabi::Token::Address(ethabi::Address::from_slice(& self + .pool_key.0)), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .pool_key.1)), ethabi::Token::FixedBytes(self.pool_key.2 + .as_ref().to_vec()) + ], + ), ethabi::Token::Tuple( vec![ { let non_full_signed_bytes = self.bounds.0 @@ -938,17 +810,11 @@ } #[derive(Debug, Clone, PartialEq)] pub struct InitializePool { - pub pool_key: ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), + pub pool_key: (Vec, Vec, [u8; 32usize]), pub tick: substreams::scalar::BigInt, } impl InitializePool { - const METHOD_ID: [u8; 4] = [85u8, 108u8, 130u8, 17u8]; + const METHOD_ID: [u8; 4] = [192u8, 83u8, 2u8, 68u8]; pub fn decode( call: &substreams_ethereum::pb::eth::v2::Call, ) -> Result { @@ -961,8 +827,7 @@ ethabi::ParamType::Tuple( vec![ ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ethabi::ParamType::FixedBytes(32usize) ], ), ethabi::ParamType::Int(32usize), @@ -992,29 +857,14 @@ .as_bytes() .to_vec(), { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] + let mut result = [0u8; 32]; + let v = tuple_elements[2usize] .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result }, - tuple_elements[4usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), ) }, tick: { @@ -1037,21 +887,8 @@ ethabi::Token::Address(ethabi::Address::from_slice(& self .pool_key.0)), ethabi::Token::Address(ethabi::Address::from_slice(& self - .pool_key.1)), - ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self - .pool_key.2.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 - .pool_key.3.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::Address(ethabi::Address::from_slice(& self - .pool_key.4)) + .pool_key.1)), ethabi::Token::FixedBytes(self.pool_key.2 + .as_ref().to_vec()) ], ), { @@ -1088,7 +925,7 @@ } pub fn output(data: &[u8]) -> Result { let mut values = ethabi::decode( - &[ethabi::ParamType::Uint(256usize)], + &[ethabi::ParamType::Uint(96usize)], data.as_ref(), ) .map_err(|e| format!("unable to decode output data: {:?}", e))?; @@ -1750,12 +1587,60 @@ 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 Pay { const NAME: &'static str = "pay"; @@ -1771,6 +1656,11 @@ self.encode() } } + impl substreams_ethereum::rpc::RPCDecodable for Pay { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } #[derive(Debug, Clone, PartialEq)] pub struct PrevInitializedTick { pub pool_id: [u8; 32usize], @@ -2400,13 +2290,7 @@ } #[derive(Debug, Clone, PartialEq)] pub struct Swap { - pub pool_key: ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), + pub pool_key: (Vec, Vec, [u8; 32usize]), pub params: ( substreams::scalar::BigInt, bool, @@ -2415,7 +2299,7 @@ ), } impl Swap { - const METHOD_ID: [u8; 4] = [170u8, 55u8, 59u8, 111u8]; + const METHOD_ID: [u8; 4] = [213u8, 86u8, 155u8, 177u8]; pub fn decode( call: &substreams_ethereum::pb::eth::v2::Call, ) -> Result { @@ -2428,14 +2312,13 @@ ethabi::ParamType::Tuple( vec![ ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ethabi::ParamType::FixedBytes(32usize) ], ), ethabi::ParamType::Tuple( vec![ ethabi::ParamType::Int(128usize), ethabi::ParamType::Bool, - ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(96usize), ethabi::ParamType::Uint(256usize) ], ), @@ -2465,29 +2348,14 @@ .as_bytes() .to_vec(), { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] + let mut result = [0u8; 32]; + let v = tuple_elements[2usize] .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result }, - tuple_elements[4usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), ) }, params: { @@ -2540,21 +2408,8 @@ ethabi::Token::Address(ethabi::Address::from_slice(& self .pool_key.0)), ethabi::Token::Address(ethabi::Address::from_slice(& self - .pool_key.1)), - ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self - .pool_key.2.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 - .pool_key.3.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::Address(ethabi::Address::from_slice(& self - .pool_key.4)) + .pool_key.1)), ethabi::Token::FixedBytes(self.pool_key.2 + .as_ref().to_vec()) ], ), ethabi::Token::Tuple( @@ -2876,13 +2731,7 @@ } #[derive(Debug, Clone, PartialEq)] pub struct UpdatePosition { - pub pool_key: ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), + pub pool_key: (Vec, Vec, [u8; 32usize]), pub params: ( [u8; 32usize], (substreams::scalar::BigInt, substreams::scalar::BigInt), @@ -2890,7 +2739,7 @@ ), } impl UpdatePosition { - const METHOD_ID: [u8; 4] = [165u8, 112u8, 111u8, 58u8]; + const METHOD_ID: [u8; 4] = [85u8, 244u8, 141u8, 1u8]; pub fn decode( call: &substreams_ethereum::pb::eth::v2::Call, ) -> Result { @@ -2903,8 +2752,7 @@ ethabi::ParamType::Tuple( vec![ ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ethabi::ParamType::FixedBytes(32usize) ], ), ethabi::ParamType::Tuple( @@ -2941,29 +2789,14 @@ .as_bytes() .to_vec(), { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] + let mut result = [0u8; 32]; + let v = tuple_elements[2usize] .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result }, - tuple_elements[4usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), ) }, params: { @@ -3029,21 +2862,8 @@ ethabi::Token::Address(ethabi::Address::from_slice(& self .pool_key.0)), ethabi::Token::Address(ethabi::Address::from_slice(& self - .pool_key.1)), - ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self - .pool_key.2.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 - .pool_key.3.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::Address(ethabi::Address::from_slice(& self - .pool_key.4)) + .pool_key.1)), ethabi::Token::FixedBytes(self.pool_key.2 + .as_ref().to_vec()) ], ), ethabi::Token::Tuple( @@ -3474,56 +3294,50 @@ } #[derive(Debug, Clone, PartialEq)] pub struct FeesAccumulated { - pub pool_key: ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), + pub pool_id: [u8; 32usize], pub amount0: substreams::scalar::BigInt, pub amount1: substreams::scalar::BigInt, } impl FeesAccumulated { const TOPIC_ID: [u8; 32] = [ - 59u8, - 179u8, - 81u8, - 188u8, - 245u8, - 129u8, - 151u8, - 154u8, - 78u8, - 90u8, - 77u8, - 90u8, - 109u8, - 26u8, - 153u8, - 147u8, + 247u8, + 224u8, + 80u8, + 216u8, + 102u8, + 119u8, + 72u8, 32u8, - 226u8, - 213u8, - 190u8, - 51u8, - 44u8, - 219u8, - 55u8, - 89u8, - 11u8, - 181u8, - 159u8, - 24u8, - 177u8, - 131u8, - 81u8, + 216u8, + 26u8, + 134u8, + 202u8, + 103u8, + 111u8, + 58u8, + 254u8, + 123u8, + 199u8, + 38u8, + 3u8, + 238u8, + 137u8, + 63u8, + 130u8, + 233u8, + 156u8, + 8u8, + 251u8, + 222u8, + 57u8, + 175u8, + 108u8, ]; pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { if log.topics.len() != 1usize { return false; } - if log.data.len() != 224usize { + if log.data.len() != 96usize { return false; } return log.topics.get(0).expect("bounds already checked").as_ref() @@ -3534,13 +3348,7 @@ ) -> Result { let mut values = ethabi::decode( &[ - ethabi::ParamType::Tuple( - vec![ - ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address - ], - ), + ethabi::ParamType::FixedBytes(32usize), ethabi::ParamType::Uint(128usize), ethabi::ParamType::Uint(128usize), ], @@ -3549,50 +3357,15 @@ .map_err(|e| format!("unable to decode log.data: {:?}", e))?; values.reverse(); Ok(Self { - pool_key: { - let tuple_elements = values + pool_id: { + let mut result = [0u8; 32]; + let v = values .pop() .expect(INTERNAL_ERR) - .into_tuple() + .into_fixed_bytes() .expect(INTERNAL_ERR); - ( - tuple_elements[0usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - tuple_elements[1usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] - .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) - }, - tuple_elements[4usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - ) + result.copy_from_slice(&v); + result }, amount0: { let mut v = [0 as u8; 32]; @@ -4011,56 +3784,51 @@ } #[derive(Debug, Clone, PartialEq)] pub struct PoolInitialized { - pub pool_key: ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), + pub pool_id: [u8; 32usize], + pub pool_key: (Vec, Vec, [u8; 32usize]), pub tick: substreams::scalar::BigInt, pub sqrt_ratio: substreams::scalar::BigInt, } impl PoolInitialized { const TOPIC_ID: [u8; 32] = [ + 94u8, + 70u8, + 136u8, + 179u8, + 64u8, + 105u8, + 75u8, + 124u8, + 127u8, + 211u8, + 0u8, + 71u8, + 253u8, + 8u8, + 33u8, + 23u8, + 220u8, + 70u8, + 227u8, + 42u8, 207u8, - 101u8, - 187u8, - 230u8, - 204u8, - 27u8, - 117u8, - 110u8, - 35u8, - 165u8, - 60u8, - 101u8, - 216u8, - 28u8, - 156u8, - 139u8, + 191u8, 129u8, - 25u8, - 165u8, - 237u8, - 70u8, - 89u8, - 163u8, - 252u8, - 38u8, - 96u8, - 145u8, - 117u8, - 6u8, - 56u8, - 231u8, - 221u8, + 164u8, + 75u8, + 177u8, + 250u8, + 192u8, + 174u8, + 101u8, + 21u8, + 77u8, ]; pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { if log.topics.len() != 1usize { return false; } - if log.data.len() != 224usize { + if log.data.len() != 192usize { return false; } return log.topics.get(0).expect("bounds already checked").as_ref() @@ -4071,21 +3839,31 @@ ) -> Result { let mut values = ethabi::decode( &[ + ethabi::ParamType::FixedBytes(32usize), ethabi::ParamType::Tuple( vec![ ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ethabi::ParamType::FixedBytes(32usize) ], ), ethabi::ParamType::Int(32usize), - ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(96usize), ], log.data.as_ref(), ) .map_err(|e| format!("unable to decode log.data: {:?}", e))?; values.reverse(); Ok(Self { + pool_id: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, pool_key: { let tuple_elements = values .pop() @@ -4106,29 +3884,14 @@ .as_bytes() .to_vec(), { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] + let mut result = [0u8; 32]; + let v = tuple_elements[2usize] .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result }, - tuple_elements[4usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), ) }, tick: { @@ -4167,13 +3930,7 @@ } #[derive(Debug, Clone, PartialEq)] pub struct PositionFeesCollected { - pub pool_key: ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), + pub pool_id: [u8; 32usize], pub position_key: ( [u8; 32usize], Vec, @@ -4184,44 +3941,44 @@ } impl PositionFeesCollected { const TOPIC_ID: [u8; 32] = [ - 114u8, - 71u8, - 150u8, - 76u8, - 39u8, - 153u8, - 67u8, - 203u8, - 135u8, - 146u8, - 250u8, - 183u8, 187u8, - 41u8, - 30u8, - 242u8, - 228u8, - 125u8, - 91u8, - 55u8, - 51u8, - 70u8, - 204u8, - 46u8, - 97u8, + 57u8, + 146u8, + 216u8, + 60u8, + 114u8, + 31u8, + 18u8, + 168u8, + 243u8, 34u8, - 84u8, - 183u8, - 7u8, - 55u8, - 67u8, - 233u8, + 66u8, + 224u8, + 210u8, + 28u8, + 54u8, + 19u8, + 148u8, + 156u8, + 106u8, + 105u8, + 210u8, + 163u8, + 93u8, + 238u8, + 205u8, + 246u8, + 148u8, + 58u8, + 97u8, + 200u8, + 178u8, ]; pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { if log.topics.len() != 1usize { return false; } - if log.data.len() != 352usize { + if log.data.len() != 224usize { return false; } return log.topics.get(0).expect("bounds already checked").as_ref() @@ -4232,13 +3989,7 @@ ) -> Result { let mut values = ethabi::decode( &[ - ethabi::ParamType::Tuple( - vec![ - ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address - ], - ), + ethabi::ParamType::FixedBytes(32usize), ethabi::ParamType::Tuple( vec![ ethabi::ParamType::FixedBytes(32usize), @@ -4255,50 +4006,15 @@ .map_err(|e| format!("unable to decode log.data: {:?}", e))?; values.reverse(); Ok(Self { - pool_key: { - let tuple_elements = values + pool_id: { + let mut result = [0u8; 32]; + let v = values .pop() .expect(INTERNAL_ERR) - .into_tuple() + .into_fixed_bytes() .expect(INTERNAL_ERR); - ( - tuple_elements[0usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - tuple_elements[1usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] - .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) - }, - tuple_elements[4usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - ) + result.copy_from_slice(&v); + result }, position_key: { let tuple_elements = values @@ -4387,13 +4103,7 @@ #[derive(Debug, Clone, PartialEq)] pub struct PositionUpdated { pub locker: Vec, - pub pool_key: ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), + pub pool_id: [u8; 32usize], pub params: ( [u8; 32usize], (substreams::scalar::BigInt, substreams::scalar::BigInt), @@ -4404,44 +4114,44 @@ } impl PositionUpdated { const TOPIC_ID: [u8; 32] = [ - 207u8, - 67u8, - 158u8, - 142u8, - 9u8, - 56u8, - 79u8, - 88u8, - 130u8, - 84u8, - 11u8, - 31u8, - 166u8, - 115u8, - 97u8, - 39u8, - 158u8, - 61u8, - 57u8, - 196u8, - 216u8, - 229u8, - 227u8, - 6u8, - 201u8, - 244u8, - 90u8, + 162u8, + 212u8, + 0u8, + 139u8, + 228u8, + 24u8, + 124u8, + 99u8, + 104u8, 79u8, - 227u8, - 94u8, - 192u8, - 191u8, + 50u8, + 55u8, + 136u8, + 225u8, + 49u8, + 225u8, + 55u8, + 13u8, + 188u8, + 34u8, + 5u8, + 73u8, + 155u8, + 239u8, + 226u8, + 131u8, + 64u8, + 5u8, + 160u8, + 12u8, + 121u8, + 44u8, ]; pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { if log.topics.len() != 1usize { return false; } - if log.data.len() != 384usize { + if log.data.len() != 256usize { return false; } return log.topics.get(0).expect("bounds already checked").as_ref() @@ -4453,13 +4163,7 @@ let mut values = ethabi::decode( &[ ethabi::ParamType::Address, - ethabi::ParamType::Tuple( - vec![ - ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address - ], - ), + ethabi::ParamType::FixedBytes(32usize), ethabi::ParamType::Tuple( vec![ ethabi::ParamType::FixedBytes(32usize), @@ -4483,50 +4187,15 @@ .expect(INTERNAL_ERR) .as_bytes() .to_vec(), - pool_key: { - let tuple_elements = values + pool_id: { + let mut result = [0u8; 32]; + let v = values .pop() .expect(INTERNAL_ERR) - .into_tuple() + .into_fixed_bytes() .expect(INTERNAL_ERR); - ( - tuple_elements[0usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - tuple_elements[1usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] - .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) - }, - tuple_elements[4usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - ) + result.copy_from_slice(&v); + result }, params: { let tuple_elements = values @@ -4616,225 +4285,6 @@ } } #[derive(Debug, Clone, PartialEq)] - pub struct ProtocolFeesPaid { - pub pool_key: ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), - pub position_key: ( - [u8; 32usize], - Vec, - (substreams::scalar::BigInt, substreams::scalar::BigInt), - ), - pub amount0: substreams::scalar::BigInt, - pub amount1: substreams::scalar::BigInt, - } - impl ProtocolFeesPaid { - const TOPIC_ID: [u8; 32] = [ - 77u8, - 6u8, - 0u8, - 175u8, - 6u8, - 71u8, - 216u8, - 178u8, - 0u8, - 155u8, - 157u8, - 242u8, - 101u8, - 166u8, - 15u8, - 71u8, - 72u8, - 18u8, - 149u8, - 62u8, - 36u8, - 114u8, - 59u8, - 160u8, - 0u8, - 227u8, - 70u8, - 184u8, - 0u8, - 50u8, - 61u8, - 238u8, - ]; - pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { - if log.topics.len() != 1usize { - return false; - } - if log.data.len() != 352usize { - 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::Tuple( - vec![ - ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address - ], - ), - ethabi::ParamType::Tuple( - vec![ - ethabi::ParamType::FixedBytes(32usize), - ethabi::ParamType::Address, - ethabi::ParamType::Tuple(vec![ethabi::ParamType::Int(32usize), - ethabi::ParamType::Int(32usize)]) - ], - ), - 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 { - pool_key: { - let tuple_elements = values - .pop() - .expect(INTERNAL_ERR) - .into_tuple() - .expect(INTERNAL_ERR); - ( - tuple_elements[0usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - tuple_elements[1usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] - .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) - }, - tuple_elements[4usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - ) - }, - position_key: { - let tuple_elements = values - .pop() - .expect(INTERNAL_ERR) - .into_tuple() - .expect(INTERNAL_ERR); - ( - { - let mut result = [0u8; 32]; - let v = tuple_elements[0usize] - .clone() - .into_fixed_bytes() - .expect(INTERNAL_ERR); - result.copy_from_slice(&v); - result - }, - tuple_elements[1usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - { - let tuple_elements = tuple_elements[2usize] - .clone() - .into_tuple() - .expect(INTERNAL_ERR); - ( - { - let mut v = [0 as u8; 32]; - tuple_elements[0usize] - .clone() - .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]; - tuple_elements[1usize] - .clone() - .into_int() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_signed_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 ProtocolFeesPaid { - const NAME: &'static str = "ProtocolFeesPaid"; - 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 ProtocolFeesWithdrawn { pub recipient: Vec, pub token: Vec, @@ -5052,258 +4502,4 @@ Self::decode(log) } } - #[derive(Debug, Clone, PartialEq)] - pub struct Swapped { - pub locker: Vec, - pub pool_key: ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), - pub params: ( - substreams::scalar::BigInt, - bool, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - ), - pub delta0: substreams::scalar::BigInt, - pub delta1: substreams::scalar::BigInt, - pub sqrt_ratio_after: substreams::scalar::BigInt, - pub tick_after: substreams::scalar::BigInt, - pub liquidity_after: substreams::scalar::BigInt, - } - impl Swapped { - const TOPIC_ID: [u8; 32] = [ - 21u8, - 3u8, - 18u8, - 134u8, - 146u8, - 8u8, - 74u8, - 3u8, - 167u8, - 33u8, - 144u8, - 144u8, - 135u8, - 236u8, - 34u8, - 229u8, - 231u8, - 1u8, - 88u8, - 58u8, - 81u8, - 189u8, - 162u8, - 125u8, - 45u8, - 35u8, - 14u8, - 67u8, - 98u8, - 69u8, - 198u8, - 160u8, - ]; - pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { - if log.topics.len() != 1usize { - return false; - } - if log.data.len() != 480usize { - 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::Tuple( - vec![ - ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address - ], - ), - ethabi::ParamType::Tuple( - vec![ - ethabi::ParamType::Int(128usize), ethabi::ParamType::Bool, - ethabi::ParamType::Uint(256usize), - ethabi::ParamType::Uint(256usize) - ], - ), - ethabi::ParamType::Int(128usize), - ethabi::ParamType::Int(128usize), - ethabi::ParamType::Uint(256usize), - ethabi::ParamType::Int(32usize), - ethabi::ParamType::Uint(128usize), - ], - log.data.as_ref(), - ) - .map_err(|e| format!("unable to decode log.data: {:?}", e))?; - values.reverse(); - Ok(Self { - locker: values - .pop() - .expect(INTERNAL_ERR) - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - pool_key: { - let tuple_elements = values - .pop() - .expect(INTERNAL_ERR) - .into_tuple() - .expect(INTERNAL_ERR); - ( - tuple_elements[0usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - tuple_elements[1usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] - .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) - }, - tuple_elements[4usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - ) - }, - params: { - let tuple_elements = values - .pop() - .expect(INTERNAL_ERR) - .into_tuple() - .expect(INTERNAL_ERR); - ( - { - let mut v = [0 as u8; 32]; - tuple_elements[0usize] - .clone() - .into_int() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_signed_bytes_be(&v) - }, - tuple_elements[1usize] - .clone() - .into_bool() - .expect(INTERNAL_ERR), - { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] - .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) - }, - ) - }, - delta0: { - 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) - }, - delta1: { - 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_ratio_after: { - 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_after: { - 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) - }, - liquidity_after: { - 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 Swapped { - const NAME: &'static str = "Swapped"; - 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-ekubo/src/abi/oracle.rs b/substreams/ethereum-ekubo/src/abi/oracle.rs index 17f68b388..f6f6a3d30 100644 --- a/substreams/ethereum-ekubo/src/abi/oracle.rs +++ b/substreams/ethereum-ekubo/src/abi/oracle.rs @@ -6,20 +6,14 @@ #[derive(Debug, Clone, PartialEq)] pub struct AfterCollectFees { pub param0: Vec, - pub param1: ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), + pub param1: (Vec, Vec, [u8; 32usize]), pub param2: [u8; 32usize], pub param3: (substreams::scalar::BigInt, substreams::scalar::BigInt), pub param4: substreams::scalar::BigInt, pub param5: substreams::scalar::BigInt, } impl AfterCollectFees { - const METHOD_ID: [u8; 4] = [167u8, 70u8, 163u8, 111u8]; + const METHOD_ID: [u8; 4] = [205u8, 208u8, 250u8, 14u8]; pub fn decode( call: &substreams_ethereum::pb::eth::v2::Call, ) -> Result { @@ -33,8 +27,7 @@ ethabi::ParamType::Tuple( vec![ ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ethabi::ParamType::FixedBytes(32usize) ], ), ethabi::ParamType::FixedBytes(32usize), @@ -79,29 +72,14 @@ .as_bytes() .to_vec(), { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] + let mut result = [0u8; 32]; + let v = tuple_elements[2usize] .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result }, - tuple_elements[4usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), ) }, param2: { @@ -174,21 +152,8 @@ ethabi::Token::Address(ethabi::Address::from_slice(& self .param1.0)), ethabi::Token::Address(ethabi::Address::from_slice(& self - .param1.1)), - ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self - .param1.2.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 - .param1.3.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::Address(ethabi::Address::from_slice(& self - .param1.4)) + .param1.1)), ethabi::Token::FixedBytes(self.param1.2 + .as_ref().to_vec()) ], ), ethabi::Token::FixedBytes(self.param2.as_ref().to_vec()), @@ -266,18 +231,12 @@ #[derive(Debug, Clone, PartialEq)] pub struct AfterInitializePool { pub param0: Vec, - pub param1: ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), + pub param1: (Vec, Vec, [u8; 32usize]), pub param2: substreams::scalar::BigInt, pub param3: substreams::scalar::BigInt, } impl AfterInitializePool { - const METHOD_ID: [u8; 4] = [236u8, 55u8, 17u8, 245u8]; + const METHOD_ID: [u8; 4] = [148u8, 131u8, 116u8, 255u8]; pub fn decode( call: &substreams_ethereum::pb::eth::v2::Call, ) -> Result { @@ -291,12 +250,11 @@ ethabi::ParamType::Tuple( vec![ ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ethabi::ParamType::FixedBytes(32usize) ], ), ethabi::ParamType::Int(32usize), - ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(96usize), ], maybe_data.unwrap(), ) @@ -330,29 +288,14 @@ .as_bytes() .to_vec(), { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] + let mut result = [0u8; 32]; + let v = tuple_elements[2usize] .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result }, - tuple_elements[4usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), ) }, param2: { @@ -388,21 +331,8 @@ ethabi::Token::Address(ethabi::Address::from_slice(& self .param1.0)), ethabi::Token::Address(ethabi::Address::from_slice(& self - .param1.1)), - ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self - .param1.2.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 - .param1.3.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::Address(ethabi::Address::from_slice(& self - .param1.4)) + .param1.1)), ethabi::Token::FixedBytes(self.param1.2 + .as_ref().to_vec()) ], ), { @@ -468,13 +398,7 @@ #[derive(Debug, Clone, PartialEq)] pub struct AfterSwap { pub param0: Vec, - pub param1: ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), + pub param1: (Vec, Vec, [u8; 32usize]), pub param2: ( substreams::scalar::BigInt, bool, @@ -485,7 +409,7 @@ pub param4: substreams::scalar::BigInt, } impl AfterSwap { - const METHOD_ID: [u8; 4] = [50u8, 150u8, 96u8, 155u8]; + const METHOD_ID: [u8; 4] = [189u8, 255u8, 60u8, 4u8]; pub fn decode( call: &substreams_ethereum::pb::eth::v2::Call, ) -> Result { @@ -499,14 +423,13 @@ ethabi::ParamType::Tuple( vec![ ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ethabi::ParamType::FixedBytes(32usize) ], ), ethabi::ParamType::Tuple( vec![ ethabi::ParamType::Int(128usize), ethabi::ParamType::Bool, - ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(96usize), ethabi::ParamType::Uint(256usize) ], ), @@ -545,29 +468,14 @@ .as_bytes() .to_vec(), { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] + let mut result = [0u8; 32]; + let v = tuple_elements[2usize] .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result }, - tuple_elements[4usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), ) }, param2: { @@ -643,21 +551,8 @@ ethabi::Token::Address(ethabi::Address::from_slice(& self .param1.0)), ethabi::Token::Address(ethabi::Address::from_slice(& self - .param1.1)), - ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self - .param1.2.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 - .param1.3.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::Address(ethabi::Address::from_slice(& self - .param1.4)) + .param1.1)), ethabi::Token::FixedBytes(self.param1.2 + .as_ref().to_vec()) ], ), ethabi::Token::Tuple( @@ -755,13 +650,7 @@ #[derive(Debug, Clone, PartialEq)] pub struct AfterUpdatePosition { pub param0: Vec, - pub param1: ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), + pub param1: (Vec, Vec, [u8; 32usize]), pub param2: ( [u8; 32usize], (substreams::scalar::BigInt, substreams::scalar::BigInt), @@ -771,7 +660,7 @@ pub param4: substreams::scalar::BigInt, } impl AfterUpdatePosition { - const METHOD_ID: [u8; 4] = [106u8, 243u8, 56u8, 139u8]; + const METHOD_ID: [u8; 4] = [60u8, 133u8, 229u8, 161u8]; pub fn decode( call: &substreams_ethereum::pb::eth::v2::Call, ) -> Result { @@ -785,8 +674,7 @@ ethabi::ParamType::Tuple( vec![ ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ethabi::ParamType::FixedBytes(32usize) ], ), ethabi::ParamType::Tuple( @@ -832,29 +720,14 @@ .as_bytes() .to_vec(), { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] + let mut result = [0u8; 32]; + let v = tuple_elements[2usize] .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result }, - tuple_elements[4usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), ) }, param2: { @@ -943,21 +816,8 @@ ethabi::Token::Address(ethabi::Address::from_slice(& self .param1.0)), ethabi::Token::Address(ethabi::Address::from_slice(& self - .param1.1)), - ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self - .param1.2.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 - .param1.3.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::Address(ethabi::Address::from_slice(& self - .param1.4)) + .param1.1)), ethabi::Token::FixedBytes(self.param1.2 + .as_ref().to_vec()) ], ), ethabi::Token::Tuple( @@ -1059,18 +919,12 @@ #[derive(Debug, Clone, PartialEq)] pub struct BeforeCollectFees { pub param0: Vec, - pub param1: ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), + pub param1: (Vec, Vec, [u8; 32usize]), pub param2: [u8; 32usize], pub param3: (substreams::scalar::BigInt, substreams::scalar::BigInt), } impl BeforeCollectFees { - const METHOD_ID: [u8; 4] = [200u8, 130u8, 64u8, 21u8]; + const METHOD_ID: [u8; 4] = [111u8, 181u8, 191u8, 227u8]; pub fn decode( call: &substreams_ethereum::pb::eth::v2::Call, ) -> Result { @@ -1084,8 +938,7 @@ ethabi::ParamType::Tuple( vec![ ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ethabi::ParamType::FixedBytes(32usize) ], ), ethabi::ParamType::FixedBytes(32usize), @@ -1128,29 +981,14 @@ .as_bytes() .to_vec(), { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] + let mut result = [0u8; 32]; + let v = tuple_elements[2usize] .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result }, - tuple_elements[4usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), ) }, param2: { @@ -1203,21 +1041,8 @@ ethabi::Token::Address(ethabi::Address::from_slice(& self .param1.0)), ethabi::Token::Address(ethabi::Address::from_slice(& self - .param1.1)), - ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self - .param1.2.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 - .param1.3.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::Address(ethabi::Address::from_slice(& self - .param1.4)) + .param1.1)), ethabi::Token::FixedBytes(self.param1.2 + .as_ref().to_vec()) ], ), ethabi::Token::FixedBytes(self.param2.as_ref().to_vec()), @@ -1271,17 +1096,11 @@ #[derive(Debug, Clone, PartialEq)] pub struct BeforeInitializePool { pub param0: Vec, - pub key: ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), + pub key: (Vec, Vec, [u8; 32usize]), pub param2: substreams::scalar::BigInt, } impl BeforeInitializePool { - const METHOD_ID: [u8; 4] = [158u8, 63u8, 119u8, 38u8]; + const METHOD_ID: [u8; 4] = [31u8, 187u8, 180u8, 98u8]; pub fn decode( call: &substreams_ethereum::pb::eth::v2::Call, ) -> Result { @@ -1295,8 +1114,7 @@ ethabi::ParamType::Tuple( vec![ ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ethabi::ParamType::FixedBytes(32usize) ], ), ethabi::ParamType::Int(32usize), @@ -1333,29 +1151,14 @@ .as_bytes() .to_vec(), { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] + let mut result = [0u8; 32]; + let v = tuple_elements[2usize] .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result }, - tuple_elements[4usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), ) }, param2: { @@ -1381,21 +1184,8 @@ ethabi::Token::Address(ethabi::Address::from_slice(& self .key.0)), ethabi::Token::Address(ethabi::Address::from_slice(& self - .key.1)), - ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self - .key.2.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 - .key.3.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::Address(ethabi::Address::from_slice(& self - .key.4)) + .key.1)), ethabi::Token::FixedBytes(self.key.2.as_ref() + .to_vec()) ], ), { @@ -1449,13 +1239,7 @@ #[derive(Debug, Clone, PartialEq)] pub struct BeforeSwap { pub param0: Vec, - pub pool_key: ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), + pub pool_key: (Vec, Vec, [u8; 32usize]), pub params: ( substreams::scalar::BigInt, bool, @@ -1464,7 +1248,7 @@ ), } impl BeforeSwap { - const METHOD_ID: [u8; 4] = [8u8, 17u8, 38u8, 31u8]; + const METHOD_ID: [u8; 4] = [62u8, 6u8, 223u8, 54u8]; pub fn decode( call: &substreams_ethereum::pb::eth::v2::Call, ) -> Result { @@ -1478,14 +1262,13 @@ ethabi::ParamType::Tuple( vec![ ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ethabi::ParamType::FixedBytes(32usize) ], ), ethabi::ParamType::Tuple( vec![ ethabi::ParamType::Int(128usize), ethabi::ParamType::Bool, - ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(96usize), ethabi::ParamType::Uint(256usize) ], ), @@ -1522,29 +1305,14 @@ .as_bytes() .to_vec(), { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] + let mut result = [0u8; 32]; + let v = tuple_elements[2usize] .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result }, - { - let mut v = [0 as u8; 32]; - tuple_elements[3usize] - .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) - }, - tuple_elements[4usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), ) }, params: { @@ -1600,21 +1368,8 @@ ethabi::Token::Address(ethabi::Address::from_slice(& self .pool_key.0)), ethabi::Token::Address(ethabi::Address::from_slice(& self - .pool_key.1)), - ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self - .pool_key.2.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 - .pool_key.3.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::Address(ethabi::Address::from_slice(& self - .pool_key.4)) + .pool_key.1)), ethabi::Token::FixedBytes(self.pool_key.2 + .as_ref().to_vec()) ], ), ethabi::Token::Tuple( @@ -1672,13 +1427,7 @@ #[derive(Debug, Clone, PartialEq)] pub struct BeforeUpdatePosition { pub param0: Vec, - pub pool_key: ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), + pub pool_key: (Vec, Vec, [u8; 32usize]), pub params: ( [u8; 32usize], (substreams::scalar::BigInt, substreams::scalar::BigInt), @@ -1686,7 +1435,7 @@ ), } impl BeforeUpdatePosition { - const METHOD_ID: [u8; 4] = [12u8, 182u8, 178u8, 21u8]; + const METHOD_ID: [u8; 4] = [177u8, 75u8, 16u8, 109u8]; pub fn decode( call: &substreams_ethereum::pb::eth::v2::Call, ) -> Result { @@ -1700,8 +1449,7 @@ ethabi::ParamType::Tuple( vec![ ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address + ethabi::ParamType::FixedBytes(32usize) ], ), ethabi::ParamType::Tuple( @@ -1745,29 +1493,14 @@ .as_bytes() .to_vec(), { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] + let mut result = [0u8; 32]; + let v = tuple_elements[2usize] .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result }, - tuple_elements[4usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), ) }, params: { @@ -1836,21 +1569,8 @@ ethabi::Token::Address(ethabi::Address::from_slice(& self .pool_key.0)), ethabi::Token::Address(ethabi::Address::from_slice(& self - .pool_key.1)), - ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self - .pool_key.2.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 - .pool_key.3.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::Address(ethabi::Address::from_slice(& self - .pool_key.4)) + .pool_key.1)), ethabi::Token::FixedBytes(self.pool_key.2 + .as_ref().to_vec()) ], ), ethabi::Token::Tuple( @@ -1895,8 +1615,319 @@ } } } - impl substreams_ethereum::Function for BeforeUpdatePosition { - const NAME: &'static str = "beforeUpdatePosition"; + impl substreams_ethereum::Function for BeforeUpdatePosition { + const NAME: &'static str = "beforeUpdatePosition"; + 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 Counts { + pub token: Vec, + } + impl Counts { + const METHOD_ID: [u8; 4] = [5u8, 104u8, 230u8, 94u8]; + 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 { + token: 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.token))], + ); + 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::Uint(64usize), + ethabi::ParamType::Uint(64usize), + ethabi::ParamType::Uint(64usize), + ], + 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) + }, + )) + } + 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 Counts { + const NAME: &'static str = "counts"; + 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 Counts { + fn output( + data: &[u8], + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct ExpandCapacity { + pub token: Vec, + pub min_capacity: substreams::scalar::BigInt, + } + impl ExpandCapacity { + const METHOD_ID: [u8; 4] = [3u8, 90u8, 143u8, 4u8]; + 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(64usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + min_capacity: { + 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)), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.min_capacity.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::Uint(64usize)], + 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 ExpandCapacity { + const NAME: &'static str = "expandCapacity"; fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { Self::match_call(call) } @@ -1909,6 +1940,12 @@ self.encode() } } + impl substreams_ethereum::rpc::RPCDecodable + for ExpandCapacity { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } #[derive(Debug, Clone, PartialEq)] pub struct ExtrapolateSnapshot { pub token: Vec, @@ -2532,232 +2569,49 @@ } impl substreams_ethereum::rpc::RPCDecodable< Vec<(substreams::scalar::BigInt, substreams::scalar::BigInt)>, - > for GetExtrapolatedSnapshotsForSortedTimestamps { - fn output( - data: &[u8], - ) -> Result< - Vec<(substreams::scalar::BigInt, substreams::scalar::BigInt)>, - String, - > { - Self::output(data) - } - } - #[derive(Debug, Clone, PartialEq)] - pub struct GetPoolKey { - pub token: Vec, - } - impl GetPoolKey { - const METHOD_ID: [u8; 4] = [110u8, 127u8, 253u8, 75u8]; - 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 { - token: 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.token))], - ); - 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, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), - String, - > { - Self::output(call.return_data.as_ref()) - } - pub fn output( - data: &[u8], - ) -> Result< - ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), - String, - > { - let mut values = ethabi::decode( - &[ - ethabi::ParamType::Tuple( - vec![ - ethabi::ParamType::Address, ethabi::ParamType::Address, - ethabi::ParamType::Uint(128usize), - ethabi::ParamType::Uint(32usize), ethabi::ParamType::Address - ], - ), - ], - data.as_ref(), - ) - .map_err(|e| format!("unable to decode output data: {:?}", e))?; - Ok({ - let tuple_elements = values - .pop() - .expect("one output data should have existed") - .into_tuple() - .expect(INTERNAL_ERR); - ( - tuple_elements[0usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - tuple_elements[1usize] - .clone() - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - { - let mut v = [0 as u8; 32]; - tuple_elements[2usize] - .clone() - .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]; - tuple_elements[3usize] - .clone() - .into_uint() - .expect(INTERNAL_ERR) - .to_big_endian(v.as_mut_slice()); - substreams::scalar::BigInt::from_unsigned_bytes_be(&v) - }, - tuple_elements[4usize] - .clone() - .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< - ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - 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 GetPoolKey { - const NAME: &'static str = "getPoolKey"; - 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, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), - > for GetPoolKey { + > for GetExtrapolatedSnapshotsForSortedTimestamps { fn output( data: &[u8], ) -> Result< - ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, - ), + Vec<(substreams::scalar::BigInt, substreams::scalar::BigInt)>, String, > { Self::output(data) } } #[derive(Debug, Clone, PartialEq)] - pub struct OracleToken {} - impl OracleToken { - const METHOD_ID: [u8; 4] = [131u8, 71u8, 47u8, 207u8]; + pub struct GetPoolKey { + pub token: Vec, + } + impl GetPoolKey { + const METHOD_ID: [u8; 4] = [110u8, 127u8, 253u8, 75u8]; pub fn decode( call: &substreams_ethereum::pb::eth::v2::Call, ) -> Result { - Ok(Self {}) + 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 { + token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) } pub fn encode(&self) -> Vec { - let data = ethabi::encode(&[]); + let data = ethabi::encode( + &[ethabi::Token::Address(ethabi::Address::from_slice(&self.token))], + ); let mut encoded = Vec::with_capacity(4 + data.len()); encoded.extend(Self::METHOD_ID); encoded.extend(data); @@ -2765,24 +2619,54 @@ } pub fn output_call( call: &substreams_ethereum::pb::eth::v2::Call, - ) -> Result, String> { + ) -> Result<(Vec, Vec, [u8; 32usize]), String> { Self::output(call.return_data.as_ref()) } - pub fn output(data: &[u8]) -> Result, String> { + pub fn output( + data: &[u8], + ) -> Result<(Vec, Vec, [u8; 32usize]), String> { let mut values = ethabi::decode( - &[ethabi::ParamType::Address], + &[ + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::FixedBytes(32usize) + ], + ), + ], data.as_ref(), ) .map_err(|e| format!("unable to decode output data: {:?}", e))?; - Ok( - values + Ok({ + let tuple_elements = values .pop() .expect("one output data should have existed") - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - ) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut result = [0u8; 32]; + let v = tuple_elements[2usize] + .clone() + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + ) + }) } pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { match call.input.get(0..4) { @@ -2790,7 +2674,10 @@ None => false, } } - pub fn call(&self, address: Vec) -> Option> { + pub fn call( + &self, + address: Vec, + ) -> Option<(Vec, Vec, [u8; 32usize])> { use substreams_ethereum::pb::eth::rpc; let rpc_calls = rpc::RpcCalls { calls: vec![ @@ -2817,8 +2704,8 @@ } } } - impl substreams_ethereum::Function for OracleToken { - const NAME: &'static str = "oracleToken"; + impl substreams_ethereum::Function for GetPoolKey { + const NAME: &'static str = "getPoolKey"; fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { Self::match_call(call) } @@ -2831,8 +2718,9 @@ self.encode() } } - impl substreams_ethereum::rpc::RPCDecodable> for OracleToken { - fn output(data: &[u8]) -> Result, String> { + impl substreams_ethereum::rpc::RPCDecodable<(Vec, Vec, [u8; 32usize])> + for GetPoolKey { + fn output(data: &[u8]) -> Result<(Vec, Vec, [u8; 32usize]), String> { Self::output(data) } } @@ -3172,119 +3060,6 @@ } } #[derive(Debug, Clone, PartialEq)] - pub struct SnapshotCount { - pub token: Vec, - } - impl SnapshotCount { - const METHOD_ID: [u8; 4] = [212u8, 3u8, 32u8, 174u8]; - 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 { - token: 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.token))], - ); - 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 SnapshotCount { - const NAME: &'static str = "snapshotCount"; - 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 SnapshotCount { - fn output(data: &[u8]) -> Result { - Self::output(data) - } - } - #[derive(Debug, Clone, PartialEq)] pub struct Snapshots { pub token: Vec, pub index: substreams::scalar::BigInt, @@ -3699,134 +3474,4 @@ #[allow(dead_code, unused_imports, unused_variables)] pub mod events { use super::INTERNAL_ERR; - #[derive(Debug, Clone, PartialEq)] - pub struct SnapshotEvent { - pub token: Vec, - pub index: substreams::scalar::BigInt, - pub timestamp: substreams::scalar::BigInt, - pub seconds_per_liquidity_cumulative: substreams::scalar::BigInt, - pub tick_cumulative: substreams::scalar::BigInt, - } - impl SnapshotEvent { - const TOPIC_ID: [u8; 32] = [ - 84u8, - 1u8, - 11u8, - 213u8, - 93u8, - 37u8, - 184u8, - 58u8, - 113u8, - 51u8, - 193u8, - 29u8, - 139u8, - 54u8, - 217u8, - 240u8, - 51u8, - 149u8, - 163u8, - 147u8, - 220u8, - 224u8, - 31u8, - 115u8, - 117u8, - 177u8, - 191u8, - 40u8, - 225u8, - 75u8, - 240u8, - 109u8, - ]; - pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { - if log.topics.len() != 1usize { - 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::Address, - ethabi::ParamType::Uint(256usize), - ethabi::ParamType::Uint(64usize), - ethabi::ParamType::Uint(160usize), - ethabi::ParamType::Int(64usize), - ], - log.data.as_ref(), - ) - .map_err(|e| format!("unable to decode log.data: {:?}", e))?; - values.reverse(); - Ok(Self { - token: values - .pop() - .expect(INTERNAL_ERR) - .into_address() - .expect(INTERNAL_ERR) - .as_bytes() - .to_vec(), - 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) - }, - timestamp: { - 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) - }, - seconds_per_liquidity_cumulative: { - 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_cumulative: { - 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 SnapshotEvent { - const NAME: &'static str = "SnapshotEvent"; - 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-ekubo/src/identifiers.rs b/substreams/ethereum-ekubo/src/identifiers.rs new file mode 100644 index 000000000..00d542b5d --- /dev/null +++ b/substreams/ethereum-ekubo/src/identifiers.rs @@ -0,0 +1,35 @@ +pub fn pool_id_to_component_id>(pool_id: T) -> String { + format!("0x{}", hex::encode(pool_id)) +} + +pub struct PoolConfig { + pub fee: Vec, + pub tick_spacing: Vec, + pub extension: Vec, +} + +impl From<[u8; 32]> for PoolConfig { + fn from(value: [u8; 32]) -> Self { + Self { + tick_spacing: value[28..32].into(), + fee: value[20..28].into(), + extension: value[..20].into(), + } + } +} + +pub struct PoolKey { + pub token0: Vec, + pub token1: Vec, + pub config: PoolConfig, +} + +impl From<(Vec, Vec, [u8; 32])> for PoolKey { + fn from(value: (Vec, Vec, [u8; 32])) -> Self { + Self { + token0: value.0, + token1: value.1, + config: value.2.into(), + } + } +} diff --git a/substreams/ethereum-ekubo/src/lib.rs b/substreams/ethereum-ekubo/src/lib.rs index 83bc58617..d979c6cc1 100644 --- a/substreams/ethereum-ekubo/src/lib.rs +++ b/substreams/ethereum-ekubo/src/lib.rs @@ -1,4 +1,5 @@ mod abi; mod pool_factories; mod modules; - +mod identifiers; +mod pb; diff --git a/substreams/ethereum-ekubo/src/modules.rs b/substreams/ethereum-ekubo/src/modules.rs index 7c436bc94..c626faed0 100644 --- a/substreams/ethereum-ekubo/src/modules.rs +++ b/substreams/ethereum-ekubo/src/modules.rs @@ -1,8 +1,5 @@ -//! Template for Protocols with singleton contract -//! -//! use std::collections::HashMap; -use anyhow::Result; +use anyhow::{ensure, Context, Result}; use substreams::pb::substreams::StoreDeltas; use substreams::prelude::*; use substreams_ethereum::Event; @@ -12,8 +9,10 @@ use tycho_substreams::contract::extract_contract_changes_builder; use tycho_substreams::prelude::*; use itertools::Itertools; use substreams::hex; +use crate::identifiers::pool_id_to_component_id; +use crate::pb::ekubo::PoolDetails; use crate::pool_factories; -use crate::pool_factories::{hash_pool_key, DeploymentConfig}; +use crate::pool_factories::DeploymentConfig; use crate::abi::core::events as core_events; /// Find and create all relevant protocol components @@ -40,124 +39,168 @@ fn map_protocol_components( &config, ) }) - .collect::>(); + .collect_vec(); - if !components.is_empty() { - Some(TransactionProtocolComponents { tx: Some(tx.into()), components }) - } else { - None - } + (!components.is_empty()).then(|| TransactionProtocolComponents { tx: Some(tx.into()), components }) }) - .collect::>(), + .collect_vec(), }) } +#[substreams::handlers::store] +fn store_pool_details(components: BlockTransactionProtocolComponents, store: StoreSetProto) { + let components = components + .tx_components + .into_iter() + .flat_map(|comp| comp.components); + + for component in components { + let attrs = component.static_att; + + let pool_details = PoolDetails { + token0: attrs[0].value.clone(), + token1: attrs[1].value.clone(), + fee: u64::from_be_bytes(attrs[2].value.clone().try_into().unwrap()), + }; + + store.set(0, component.id, &pool_details); + } +} + /// Extracts balance changes per component /// /// Indexes balance changes according to Ekubo core events. #[substreams::handlers::map] -fn map_relative_component_balance(params: String, block: eth::v2::Block) -> Result { +fn map_relative_component_balance(params: String, block: eth::v2::Block, store: StoreGetProto) -> Result { let config: DeploymentConfig = serde_qs::from_str(params.as_str())?; let res = block .transactions() - .flat_map(|tx| { - tx.logs_with_calls() + .map(|tx| { + tx + .logs_with_calls() .map(|(log, _)| { if log.address != config.core { - return vec![]; + return Ok(vec![]); } - if let Some(ev) = core_events::PositionUpdated::match_and_decode(log) { - let pool_id = hash_pool_key(&ev.pool_key); + + Ok(if let Some(ev) = core_events::PositionUpdated::match_and_decode(log) { + let component_id = pool_id_to_component_id(ev.pool_id); + let pool_details = get_pool_details(&store, &component_id)?; vec![ BalanceDelta { ord: log.ordinal, tx: Some(tx.into()), - token: ev.pool_key.0.clone(), - delta: adjust_delta_by_fee(&ev.delta0, &ev.pool_key.3).to_signed_bytes_be(), - component_id: pool_id.clone().into(), + token: pool_details.token0, + delta: adjust_delta_by_fee(ev.delta0, pool_details.fee).to_signed_bytes_be(), + component_id: component_id.clone().into(), }, BalanceDelta { ord: log.ordinal, tx: Some(tx.into()), - token: ev.pool_key.1.clone(), - delta: adjust_delta_by_fee(&ev.delta1, &ev.pool_key.3).to_signed_bytes_be(), - component_id: pool_id.into(), + token: pool_details.token1, + delta: adjust_delta_by_fee(ev.delta1, pool_details.fee).to_signed_bytes_be(), + component_id: component_id.into(), } ] } else if let Some(ev) = core_events::PositionFeesCollected::match_and_decode(log) { - let pool_id = hash_pool_key(&ev.pool_key); + let component_id = pool_id_to_component_id(ev.pool_id); + let pool_details = get_pool_details(&store, &component_id)?; vec![ BalanceDelta { ord: log.ordinal, tx: Some(tx.into()), - token: ev.pool_key.0.clone(), + token: pool_details.token0, delta: ev.amount0.neg().to_signed_bytes_be(), - component_id: pool_id.clone().into(), + component_id: ev.pool_id.into(), }, BalanceDelta { ord: log.ordinal, tx: Some(tx.into()), - token: ev.pool_key.1.clone(), + token: pool_details.token1, delta: ev.amount1.neg().to_signed_bytes_be(), - component_id: pool_id.into(), + component_id: component_id.into(), } ] - } else if let Some(ev) = core_events::Swapped::match_and_decode(log) { - let pool_id = hash_pool_key(&ev.pool_key); + } else if let Some(ev) = core_events::FeesAccumulated::match_and_decode(log) { + let component_id = pool_id_to_component_id(ev.pool_id); + let pool_details = get_pool_details(&store, &component_id)?; + vec![ BalanceDelta { ord: log.ordinal, tx: Some(tx.into()), - token: ev.pool_key.0.clone(), - delta: ev.delta0.to_signed_bytes_be(), - component_id: pool_id.clone().into(), + token: pool_details.token0, + delta: ev.amount0.to_signed_bytes_be(), + component_id: component_id.clone().into(), }, BalanceDelta { ord: log.ordinal, tx: Some(tx.into()), - token: ev.pool_key.1.clone(), - delta: &ev.delta1.to_signed_bytes_be(), - component_id: pool_id.into(), + token: pool_details.token1, + delta: ev.amount1.to_signed_bytes_be(), + component_id: component_id.into(), } ] - } else if let Some(ev) = core_events::FeesAccumulated::match_and_decode(log) { - let pool_id = hash_pool_key(&ev.pool_key); + } else if log.topics.is_empty() { + let data = &log.data; + + ensure!(data.len() == 116, "swapped event data length mismatch"); + + let component_id = pool_id_to_component_id(&data[20..52]); + let (delta0, delta1) = ( + i128::from_be_bytes(data[52..68].try_into().unwrap()), + i128::from_be_bytes(data[68..84].try_into().unwrap()), + ); + + let pool_details = get_pool_details(&store, &component_id)?; + vec![ BalanceDelta { ord: log.ordinal, tx: Some(tx.into()), - token: ev.pool_key.0.clone(), - delta: ev.amount0.to_signed_bytes_be(), - component_id: pool_id.clone().into(), + token: pool_details.token0, + delta: delta0.to_be_bytes().into(), + component_id: component_id.clone().into(), }, BalanceDelta { ord: log.ordinal, tx: Some(tx.into()), - token: ev.pool_key.1.clone(), - delta: ev.amount1.to_signed_bytes_be(), - component_id: pool_id.into(), + token: pool_details.token1, + delta: delta1.to_be_bytes().into(), + component_id: component_id.into(), } ] } else { vec![] - } + }) }) + .try_collect() + .with_context(|| format!("handling tx {}", hex::encode(&tx.hash))) }) + .collect::>>>>()? + .into_iter() + .flatten() .flatten() - .collect::>(); + .collect(); Ok(BlockBalanceDeltas { balance_deltas: res }) } +fn get_pool_details(store: &StoreGetProto, component_id: &str) -> Result { + store + .get_at(0, component_id) + .context("pool id should exist in store") +} + -fn adjust_delta_by_fee(delta: &BigInt, fee: &BigInt) -> BigInt { - if delta < &BigInt::zero() { +fn adjust_delta_by_fee(delta: BigInt, fee: u64) -> BigInt { + if delta < BigInt::zero() { let denom = BigInt::from_signed_bytes_be(&hex!("0100000000000000000000000000000000")); (delta * denom.clone()) / (denom - fee) } else { - delta.clone() + delta } } @@ -250,4 +293,4 @@ fn map_protocol_changes( .filter_map(|(_, builder)| builder.build()) .collect::>(), }) -} \ No newline at end of file +} diff --git a/substreams/ethereum-ekubo/src/pb/ekubo.rs b/substreams/ethereum-ekubo/src/pb/ekubo.rs new file mode 100644 index 000000000..faed0db83 --- /dev/null +++ b/substreams/ethereum-ekubo/src/pb/ekubo.rs @@ -0,0 +1,12 @@ +// @generated +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PoolDetails { + #[prost(bytes="vec", tag="1")] + pub token0: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="2")] + pub token1: ::prost::alloc::vec::Vec, + #[prost(fixed64, tag="3")] + pub fee: u64, +} +// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-ekubo/src/pb/mod.rs b/substreams/ethereum-ekubo/src/pb/mod.rs index a231da221..64dbbe3f1 100644 --- a/substreams/ethereum-ekubo/src/pb/mod.rs +++ b/substreams/ethereum-ekubo/src/pb/mod.rs @@ -1,45 +1,8 @@ // @generated -pub mod google { - // @@protoc_insertion_point(attribute:google.protobuf) - pub mod protobuf { - include!("google.protobuf.rs"); - // @@protoc_insertion_point(google.protobuf) - } -} -pub mod sf { - // @@protoc_insertion_point(attribute:sf.substreams) - pub mod substreams { - include!("sf.substreams.rs"); - // @@protoc_insertion_point(sf.substreams) - pub mod index { - // @@protoc_insertion_point(attribute:sf.substreams.index.v1) - pub mod v1 { - include!("sf.substreams.index.v1.rs"); - // @@protoc_insertion_point(sf.substreams.index.v1) - } - } - pub mod rpc { - // @@protoc_insertion_point(attribute:sf.substreams.rpc.v2) - pub mod v2 { - include!("sf.substreams.rpc.v2.rs"); - // @@protoc_insertion_point(sf.substreams.rpc.v2) - } - } - pub mod sink { - pub mod service { - // @@protoc_insertion_point(attribute:sf.substreams.sink.service.v1) - pub mod v1 { - include!("sf.substreams.sink.service.v1.rs"); - // @@protoc_insertion_point(sf.substreams.sink.service.v1) - } - } - } - // @@protoc_insertion_point(attribute:sf.substreams.v1) - pub mod v1 { - include!("sf.substreams.v1.rs"); - // @@protoc_insertion_point(sf.substreams.v1) - } - } +// @@protoc_insertion_point(attribute:ekubo) +pub mod ekubo { + include!("ekubo.rs"); + // @@protoc_insertion_point(ekubo) } pub mod tycho { pub mod evm { diff --git a/substreams/ethereum-ekubo/src/pb/sf.substreams.index.v1.rs b/substreams/ethereum-ekubo/src/pb/sf.substreams.index.v1.rs deleted file mode 100644 index a9543652c..000000000 --- a/substreams/ethereum-ekubo/src/pb/sf.substreams.index.v1.rs +++ /dev/null @@ -1,8 +0,0 @@ -// @generated -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Keys { - #[prost(string, repeated, tag="1")] - pub keys: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, -} -// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-ekubo/src/pb/sf.substreams.rpc.v2.rs b/substreams/ethereum-ekubo/src/pb/sf.substreams.rpc.v2.rs deleted file mode 100644 index 96df02286..000000000 --- a/substreams/ethereum-ekubo/src/pb/sf.substreams.rpc.v2.rs +++ /dev/null @@ -1,340 +0,0 @@ -// @generated -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Request { - #[prost(int64, tag="1")] - pub start_block_num: i64, - #[prost(string, tag="2")] - pub start_cursor: ::prost::alloc::string::String, - #[prost(uint64, tag="3")] - pub stop_block_num: u64, - /// With final_block_only, you only receive blocks that are irreversible: - /// 'final_block_height' will be equal to current block and no 'undo_signal' will ever be sent - #[prost(bool, tag="4")] - pub final_blocks_only: bool, - /// Substreams has two mode when executing your module(s) either development mode or production - /// mode. Development and production modes impact the execution of Substreams, important aspects - /// of execution include: - /// * The time required to reach the first byte. - /// * The speed that large ranges get executed. - /// * The module logs and outputs sent back to the client. - /// - /// By default, the engine runs in developer mode, with richer and deeper output. Differences - /// between production and development modes include: - /// * Forward parallel execution is enabled in production mode and disabled in development mode - /// * The time required to reach the first byte in development mode is faster than in production mode. - /// - /// Specific attributes of development mode include: - /// * The client will receive all of the executed module's logs. - /// * It's possible to request specific store snapshots in the execution tree (via `debug_initial_store_snapshot_for_modules`). - /// * Multiple module's output is possible. - /// - /// With production mode`, however, you trade off functionality for high speed enabling forward - /// parallel execution of module ahead of time. - #[prost(bool, tag="5")] - pub production_mode: bool, - #[prost(string, tag="6")] - pub output_module: ::prost::alloc::string::String, - #[prost(message, optional, tag="7")] - pub modules: ::core::option::Option, - /// Available only in developer mode - #[prost(string, repeated, tag="10")] - pub debug_initial_store_snapshot_for_modules: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Response { - #[prost(oneof="response::Message", tags="1, 2, 3, 4, 5, 10, 11")] - pub message: ::core::option::Option, -} -/// Nested message and enum types in `Response`. -pub mod response { - #[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Message { - /// Always sent first - #[prost(message, tag="1")] - Session(super::SessionInit), - /// Progress of data preparation, before sending in the stream of `data` events. - #[prost(message, tag="2")] - Progress(super::ModulesProgress), - #[prost(message, tag="3")] - BlockScopedData(super::BlockScopedData), - #[prost(message, tag="4")] - BlockUndoSignal(super::BlockUndoSignal), - #[prost(message, tag="5")] - FatalError(super::Error), - /// Available only in developer mode, and only if `debug_initial_store_snapshot_for_modules` is set. - #[prost(message, tag="10")] - DebugSnapshotData(super::InitialSnapshotData), - /// Available only in developer mode, and only if `debug_initial_store_snapshot_for_modules` is set. - #[prost(message, tag="11")] - DebugSnapshotComplete(super::InitialSnapshotComplete), - } -} -/// BlockUndoSignal informs you that every bit of data -/// with a block number above 'last_valid_block' has been reverted -/// on-chain. Delete that data and restart from 'last_valid_cursor' -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BlockUndoSignal { - #[prost(message, optional, tag="1")] - pub last_valid_block: ::core::option::Option, - #[prost(string, tag="2")] - pub last_valid_cursor: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BlockScopedData { - #[prost(message, optional, tag="1")] - pub output: ::core::option::Option, - #[prost(message, optional, tag="2")] - pub clock: ::core::option::Option, - #[prost(string, tag="3")] - pub cursor: ::prost::alloc::string::String, - /// Non-deterministic, allows substreams-sink to let go of their undo data. - #[prost(uint64, tag="4")] - pub final_block_height: u64, - #[prost(message, repeated, tag="10")] - pub debug_map_outputs: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="11")] - pub debug_store_outputs: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SessionInit { - #[prost(string, tag="1")] - pub trace_id: ::prost::alloc::string::String, - #[prost(uint64, tag="2")] - pub resolved_start_block: u64, - #[prost(uint64, tag="3")] - pub linear_handoff_block: u64, - #[prost(uint64, tag="4")] - pub max_parallel_workers: u64, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct InitialSnapshotComplete { - #[prost(string, tag="1")] - pub cursor: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct InitialSnapshotData { - #[prost(string, tag="1")] - pub module_name: ::prost::alloc::string::String, - #[prost(message, repeated, tag="2")] - pub deltas: ::prost::alloc::vec::Vec, - #[prost(uint64, tag="4")] - pub sent_keys: u64, - #[prost(uint64, tag="3")] - pub total_keys: u64, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct MapModuleOutput { - #[prost(string, tag="1")] - pub name: ::prost::alloc::string::String, - #[prost(message, optional, tag="2")] - pub map_output: ::core::option::Option<::prost_types::Any>, - /// DebugOutputInfo is available in non-production mode only - #[prost(message, optional, tag="10")] - pub debug_info: ::core::option::Option, -} -/// StoreModuleOutput are produced for store modules in development mode. -/// It is not possible to retrieve store models in production, with parallelization -/// enabled. If you need the deltas directly, write a pass through mapper module -/// that will get them down to you. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct StoreModuleOutput { - #[prost(string, tag="1")] - pub name: ::prost::alloc::string::String, - #[prost(message, repeated, tag="2")] - pub debug_store_deltas: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag="10")] - pub debug_info: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct OutputDebugInfo { - #[prost(string, repeated, tag="1")] - pub logs: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - /// LogsTruncated is a flag that tells you if you received all the logs or if they - /// were truncated because you logged too much (fixed limit currently is set to 128 KiB). - #[prost(bool, tag="2")] - pub logs_truncated: bool, - #[prost(bool, tag="3")] - pub cached: bool, -} -/// ModulesProgress is a message that is sent every 500ms -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ModulesProgress { - /// List of jobs running on tier2 servers - #[prost(message, repeated, tag="2")] - pub running_jobs: ::prost::alloc::vec::Vec, - /// Execution statistics for each module - #[prost(message, repeated, tag="3")] - pub modules_stats: ::prost::alloc::vec::Vec, - /// Stages definition and completed block ranges - #[prost(message, repeated, tag="4")] - pub stages: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag="5")] - pub processed_bytes: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ProcessedBytes { - #[prost(uint64, tag="1")] - pub total_bytes_read: u64, - #[prost(uint64, tag="2")] - pub total_bytes_written: u64, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Error { - #[prost(string, tag="1")] - pub module: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub reason: ::prost::alloc::string::String, - #[prost(string, repeated, tag="3")] - pub logs: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - /// FailureLogsTruncated is a flag that tells you if you received all the logs or if they - /// were truncated because you logged too much (fixed limit currently is set to 128 KiB). - #[prost(bool, tag="4")] - pub logs_truncated: bool, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Job { - #[prost(uint32, tag="1")] - pub stage: u32, - #[prost(uint64, tag="2")] - pub start_block: u64, - #[prost(uint64, tag="3")] - pub stop_block: u64, - #[prost(uint64, tag="4")] - pub processed_blocks: u64, - #[prost(uint64, tag="5")] - pub duration_ms: u64, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Stage { - #[prost(string, repeated, tag="1")] - pub modules: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(message, repeated, tag="2")] - pub completed_ranges: ::prost::alloc::vec::Vec, -} -/// ModuleStats gathers metrics and statistics from each module, running on tier1 or tier2 -/// All the 'count' and 'time_ms' values may include duplicate for each stage going over that module -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ModuleStats { - /// name of the module - #[prost(string, tag="1")] - pub name: ::prost::alloc::string::String, - /// total_processed_blocks is the sum of blocks sent to that module code - #[prost(uint64, tag="2")] - pub total_processed_block_count: u64, - /// total_processing_time_ms is the sum of all time spent running that module code - #[prost(uint64, tag="3")] - pub total_processing_time_ms: u64, - /// // external_calls are chain-specific intrinsics, like "Ethereum RPC calls". - #[prost(message, repeated, tag="4")] - pub external_call_metrics: ::prost::alloc::vec::Vec, - /// total_store_operation_time_ms is the sum of all time spent running that module code waiting for a store operation (ex: read, write, delete...) - #[prost(uint64, tag="5")] - pub total_store_operation_time_ms: u64, - /// total_store_read_count is the sum of all the store Read operations called from that module code - #[prost(uint64, tag="6")] - pub total_store_read_count: u64, - /// total_store_write_count is the sum of all store Write operations called from that module code (store-only) - #[prost(uint64, tag="10")] - pub total_store_write_count: u64, - /// total_store_deleteprefix_count is the sum of all store DeletePrefix operations called from that module code (store-only) - /// note that DeletePrefix can be a costly operation on large stores - #[prost(uint64, tag="11")] - pub total_store_deleteprefix_count: u64, - /// store_size_bytes is the uncompressed size of the full KV store for that module, from the last 'merge' operation (store-only) - #[prost(uint64, tag="12")] - pub store_size_bytes: u64, - /// total_store_merging_time_ms is the time spent merging partial stores into a full KV store for that module (store-only) - #[prost(uint64, tag="13")] - pub total_store_merging_time_ms: u64, - /// store_currently_merging is true if there is a merging operation (partial store to full KV store) on the way. - #[prost(bool, tag="14")] - pub store_currently_merging: bool, - /// highest_contiguous_block is the highest block in the highest merged full KV store of that module (store-only) - #[prost(uint64, tag="15")] - pub highest_contiguous_block: u64, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ExternalCallMetric { - #[prost(string, tag="1")] - pub name: ::prost::alloc::string::String, - #[prost(uint64, tag="2")] - pub count: u64, - #[prost(uint64, tag="3")] - pub time_ms: u64, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct StoreDelta { - #[prost(enumeration="store_delta::Operation", tag="1")] - pub operation: i32, - #[prost(uint64, tag="2")] - pub ordinal: u64, - #[prost(string, tag="3")] - pub key: ::prost::alloc::string::String, - #[prost(bytes="vec", tag="4")] - pub old_value: ::prost::alloc::vec::Vec, - #[prost(bytes="vec", tag="5")] - pub new_value: ::prost::alloc::vec::Vec, -} -/// Nested message and enum types in `StoreDelta`. -pub mod store_delta { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum Operation { - Unset = 0, - Create = 1, - Update = 2, - Delete = 3, - } - impl Operation { - /// 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 { - Operation::Unset => "UNSET", - Operation::Create => "CREATE", - Operation::Update => "UPDATE", - Operation::Delete => "DELETE", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNSET" => Some(Self::Unset), - "CREATE" => Some(Self::Create), - "UPDATE" => Some(Self::Update), - "DELETE" => Some(Self::Delete), - _ => None, - } - } - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BlockRange { - #[prost(uint64, tag="2")] - pub start_block: u64, - #[prost(uint64, tag="3")] - pub end_block: u64, -} -// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-ekubo/src/pb/sf.substreams.rs b/substreams/ethereum-ekubo/src/pb/sf.substreams.rs deleted file mode 100644 index ffc5f78da..000000000 --- a/substreams/ethereum-ekubo/src/pb/sf.substreams.rs +++ /dev/null @@ -1,14 +0,0 @@ -// @generated -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct FieldOptions { - /// this option informs the `substreams pack` command that it should treat the corresponding manifest value as a path to a file, putting its content as bytes in this field. - /// must be applied to a `bytes` or `string` field - #[prost(bool, tag="1")] - pub load_from_file: bool, - /// this option informs the `substreams pack` command that it should treat the corresponding manifest value as a path to a folder, zipping its content and putting the zip content as bytes in this field. - /// must be applied to a `bytes` field - #[prost(bool, tag="2")] - pub zip_from_folder: bool, -} -// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-ekubo/src/pb/sf.substreams.sink.service.v1.rs b/substreams/ethereum-ekubo/src/pb/sf.substreams.sink.service.v1.rs deleted file mode 100644 index d1c643dd2..000000000 --- a/substreams/ethereum-ekubo/src/pb/sf.substreams.sink.service.v1.rs +++ /dev/null @@ -1,227 +0,0 @@ -// @generated -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DeployRequest { - #[prost(message, optional, tag="1")] - pub substreams_package: ::core::option::Option, - #[prost(bool, tag="2")] - pub development_mode: bool, - #[prost(message, repeated, tag="3")] - pub parameters: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Parameter { - #[prost(string, tag="1")] - pub key: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub value: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DeployResponse { - #[prost(enumeration="DeploymentStatus", tag="1")] - pub status: i32, - /// deployment_id is a short name (max 8 characters) that uniquely identifies your deployment - #[prost(string, tag="2")] - pub deployment_id: ::prost::alloc::string::String, - #[prost(map="string, string", tag="3")] - pub services: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, - #[prost(string, tag="4")] - pub reason: ::prost::alloc::string::String, - #[prost(string, tag="5")] - pub motd: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct UpdateRequest { - #[prost(message, optional, tag="1")] - pub substreams_package: ::core::option::Option, - #[prost(string, tag="2")] - pub deployment_id: ::prost::alloc::string::String, - #[prost(bool, tag="3")] - pub reset: bool, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct UpdateResponse { - #[prost(enumeration="DeploymentStatus", tag="1")] - pub status: i32, - #[prost(map="string, string", tag="2")] - pub services: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, - #[prost(string, tag="3")] - pub reason: ::prost::alloc::string::String, - #[prost(string, tag="4")] - pub motd: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct InfoRequest { - #[prost(string, tag="1")] - pub deployment_id: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct InfoResponse { - #[prost(enumeration="DeploymentStatus", tag="1")] - pub status: i32, - #[prost(map="string, string", tag="2")] - pub services: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, - #[prost(string, tag="3")] - pub reason: ::prost::alloc::string::String, - #[prost(message, optional, tag="4")] - pub package_info: ::core::option::Option, - #[prost(message, optional, tag="5")] - pub progress: ::core::option::Option, - #[prost(string, tag="6")] - pub motd: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SinkProgress { - #[prost(uint64, tag="1")] - pub last_processed_block: u64, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct PackageInfo { - #[prost(string, tag="1")] - pub name: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub version: ::prost::alloc::string::String, - #[prost(string, tag="3")] - pub output_module_name: ::prost::alloc::string::String, - #[prost(string, tag="4")] - pub output_module_hash: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ListRequest { -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ListResponse { - #[prost(message, repeated, tag="1")] - pub deployments: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DeploymentWithStatus { - #[prost(string, tag="1")] - pub id: ::prost::alloc::string::String, - #[prost(enumeration="DeploymentStatus", tag="2")] - pub status: i32, - #[prost(string, tag="3")] - pub reason: ::prost::alloc::string::String, - #[prost(message, optional, tag="4")] - pub package_info: ::core::option::Option, - #[prost(message, optional, tag="5")] - pub progress: ::core::option::Option, - #[prost(string, tag="6")] - pub motd: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct RemoveRequest { - #[prost(string, tag="1")] - pub deployment_id: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct RemoveResponse { - #[prost(enumeration="DeploymentStatus", tag="1")] - pub previous_status: i32, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct PauseRequest { - #[prost(string, tag="1")] - pub deployment_id: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct PauseResponse { - #[prost(enumeration="DeploymentStatus", tag="1")] - pub previous_status: i32, - #[prost(enumeration="DeploymentStatus", tag="2")] - pub new_status: i32, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct StopRequest { - #[prost(string, tag="1")] - pub deployment_id: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct StopResponse { - #[prost(enumeration="DeploymentStatus", tag="1")] - pub previous_status: i32, - #[prost(enumeration="DeploymentStatus", tag="2")] - pub new_status: i32, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ResumeRequest { - #[prost(string, tag="1")] - pub deployment_id: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ResumeResponse { - #[prost(enumeration="DeploymentStatus", tag="1")] - pub previous_status: i32, - #[prost(enumeration="DeploymentStatus", tag="2")] - pub new_status: i32, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum DeploymentStatus { - Unknown = 0, - Running = 1, - Failing = 2, - Paused = 3, - Stopped = 4, - Starting = 5, - Pausing = 6, - Stopping = 7, - Removing = 8, - Resuming = 9, -} -impl DeploymentStatus { - /// 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 { - DeploymentStatus::Unknown => "UNKNOWN", - DeploymentStatus::Running => "RUNNING", - DeploymentStatus::Failing => "FAILING", - DeploymentStatus::Paused => "PAUSED", - DeploymentStatus::Stopped => "STOPPED", - DeploymentStatus::Starting => "STARTING", - DeploymentStatus::Pausing => "PAUSING", - DeploymentStatus::Stopping => "STOPPING", - DeploymentStatus::Removing => "REMOVING", - DeploymentStatus::Resuming => "RESUMING", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNKNOWN" => Some(Self::Unknown), - "RUNNING" => Some(Self::Running), - "FAILING" => Some(Self::Failing), - "PAUSED" => Some(Self::Paused), - "STOPPED" => Some(Self::Stopped), - "STARTING" => Some(Self::Starting), - "PAUSING" => Some(Self::Pausing), - "STOPPING" => Some(Self::Stopping), - "REMOVING" => Some(Self::Removing), - "RESUMING" => Some(Self::Resuming), - _ => None, - } - } -} -// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-ekubo/src/pb/sf.substreams.v1.rs b/substreams/ethereum-ekubo/src/pb/sf.substreams.v1.rs deleted file mode 100644 index dc86dac23..000000000 --- a/substreams/ethereum-ekubo/src/pb/sf.substreams.v1.rs +++ /dev/null @@ -1,324 +0,0 @@ -// @generated -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Modules { - #[prost(message, repeated, tag="1")] - pub modules: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="2")] - pub binaries: ::prost::alloc::vec::Vec, -} -/// Binary represents some code compiled to its binary form. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Binary { - #[prost(string, tag="1")] - pub r#type: ::prost::alloc::string::String, - #[prost(bytes="vec", tag="2")] - pub content: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Module { - #[prost(string, tag="1")] - pub name: ::prost::alloc::string::String, - #[prost(uint32, tag="4")] - pub binary_index: u32, - #[prost(string, tag="5")] - pub binary_entrypoint: ::prost::alloc::string::String, - #[prost(message, repeated, tag="6")] - pub inputs: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag="7")] - pub output: ::core::option::Option, - #[prost(uint64, tag="8")] - pub initial_block: u64, - #[prost(message, optional, tag="9")] - pub block_filter: ::core::option::Option, - #[prost(oneof="module::Kind", tags="2, 3, 10")] - pub kind: ::core::option::Option, -} -/// Nested message and enum types in `Module`. -pub mod module { - #[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] - pub struct BlockFilter { - #[prost(string, tag="1")] - pub module: ::prost::alloc::string::String, - #[prost(oneof="block_filter::Query", tags="2, 3")] - pub query: ::core::option::Option, - } - /// Nested message and enum types in `BlockFilter`. - pub mod block_filter { - #[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Query { - #[prost(string, tag="2")] - QueryString(::prost::alloc::string::String), - /// QueryFromStore query_from_store_keys = 3; - #[prost(message, tag="3")] - QueryFromParams(super::QueryFromParams), - } - } - #[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] - pub struct QueryFromParams { - } - #[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] - pub struct KindMap { - #[prost(string, tag="1")] - pub output_type: ::prost::alloc::string::String, - } - #[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] - pub struct KindStore { - /// The `update_policy` determines the functions available to mutate the store - /// (like `set()`, `set_if_not_exists()` or `sum()`, etc..) in - /// order to ensure that parallel operations are possible and deterministic - /// - /// Say a store cumulates keys from block 0 to 1M, and a second store - /// cumulates keys from block 1M to 2M. When we want to use this - /// store as a dependency for a downstream module, we will merge the - /// two stores according to this policy. - #[prost(enumeration="kind_store::UpdatePolicy", tag="1")] - pub update_policy: i32, - #[prost(string, tag="2")] - pub value_type: ::prost::alloc::string::String, - } - /// Nested message and enum types in `KindStore`. - pub mod kind_store { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum UpdatePolicy { - Unset = 0, - /// Provides a store where you can `set()` keys, and the latest key wins - Set = 1, - /// Provides a store where you can `set_if_not_exists()` keys, and the first key wins - SetIfNotExists = 2, - /// Provides a store where you can `add_*()` keys, where two stores merge by summing its values. - Add = 3, - /// Provides a store where you can `min_*()` keys, where two stores merge by leaving the minimum value. - Min = 4, - /// Provides a store where you can `max_*()` keys, where two stores merge by leaving the maximum value. - Max = 5, - /// Provides a store where you can `append()` keys, where two stores merge by concatenating the bytes in order. - Append = 6, - /// Provides a store with both `set()` and `sum()` functions. - SetSum = 7, - } - impl UpdatePolicy { - /// 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 { - UpdatePolicy::Unset => "UPDATE_POLICY_UNSET", - UpdatePolicy::Set => "UPDATE_POLICY_SET", - UpdatePolicy::SetIfNotExists => "UPDATE_POLICY_SET_IF_NOT_EXISTS", - UpdatePolicy::Add => "UPDATE_POLICY_ADD", - UpdatePolicy::Min => "UPDATE_POLICY_MIN", - UpdatePolicy::Max => "UPDATE_POLICY_MAX", - UpdatePolicy::Append => "UPDATE_POLICY_APPEND", - UpdatePolicy::SetSum => "UPDATE_POLICY_SET_SUM", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UPDATE_POLICY_UNSET" => Some(Self::Unset), - "UPDATE_POLICY_SET" => Some(Self::Set), - "UPDATE_POLICY_SET_IF_NOT_EXISTS" => Some(Self::SetIfNotExists), - "UPDATE_POLICY_ADD" => Some(Self::Add), - "UPDATE_POLICY_MIN" => Some(Self::Min), - "UPDATE_POLICY_MAX" => Some(Self::Max), - "UPDATE_POLICY_APPEND" => Some(Self::Append), - "UPDATE_POLICY_SET_SUM" => Some(Self::SetSum), - _ => None, - } - } - } - } - #[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] - pub struct KindBlockIndex { - #[prost(string, tag="1")] - pub output_type: ::prost::alloc::string::String, - } - #[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] - pub struct Input { - #[prost(oneof="input::Input", tags="1, 2, 3, 4")] - pub input: ::core::option::Option, - } - /// Nested message and enum types in `Input`. - pub mod input { - #[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] - pub struct Source { - /// ex: "sf.ethereum.type.v1.Block" - #[prost(string, tag="1")] - pub r#type: ::prost::alloc::string::String, - } - #[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] - pub struct Map { - /// ex: "block_to_pairs" - #[prost(string, tag="1")] - pub module_name: ::prost::alloc::string::String, - } - #[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] - pub struct Store { - #[prost(string, tag="1")] - pub module_name: ::prost::alloc::string::String, - #[prost(enumeration="store::Mode", tag="2")] - pub mode: i32, - } - /// Nested message and enum types in `Store`. - pub mod store { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum Mode { - Unset = 0, - Get = 1, - Deltas = 2, - } - impl Mode { - /// 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 { - Mode::Unset => "UNSET", - Mode::Get => "GET", - Mode::Deltas => "DELTAS", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNSET" => Some(Self::Unset), - "GET" => Some(Self::Get), - "DELTAS" => Some(Self::Deltas), - _ => None, - } - } - } - } - #[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] - pub struct Params { - #[prost(string, tag="1")] - pub value: ::prost::alloc::string::String, - } - #[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Input { - #[prost(message, tag="1")] - Source(Source), - #[prost(message, tag="2")] - Map(Map), - #[prost(message, tag="3")] - Store(Store), - #[prost(message, tag="4")] - Params(Params), - } - } - #[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] - pub struct Output { - #[prost(string, tag="1")] - pub r#type: ::prost::alloc::string::String, - } - #[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Kind { - #[prost(message, tag="2")] - KindMap(KindMap), - #[prost(message, tag="3")] - KindStore(KindStore), - #[prost(message, tag="10")] - KindBlockIndex(KindBlockIndex), - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Package { - /// Needs to be one so this file can be used _directly_ as a - /// buf `Image` andor a ProtoSet for grpcurl and other tools - #[prost(message, repeated, tag="1")] - pub proto_files: ::prost::alloc::vec::Vec<::prost_types::FileDescriptorProto>, - #[prost(uint64, tag="5")] - pub version: u64, - #[prost(message, optional, tag="6")] - pub modules: ::core::option::Option, - #[prost(message, repeated, tag="7")] - pub module_meta: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="8")] - pub package_meta: ::prost::alloc::vec::Vec, - /// Source network for Substreams to fetch its data from. - #[prost(string, tag="9")] - pub network: ::prost::alloc::string::String, - #[prost(message, optional, tag="10")] - pub sink_config: ::core::option::Option<::prost_types::Any>, - #[prost(string, tag="11")] - pub sink_module: ::prost::alloc::string::String, - /// image is the bytes to a JPEG, WebP or PNG file. Max size is 2 MiB - #[prost(bytes="vec", tag="12")] - pub image: ::prost::alloc::vec::Vec, - #[prost(map="string, message", tag="13")] - pub networks: ::std::collections::HashMap<::prost::alloc::string::String, NetworkParams>, - #[prost(map="string, string", tag="14")] - pub block_filters: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct NetworkParams { - #[prost(map="string, uint64", tag="1")] - pub initial_blocks: ::std::collections::HashMap<::prost::alloc::string::String, u64>, - #[prost(map="string, string", tag="2")] - pub params: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct PackageMetadata { - #[prost(string, tag="1")] - pub version: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub url: ::prost::alloc::string::String, - #[prost(string, tag="3")] - pub name: ::prost::alloc::string::String, - #[prost(string, tag="4")] - pub doc: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ModuleMetadata { - /// Corresponds to the index in `Package.metadata.package_meta` - #[prost(uint64, tag="1")] - pub package_index: u64, - #[prost(string, tag="2")] - pub doc: ::prost::alloc::string::String, -} -/// Clock is a pointer to a block with added timestamp -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Clock { - #[prost(string, tag="1")] - pub id: ::prost::alloc::string::String, - #[prost(uint64, tag="2")] - pub number: u64, - #[prost(message, optional, tag="3")] - pub timestamp: ::core::option::Option<::prost_types::Timestamp>, -} -/// BlockRef is a pointer to a block to which we don't know the timestamp -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BlockRef { - #[prost(string, tag="1")] - pub id: ::prost::alloc::string::String, - #[prost(uint64, tag="2")] - pub number: u64, -} -// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-ekubo/src/pool_factories.rs b/substreams/ethereum-ekubo/src/pool_factories.rs index 07426eceb..148b187e8 100644 --- a/substreams/ethereum-ekubo/src/pool_factories.rs +++ b/substreams/ethereum-ekubo/src/pool_factories.rs @@ -1,10 +1,14 @@ +use std::iter; + +use itertools::Itertools; use serde::Deserialize; use substreams_ethereum::Event; use substreams_ethereum::pb::eth::v2::{Call, Log, TransactionTrace}; -use tiny_keccak::{Hasher, Keccak}; use tycho_substreams::models::{ChangeType, FinancialType, ImplementationType, ProtocolComponent, ProtocolType}; use tycho_substreams::prelude::Attribute; +use crate::identifiers::{pool_id_to_component_id, PoolKey}; + #[derive(Deserialize)] pub struct DeploymentConfig { #[serde(with = "hex::serde")] @@ -28,51 +32,50 @@ pub fn maybe_create_component( ) -> Option { if call.address == config.core { if let Some(pi) = crate::abi::core::events::PoolInitialized::match_and_decode(log) { - let pool_id = hash_pool_key(&pi.pool_key); + let pool_key = PoolKey::from(pi.pool_key); + + let contracts = iter + ::once(config.core.clone()) + .chain((config.oracle == pool_key.config.extension).then(|| config.oracle.clone())) + .collect_vec(); return Some(ProtocolComponent { - id: pool_id, - tokens: vec![pi.pool_key.0.clone(), pi.pool_key.1.clone()], - contracts: if config.oracle == pi.pool_key.4 { - vec![ - config.oracle.clone(), - config.core.clone(), - ] - } else { - vec![config.core.clone()] - }, + id: pool_id_to_component_id(pi.pool_id), + tokens: vec![pool_key.token0.clone(), pool_key.token1.clone()], + contracts, change: ChangeType::Creation.into(), protocol_type: Some(ProtocolType { - name: "EKUBO".to_string(), + name: "ekubo".to_string(), financial_type: FinancialType::Swap.into(), implementation_type: ImplementationType::Vm.into(), attribute_schema: vec![], }), + // NOTE: Order of attributes matters (used in store_pool_details) static_att: vec![ Attribute { change: ChangeType::Creation.into(), name: "token0".to_string(), - value: pi.pool_key.0, + value: pool_key.token0, }, Attribute { change: ChangeType::Creation.into(), name: "token1".to_string(), - value: pi.pool_key.1, + value: pool_key.token1, }, Attribute { change: ChangeType::Creation.into(), name: "fee".to_string(), - value: pi.pool_key.2.to_bytes_be().1, + value: pool_key.config.fee, }, Attribute { change: ChangeType::Creation.into(), name: "tick_spacing".to_string(), - value: pi.pool_key.3.to_bytes_be().1, + value: pool_key.config.tick_spacing, }, Attribute { change: ChangeType::Creation.into(), name: "extension".to_string(), - value: pi.pool_key.4, + value: pool_key.config.extension, }, ], }); @@ -81,25 +84,3 @@ pub fn maybe_create_component( None } - - -pub type PoolKey = ( - Vec, - Vec, - substreams::scalar::BigInt, - substreams::scalar::BigInt, - Vec, -); - -pub fn hash_pool_key(pool_key: &PoolKey) -> String { - let mut hasher = Keccak::v256(); - hasher.update(pool_key.0.as_slice()); - hasher.update(pool_key.1.as_slice()); - hasher.update(pool_key.2.to_signed_bytes_be().as_slice()); - hasher.update(pool_key.3.to_signed_bytes_be().as_slice()); - hasher.update(pool_key.4.as_slice()); - - let mut output = [0u8; 32]; - hasher.finalize(&mut output); - hex::encode(output) -} \ No newline at end of file diff --git a/substreams/ethereum-ekubo/substreams.yaml b/substreams/ethereum-ekubo/substreams.yaml index 116f992ae..c0afa2c01 100644 --- a/substreams/ethereum-ekubo/substreams.yaml +++ b/substreams/ethereum-ekubo/substreams.yaml @@ -8,26 +8,26 @@ protobuf: - tycho/evm/v1/vm.proto - tycho/evm/v1/common.proto - tycho/evm/v1/utils.proto + - ekubo.proto importPaths: - ../../proto + - ./proto binaries: default: type: wasm/rust-v1 file: ../target/wasm32-unknown-unknown/release/ethereum_ekubo.wasm -network: mainnet +network: sepolia networks: - mainnet: + sepolia: initialBlock: - map_protocol_components: 21739334 - map_relative_component_balance: 21739334 - store_balances: 21739334 - map_protocol_changes: 21739334 + map_protocol_components: 7811236 + map_relative_component_balance: 7811236 params: - map_protocol_components: "core=39d8ab62fcaa5b466eb8397187732b6ba455aaa8&oracle=51ee1902db6d5640163506b9e178a21ff027282c" - map_relative_component_balance: "core=39d8ab62fcaa5b466eb8397187732b6ba455aaa8&oracle=51ee1902db6d5640163506b9e178a21ff027282c" - map_protocol_changes: "core=39d8ab62fcaa5b466eb8397187732b6ba455aaa8&oracle=51ee1902db6d5640163506b9e178a21ff027282c" + map_protocol_components: "core=16e186ecdc94083fff53ef2a41d46b92a54f61e2&oracle=51f1b10abf90e16498d25086641b0669ec62f32f" + map_relative_component_balance: "core=16e186ecdc94083fff53ef2a41d46b92a54f61e2&oracle=51f1b10abf90e16498d25086641b0669ec62f32f" + map_protocol_changes: "core=16e186ecdc94083fff53ef2a41d46b92a54f61e2&oracle=51f1b10abf90e16498d25086641b0669ec62f32f" modules: - name: map_protocol_components @@ -38,11 +38,19 @@ modules: output: type: proto:tycho.evm.v1.BlockTransactionProtocolComponents + - name: store_pool_details + kind: store + updatePolicy: set + valueType: proto:ekubo.PoolDetails + inputs: + - map: map_protocol_components + - name: map_relative_component_balance kind: map inputs: - params: string - source: sf.ethereum.type.v2.Block + - store: store_pool_details output: type: proto:tycho.evm.v1.BlockBalanceDeltas