From 376406b8b675a812a2f8cf03a1847478f7e732b3 Mon Sep 17 00:00:00 2001 From: catalyst17 <37663786+catalyst17@users.noreply.github.com> Date: Tue, 2 Jan 2024 19:24:24 +0100 Subject: [PATCH 1/9] feat: mapping creations of Nitro rollups --- Makefile | 2 +- abi/rollups/arbitrum/rollup_creator.json | 485 +++++ build.rs | 4 + proto/nitro_rollup.proto | 18 + src/abi/mod.rs | 1 + src/abi/rollups/arbitrum/mod.rs | 1 + src/abi/rollups/arbitrum/rollup_creator.rs | 1955 ++++++++++++++++++++ src/abi/rollups/mod.rs | 1 + src/lib.rs | 1 + src/map_index_nitro_rollup_creations.rs | 60 + src/pb/eth.transaction.v1.rs | 22 + substreams.yaml | 8 + 12 files changed, 2557 insertions(+), 1 deletion(-) create mode 100644 abi/rollups/arbitrum/rollup_creator.json create mode 100644 proto/nitro_rollup.proto create mode 100644 src/abi/rollups/arbitrum/mod.rs create mode 100644 src/abi/rollups/arbitrum/rollup_creator.rs create mode 100644 src/abi/rollups/mod.rs create mode 100644 src/map_index_nitro_rollup_creations.rs diff --git a/Makefile b/Makefile index 8057f37..04070ab 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ sink: build .PHONY: gui gui: build - substreams gui -e $(ENDPOINT) substreams.yaml db_out -s $(START_BLOCK) -t $(STOP_BLOCK) + substreams gui -e $(ENDPOINT) substreams.yaml map_combine_transactions -s $(START_BLOCK) -t $(STOP_BLOCK) .PHONY: protogen protogen: diff --git a/abi/rollups/arbitrum/rollup_creator.json b/abi/rollups/arbitrum/rollup_creator.json new file mode 100644 index 0000000..358ea90 --- /dev/null +++ b/abi/rollups/arbitrum/rollup_creator.json @@ -0,0 +1,485 @@ +[ + { + "inputs":[ + + ], + "stateMutability":"nonpayable", + "type":"constructor" + }, + { + "anonymous":false, + "inputs":[ + { + "indexed":true, + "internalType":"address", + "name":"previousOwner", + "type":"address" + }, + { + "indexed":true, + "internalType":"address", + "name":"newOwner", + "type":"address" + } + ], + "name":"OwnershipTransferred", + "type":"event" + }, + { + "anonymous":false, + "inputs":[ + { + "indexed":true, + "internalType":"address", + "name":"rollupAddress", + "type":"address" + }, + { + "indexed":true, + "internalType":"address", + "name":"nativeToken", + "type":"address" + }, + { + "indexed":false, + "internalType":"address", + "name":"inboxAddress", + "type":"address" + }, + { + "indexed":false, + "internalType":"address", + "name":"outbox", + "type":"address" + }, + { + "indexed":false, + "internalType":"address", + "name":"rollupEventInbox", + "type":"address" + }, + { + "indexed":false, + "internalType":"address", + "name":"challengeManager", + "type":"address" + }, + { + "indexed":false, + "internalType":"address", + "name":"adminProxy", + "type":"address" + }, + { + "indexed":false, + "internalType":"address", + "name":"sequencerInbox", + "type":"address" + }, + { + "indexed":false, + "internalType":"address", + "name":"bridge", + "type":"address" + }, + { + "indexed":false, + "internalType":"address", + "name":"upgradeExecutor", + "type":"address" + }, + { + "indexed":false, + "internalType":"address", + "name":"validatorUtils", + "type":"address" + }, + { + "indexed":false, + "internalType":"address", + "name":"validatorWalletCreator", + "type":"address" + } + ], + "name":"RollupCreated", + "type":"event" + }, + { + "anonymous":false, + "inputs":[ + + ], + "name":"TemplatesUpdated", + "type":"event" + }, + { + "inputs":[ + + ], + "name":"bridgeCreator", + "outputs":[ + { + "internalType":"contract BridgeCreator", + "name":"", + "type":"address" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"challengeManagerTemplate", + "outputs":[ + { + "internalType":"contract IChallengeManager", + "name":"", + "type":"address" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + { + "components":[ + { + "components":[ + { + "internalType":"uint64", + "name":"confirmPeriodBlocks", + "type":"uint64" + }, + { + "internalType":"uint64", + "name":"extraChallengeTimeBlocks", + "type":"uint64" + }, + { + "internalType":"address", + "name":"stakeToken", + "type":"address" + }, + { + "internalType":"uint256", + "name":"baseStake", + "type":"uint256" + }, + { + "internalType":"bytes32", + "name":"wasmModuleRoot", + "type":"bytes32" + }, + { + "internalType":"address", + "name":"owner", + "type":"address" + }, + { + "internalType":"address", + "name":"loserStakeEscrow", + "type":"address" + }, + { + "internalType":"uint256", + "name":"chainId", + "type":"uint256" + }, + { + "internalType":"string", + "name":"chainConfig", + "type":"string" + }, + { + "internalType":"uint64", + "name":"genesisBlockNum", + "type":"uint64" + }, + { + "components":[ + { + "internalType":"uint256", + "name":"delayBlocks", + "type":"uint256" + }, + { + "internalType":"uint256", + "name":"futureBlocks", + "type":"uint256" + }, + { + "internalType":"uint256", + "name":"delaySeconds", + "type":"uint256" + }, + { + "internalType":"uint256", + "name":"futureSeconds", + "type":"uint256" + } + ], + "internalType":"struct ISequencerInbox.MaxTimeVariation", + "name":"sequencerInboxMaxTimeVariation", + "type":"tuple" + } + ], + "internalType":"struct Config", + "name":"config", + "type":"tuple" + }, + { + "internalType":"address", + "name":"batchPoster", + "type":"address" + }, + { + "internalType":"address[]", + "name":"validators", + "type":"address[]" + }, + { + "internalType":"uint256", + "name":"maxDataSize", + "type":"uint256" + }, + { + "internalType":"address", + "name":"nativeToken", + "type":"address" + }, + { + "internalType":"bool", + "name":"deployFactoriesToL2", + "type":"bool" + }, + { + "internalType":"uint256", + "name":"maxFeePerGasForRetryables", + "type":"uint256" + } + ], + "internalType":"struct RollupCreator.RollupDeploymentParams", + "name":"deployParams", + "type":"tuple" + } + ], + "name":"createRollup", + "outputs":[ + { + "internalType":"address", + "name":"", + "type":"address" + } + ], + "stateMutability":"payable", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"l2FactoriesDeployer", + "outputs":[ + { + "internalType":"contract DeployHelper", + "name":"", + "type":"address" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"osp", + "outputs":[ + { + "internalType":"contract IOneStepProofEntry", + "name":"", + "type":"address" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"owner", + "outputs":[ + { + "internalType":"address", + "name":"", + "type":"address" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"renounceOwnership", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"rollupAdminLogic", + "outputs":[ + { + "internalType":"contract IRollupAdmin", + "name":"", + "type":"address" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"rollupUserLogic", + "outputs":[ + { + "internalType":"contract IRollupUser", + "name":"", + "type":"address" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + { + "internalType":"contract BridgeCreator", + "name":"_bridgeCreator", + "type":"address" + }, + { + "internalType":"contract IOneStepProofEntry", + "name":"_osp", + "type":"address" + }, + { + "internalType":"contract IChallengeManager", + "name":"_challengeManagerLogic", + "type":"address" + }, + { + "internalType":"contract IRollupAdmin", + "name":"_rollupAdminLogic", + "type":"address" + }, + { + "internalType":"contract IRollupUser", + "name":"_rollupUserLogic", + "type":"address" + }, + { + "internalType":"contract IUpgradeExecutor", + "name":"_upgradeExecutorLogic", + "type":"address" + }, + { + "internalType":"address", + "name":"_validatorUtils", + "type":"address" + }, + { + "internalType":"address", + "name":"_validatorWalletCreator", + "type":"address" + }, + { + "internalType":"contract DeployHelper", + "name":"_l2FactoriesDeployer", + "type":"address" + } + ], + "name":"setTemplates", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "internalType":"address", + "name":"newOwner", + "type":"address" + } + ], + "name":"transferOwnership", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"upgradeExecutorLogic", + "outputs":[ + { + "internalType":"contract IUpgradeExecutor", + "name":"", + "type":"address" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"validatorUtils", + "outputs":[ + { + "internalType":"address", + "name":"", + "type":"address" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"validatorWalletCreator", + "outputs":[ + { + "internalType":"address", + "name":"", + "type":"address" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "stateMutability":"payable", + "type":"receive" + } + ] \ No newline at end of file diff --git a/build.rs b/build.rs index 0358546..4a117c8 100644 --- a/build.rs +++ b/build.rs @@ -2,6 +2,10 @@ use anyhow::{Ok, Result}; use substreams_ethereum::Abigen; fn main() -> Result<(), anyhow::Error> { + Abigen::new("Rollup Creator", "abi/rollups/arbitrum/rollup_creator.json")? + .generate()? + .write_to_file("src/abi/rollups/arbitrum/rollup_creator.rs")?; + Abigen::new("Chronicle Median", "abi/chronicle/median.json")? .generate()? .write_to_file("src/abi/chronicle/median.rs")?; diff --git a/proto/nitro_rollup.proto b/proto/nitro_rollup.proto new file mode 100644 index 0000000..0a148e7 --- /dev/null +++ b/proto/nitro_rollup.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; + +package eth.transaction.v1; + +import "google/protobuf/timestamp.proto"; + +message NitroRollups { + repeated NitroRollup rollups = 1; +} + +message NitroRollup { + string rollupAddress = 1; + string nativeTokenAddress = 2; + string inboxAddress = 3; + string outboxAddress = 4; + string sequencerInbox = 5; + google.protobuf.Timestamp createdAt = 6; +} \ No newline at end of file diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 01a0a84..cbe6df7 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -1,2 +1,3 @@ pub mod account_abstraction; pub mod chronicle; +pub mod rollups; diff --git a/src/abi/rollups/arbitrum/mod.rs b/src/abi/rollups/arbitrum/mod.rs new file mode 100644 index 0000000..5d0a0c4 --- /dev/null +++ b/src/abi/rollups/arbitrum/mod.rs @@ -0,0 +1 @@ +pub mod rollup_creator; diff --git a/src/abi/rollups/arbitrum/rollup_creator.rs b/src/abi/rollups/arbitrum/rollup_creator.rs new file mode 100644 index 0000000..366ea55 --- /dev/null +++ b/src/abi/rollups/arbitrum/rollup_creator.rs @@ -0,0 +1,1955 @@ + 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 BridgeCreator {} + impl BridgeCreator { + const METHOD_ID: [u8; 4] = [248u8, 96u8, 206u8, 250u8]; + 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 BridgeCreator { + const NAME: &'static str = "bridgeCreator"; + 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 BridgeCreator { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct ChallengeManagerTemplate {} + impl ChallengeManagerTemplate { + const METHOD_ID: [u8; 4] = [156u8, 104u8, 61u8, 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, 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 ChallengeManagerTemplate { + const NAME: &'static str = "challengeManagerTemplate"; + 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 ChallengeManagerTemplate { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct CreateRollup { + pub deploy_params: ( + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + substreams::scalar::BigInt, + [u8; 32usize], + Vec, + Vec, + substreams::scalar::BigInt, + String, + substreams::scalar::BigInt, + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + ), + Vec, + Vec>, + substreams::scalar::BigInt, + Vec, + bool, + substreams::scalar::BigInt, + ), + } + impl CreateRollup { + const METHOD_ID: [u8; 4] = [203u8, 115u8, 214u8, 226u8]; + 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::Tuple(vec![ethabi::ParamType::Uint(64usize), + ethabi::ParamType::Uint(64usize), + ethabi::ParamType::Address, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Address, ethabi::ParamType::Address, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::String, ethabi::ParamType::Uint(64usize), + ethabi::ParamType::Tuple(vec![ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize)])]), + ethabi::ParamType::Address, + ethabi::ParamType::Array(Box::new(ethabi::ParamType::Address)), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Address, ethabi::ParamType::Bool, + ethabi::ParamType::Uint(256usize) + ], + ), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + deploy_params: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let tuple_elements = tuple_elements[0usize] + .clone() + .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) + }, + tuple_elements[2usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + 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) + }, + { + let mut result = [0u8; 32]; + let v = tuple_elements[4usize] + .clone() + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + tuple_elements[5usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[6usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[7usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[8usize] + .clone() + .into_string() + .expect(INTERNAL_ERR), + { + let mut v = [0 as u8; 32]; + tuple_elements[9usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let tuple_elements = tuple_elements[10usize] + .clone() + .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_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[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[2usize] + .clone() + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec() + }) + .collect(), + { + 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(), + tuple_elements[5usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + { + let mut v = [0 as u8; 32]; + tuple_elements[6usize] + .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::Tuple(vec![ethabi::Token::Uint(ethabi::Uint::from_big_endian(match + self.deploy_params.0.0.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 + .deploy_params.0.1.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 + .deploy_params.0.2)), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .deploy_params.0.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::FixedBytes(self + .deploy_params.0.4.as_ref().to_vec()), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .deploy_params.0.5)), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .deploy_params.0.6)), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .deploy_params.0.7.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::String(self.deploy_params.0 + .8.clone()), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .deploy_params.0.9.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::Tuple(vec![ethabi::Token::Uint(ethabi::Uint::from_big_endian(match + self.deploy_params.0.10.0.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 + .deploy_params.0.10.1.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 + .deploy_params.0.10.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 + .deploy_params.0.10.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 + .deploy_params.1)), { let v = self.deploy_params.2.iter() + .map(| inner | + ethabi::Token::Address(ethabi::Address::from_slice(& + inner))).collect(); ethabi::Token::Array(v) }, + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .deploy_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(),),), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .deploy_params.4)), ethabi::Token::Bool(self.deploy_params.5 + .clone()), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .deploy_params.6.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") }, } + .as_slice(),),) + ], + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for CreateRollup { + const NAME: &'static str = "createRollup"; + 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 CreateRollup { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct L2FactoriesDeployer {} + impl L2FactoriesDeployer { + const METHOD_ID: [u8; 4] = [172u8, 4u8, 37u8, 188u8]; + 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 L2FactoriesDeployer { + const NAME: &'static str = "l2FactoriesDeployer"; + 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 L2FactoriesDeployer { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Osp {} + impl Osp { + const METHOD_ID: [u8; 4] = [242u8, 106u8, 98u8, 198u8]; + 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 Osp { + const NAME: &'static str = "osp"; + 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 Osp { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Owner {} + impl Owner { + const METHOD_ID: [u8; 4] = [141u8, 165u8, 203u8, 91u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Owner { + const NAME: &'static str = "owner"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for Owner { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct 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 RollupAdminLogic {} + impl RollupAdminLogic { + const METHOD_ID: [u8; 4] = [157u8, 186u8, 50u8, 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, 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 RollupAdminLogic { + const NAME: &'static str = "rollupAdminLogic"; + 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 RollupAdminLogic { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct RollupUserLogic {} + impl RollupUserLogic { + const METHOD_ID: [u8; 4] = [157u8, 71u8, 152u8, 227u8]; + 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 RollupUserLogic { + const NAME: &'static str = "rollupUserLogic"; + 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 RollupUserLogic { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct SetTemplates { + pub bridge_creator: Vec, + pub osp: Vec, + pub challenge_manager_logic: Vec, + pub rollup_admin_logic: Vec, + pub rollup_user_logic: Vec, + pub upgrade_executor_logic: Vec, + pub validator_utils: Vec, + pub validator_wallet_creator: Vec, + pub l2_factories_deployer: Vec, + } + impl SetTemplates { + const METHOD_ID: [u8; 4] = [172u8, 154u8, 151u8, 180u8]; + 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::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + bridge_creator: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + osp: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + challenge_manager_logic: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + rollup_admin_logic: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + rollup_user_logic: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + upgrade_executor_logic: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + validator_utils: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + validator_wallet_creator: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + l2_factories_deployer: 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.bridge_creator), + ), + ethabi::Token::Address(ethabi::Address::from_slice(&self.osp)), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.challenge_manager_logic), + ), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.rollup_admin_logic), + ), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.rollup_user_logic), + ), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.upgrade_executor_logic), + ), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.validator_utils), + ), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.validator_wallet_creator), + ), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.l2_factories_deployer), + ), + ], + ); + 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 SetTemplates { + const NAME: &'static str = "setTemplates"; + 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 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 UpgradeExecutorLogic {} + impl UpgradeExecutorLogic { + const METHOD_ID: [u8; 4] = [3u8, 12u8, 184u8, 94u8]; + 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 UpgradeExecutorLogic { + const NAME: &'static str = "upgradeExecutorLogic"; + 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 UpgradeExecutorLogic { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct ValidatorUtils {} + impl ValidatorUtils { + const METHOD_ID: [u8; 4] = [1u8, 76u8, 201u8, 44u8]; + 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 ValidatorUtils { + const NAME: &'static str = "validatorUtils"; + 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 ValidatorUtils { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct ValidatorWalletCreator {} + impl ValidatorWalletCreator { + const METHOD_ID: [u8; 4] = [188u8, 69u8, 224u8, 174u8]; + 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 ValidatorWalletCreator { + const NAME: &'static str = "validatorWalletCreator"; + 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 ValidatorWalletCreator { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + } + /// Contract's events. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod events { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct OwnershipTransferred { + pub previous_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 { + previous_owner: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'previous_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 RollupCreated { + pub rollup_address: Vec, + pub native_token: Vec, + pub inbox_address: Vec, + pub outbox: Vec, + pub rollup_event_inbox: Vec, + pub challenge_manager: Vec, + pub admin_proxy: Vec, + pub sequencer_inbox: Vec, + pub bridge: Vec, + pub upgrade_executor: Vec, + pub validator_utils: Vec, + pub validator_wallet_creator: Vec, + } + impl RollupCreated { + const TOPIC_ID: [u8; 32] = [ + 72u8, + 18u8, + 119u8, + 222u8, + 81u8, + 141u8, + 31u8, + 54u8, + 75u8, + 25u8, + 97u8, + 102u8, + 185u8, + 2u8, + 25u8, + 185u8, + 150u8, + 251u8, + 167u8, + 97u8, + 56u8, + 163u8, + 220u8, + 132u8, + 231u8, + 254u8, + 2u8, + 84u8, + 14u8, + 177u8, + 203u8, + 219u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 320usize { + 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::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + rollup_address: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'rollup_address' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + native_token: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'native_token' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + inbox_address: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + outbox: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + rollup_event_inbox: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + challenge_manager: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + admin_proxy: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + sequencer_inbox: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + bridge: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + upgrade_executor: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + validator_utils: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + validator_wallet_creator: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + } + impl substreams_ethereum::Event for RollupCreated { + const NAME: &'static str = "RollupCreated"; + 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 TemplatesUpdated {} + impl TemplatesUpdated { + const TOPIC_ID: [u8; 32] = [ + 201u8, + 211u8, + 148u8, + 125u8, + 34u8, + 250u8, + 18u8, + 74u8, + 174u8, + 196u8, + 199u8, + 232u8, + 201u8, + 25u8, + 247u8, + 144u8, + 22u8, + 226u8, + 215u8, + 180u8, + 142u8, + 238u8, + 16u8, + 86u8, + 131u8, + 117u8, + 217u8, + 139u8, + 134u8, + 70u8, + 13u8, + 27u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + 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 {}) + } + } + impl substreams_ethereum::Event for TemplatesUpdated { + const NAME: &'static str = "TemplatesUpdated"; + 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/src/abi/rollups/mod.rs b/src/abi/rollups/mod.rs new file mode 100644 index 0000000..abc36c4 --- /dev/null +++ b/src/abi/rollups/mod.rs @@ -0,0 +1 @@ +pub mod arbitrum; diff --git a/src/lib.rs b/src/lib.rs index f0d8d63..2b43c51 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +mod map_index_nitro_rollup_creations; mod map_filter_chronicle_transactions; mod map_filter_aa_transactions; mod map_combine_transactions; diff --git a/src/map_index_nitro_rollup_creations.rs b/src/map_index_nitro_rollup_creations.rs new file mode 100644 index 0000000..877bfaf --- /dev/null +++ b/src/map_index_nitro_rollup_creations.rs @@ -0,0 +1,60 @@ +use crate::abi::rollups::arbitrum::rollup_creator::events::RollupCreated; +use crate::pb::eth::transaction::v1::{NitroRollup, NitroRollups}; +use crate::abi; +use substreams::{log, Hex}; +use substreams_ethereum::Event; +use substreams_ethereum::block_view::CallView; +use substreams_ethereum::pb::eth::v2::{Block, TransactionTrace, Log, BlockHeader}; + + +#[substreams::handlers::map] +fn map_index_nitro_rollup_creations(blk: Block) -> Result> { + let header = blk.header.unwrap(); + + let rollups: Vec = blk + .transaction_traces.iter() + .filter(|trans| apply_filter(&trans)) + .map(|trans| extract_rollup_creation_event_data(&trans, &header)) + .collect(); + + Ok(NitroRollups { rollups }) +} + +fn apply_filter(transaction: &TransactionTrace) -> bool { + return transaction.calls().any(|call| create_rollup_call_filter(&call)) +} + +fn create_rollup_call_filter(call: &CallView) -> bool { + if abi::rollups::arbitrum::rollup_creator::functions::CreateRollup::match_call(&call.call) { + log::info!("createRollup() call found"); + return true; + } + + false +} + +fn rollup_created_event_decode(log: &Log) -> Option { + return abi::rollups::arbitrum::rollup_creator::events::RollupCreated::match_and_decode(log); +} + +fn extract_rollup_creation_event_data(transaction: &TransactionTrace, header: &BlockHeader) -> NitroRollup { + let optional_event = transaction.logs_with_calls() + .find_map(|(log, _call_view)| { + rollup_created_event_decode(log) + .map(|creation_event| NitroRollup { + rollup_address: Hex::encode(creation_event.rollup_address), + native_token_address: Hex::encode(creation_event.native_token), + inbox_address: Hex::encode(creation_event.inbox_address), + outbox_address: Hex::encode(creation_event.outbox), + sequencer_inbox: Hex::encode(creation_event.sequencer_inbox), + created_at: Some(header.timestamp.as_ref().unwrap().clone()) + }) + }); + + if optional_event.is_none() { + log::debug!("RollupCreated() event NOT FOUND in a Create Rollup transaction"); + } + + return optional_event.unwrap_or_default(); +} + diff --git a/src/pb/eth.transaction.v1.rs b/src/pb/eth.transaction.v1.rs index 8b840f5..f711119 100644 --- a/src/pb/eth.transaction.v1.rs +++ b/src/pb/eth.transaction.v1.rs @@ -47,6 +47,28 @@ pub struct AccountAbstractionTransaction { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] +pub struct NitroRollups { + #[prost(message, repeated, tag="1")] + pub rollups: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct NitroRollup { + #[prost(string, tag="1")] + pub rollup_address: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub native_token_address: ::prost::alloc::string::String, + #[prost(string, tag="3")] + pub inbox_address: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub outbox_address: ::prost::alloc::string::String, + #[prost(string, tag="5")] + pub sequencer_inbox: ::prost::alloc::string::String, + #[prost(message, optional, tag="6")] + pub created_at: ::core::option::Option<::prost_types::Timestamp>, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] pub struct CombinedTransactions { #[prost(message, repeated, tag="1")] pub account_abstraction_transactions: ::prost::alloc::vec::Vec, diff --git a/substreams.yaml b/substreams.yaml index 96487d2..0d46bc4 100644 --- a/substreams.yaml +++ b/substreams.yaml @@ -12,6 +12,7 @@ protobuf: files: - chronicle_transaction.proto - aa_transaction.proto + - nitro_rollup.proto - combined_transactions.proto importPaths: - ./proto @@ -22,6 +23,13 @@ binaries: file: ./target/wasm32-unknown-unknown/release/substreams.wasm modules: + - name: map_index_nitro_rollup_creations + kind: map + inputs: + - source: sf.ethereum.type.v2.Block + output: + type: proto:eth.transaction.v1.NitroRollups + - name: map_filter_aa_transactions kind: map inputs: From 8a403872f2d74e15eb19ace6d4a8ce4fa60f2b12 Mon Sep 17 00:00:00 2001 From: catalyst17 <37663786+catalyst17@users.noreply.github.com> Date: Thu, 4 Jan 2024 20:34:44 +0100 Subject: [PATCH 2/9] chore: add abi and generate .rs files --- abi/rollups/op/proxy_admin.json | 315 +++++++ build.rs | 4 + src/abi/rollups/mod.rs | 1 + src/abi/rollups/op/mod.rs | 1 + src/abi/rollups/op/proxy_admin.rs | 1403 +++++++++++++++++++++++++++++ 5 files changed, 1724 insertions(+) create mode 100644 abi/rollups/op/proxy_admin.json create mode 100644 src/abi/rollups/op/mod.rs create mode 100644 src/abi/rollups/op/proxy_admin.rs diff --git a/abi/rollups/op/proxy_admin.json b/abi/rollups/op/proxy_admin.json new file mode 100644 index 0000000..120f0e5 --- /dev/null +++ b/abi/rollups/op/proxy_admin.json @@ -0,0 +1,315 @@ +[ + { + "inputs":[ + { + "internalType":"address", + "name":"_owner", + "type":"address" + } + ], + "stateMutability":"nonpayable", + "type":"constructor" + }, + { + "anonymous":false, + "inputs":[ + { + "indexed":true, + "internalType":"address", + "name":"previousOwner", + "type":"address" + }, + { + "indexed":true, + "internalType":"address", + "name":"newOwner", + "type":"address" + } + ], + "name":"OwnershipTransferred", + "type":"event" + }, + { + "inputs":[ + + ], + "name":"addressManager", + "outputs":[ + { + "internalType":"contract AddressManager", + "name":"", + "type":"address" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + { + "internalType":"address payable", + "name":"_proxy", + "type":"address" + }, + { + "internalType":"address", + "name":"_newAdmin", + "type":"address" + } + ], + "name":"changeProxyAdmin", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "internalType":"address payable", + "name":"_proxy", + "type":"address" + } + ], + "name":"getProxyAdmin", + "outputs":[ + { + "internalType":"address", + "name":"", + "type":"address" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + { + "internalType":"address", + "name":"_proxy", + "type":"address" + } + ], + "name":"getProxyImplementation", + "outputs":[ + { + "internalType":"address", + "name":"", + "type":"address" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + { + "internalType":"address", + "name":"", + "type":"address" + } + ], + "name":"implementationName", + "outputs":[ + { + "internalType":"string", + "name":"", + "type":"string" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"isUpgrading", + "outputs":[ + { + "internalType":"bool", + "name":"", + "type":"bool" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"owner", + "outputs":[ + { + "internalType":"address", + "name":"", + "type":"address" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + { + "internalType":"address", + "name":"", + "type":"address" + } + ], + "name":"proxyType", + "outputs":[ + { + "internalType":"enum ProxyAdmin.ProxyType", + "name":"", + "type":"uint8" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"renounceOwnership", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "internalType":"string", + "name":"_name", + "type":"string" + }, + { + "internalType":"address", + "name":"_address", + "type":"address" + } + ], + "name":"setAddress", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "internalType":"contract AddressManager", + "name":"_address", + "type":"address" + } + ], + "name":"setAddressManager", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "internalType":"address", + "name":"_address", + "type":"address" + }, + { + "internalType":"string", + "name":"_name", + "type":"string" + } + ], + "name":"setImplementationName", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + + { + "inputs":[ + { + "internalType":"bool", + "name":"_upgrading", + "type":"bool" + } + ], + "name":"setUpgrading", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "internalType":"address", + "name":"newOwner", + "type":"address" + } + ], + "name":"transferOwnership", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "internalType":"address payable", + "name":"_proxy", + "type":"address" + }, + { + "internalType":"address", + "name":"_implementation", + "type":"address" + } + ], + "name":"upgrade", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "internalType":"address payable", + "name":"_proxy", + "type":"address" + }, + { + "internalType":"address", + "name":"_implementation", + "type":"address" + }, + { + "internalType":"bytes", + "name":"_data", + "type":"bytes" + } + ], + "name":"upgradeAndCall", + "outputs":[ + + ], + "stateMutability":"payable", + "type":"function" + } +] \ No newline at end of file diff --git a/build.rs b/build.rs index 4a117c8..c2fb40b 100644 --- a/build.rs +++ b/build.rs @@ -6,6 +6,10 @@ fn main() -> Result<(), anyhow::Error> { .generate()? .write_to_file("src/abi/rollups/arbitrum/rollup_creator.rs")?; + Abigen::new("Proxy Admin", "abi/rollups/op/proxy_admin.json")? + .generate()? + .write_to_file("src/abi/rollups/op/proxy_admin.rs")?; + Abigen::new("Chronicle Median", "abi/chronicle/median.json")? .generate()? .write_to_file("src/abi/chronicle/median.rs")?; diff --git a/src/abi/rollups/mod.rs b/src/abi/rollups/mod.rs index abc36c4..d7bc3a6 100644 --- a/src/abi/rollups/mod.rs +++ b/src/abi/rollups/mod.rs @@ -1 +1,2 @@ pub mod arbitrum; +pub mod op; diff --git a/src/abi/rollups/op/mod.rs b/src/abi/rollups/op/mod.rs new file mode 100644 index 0000000..17358d5 --- /dev/null +++ b/src/abi/rollups/op/mod.rs @@ -0,0 +1 @@ +pub mod proxy_admin; diff --git a/src/abi/rollups/op/proxy_admin.rs b/src/abi/rollups/op/proxy_admin.rs new file mode 100644 index 0000000..ac99951 --- /dev/null +++ b/src/abi/rollups/op/proxy_admin.rs @@ -0,0 +1,1403 @@ + 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 AddressManager {} + impl AddressManager { + const METHOD_ID: [u8; 4] = [58u8, 183u8, 110u8, 159u8]; + 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 AddressManager { + const NAME: &'static str = "addressManager"; + 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 AddressManager { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct ChangeProxyAdmin { + pub proxy: Vec, + pub new_admin: Vec, + } + impl ChangeProxyAdmin { + const METHOD_ID: [u8; 4] = [126u8, 255u8, 39u8, 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, ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + proxy: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + new_admin: 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.proxy)), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.new_admin), + ), + ], + ); + 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 ChangeProxyAdmin { + const NAME: &'static str = "changeProxyAdmin"; + 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 GetProxyAdmin { + pub proxy: Vec, + } + impl GetProxyAdmin { + const METHOD_ID: [u8; 4] = [243u8, 183u8, 222u8, 173u8]; + 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 { + proxy: 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.proxy))], + ); + 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 GetProxyAdmin { + const NAME: &'static str = "getProxyAdmin"; + 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 GetProxyAdmin { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetProxyImplementation { + pub proxy: Vec, + } + impl GetProxyImplementation { + const METHOD_ID: [u8; 4] = [32u8, 78u8, 28u8, 122u8]; + 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 { + proxy: 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.proxy))], + ); + 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 GetProxyImplementation { + const NAME: &'static str = "getProxyImplementation"; + 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 GetProxyImplementation { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct ImplementationName { + pub param0: Vec, + } + impl ImplementationName { + const METHOD_ID: [u8; 4] = [35u8, 129u8, 129u8, 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 { + param0: 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.param0))], + ); + 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 ImplementationName { + const NAME: &'static str = "implementationName"; + 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 ImplementationName { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IsUpgrading {} + impl IsUpgrading { + const METHOD_ID: [u8; 4] = [183u8, 148u8, 114u8, 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 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 IsUpgrading { + const NAME: &'static str = "isUpgrading"; + 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 IsUpgrading { + fn output(data: &[u8]) -> Result { + 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 ProxyType { + pub param0: Vec, + } + impl ProxyType { + const METHOD_ID: [u8; 4] = [107u8, 217u8, 245u8, 22u8]; + 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 { + param0: 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.param0))], + ); + 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 ProxyType { + const NAME: &'static str = "proxyType"; + 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 ProxyType { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[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 SetAddress { + pub name: String, + pub address: Vec, + } + impl SetAddress { + const METHOD_ID: [u8; 4] = [155u8, 46u8, 164u8, 189u8]; + 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::String, ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + name: values + .pop() + .expect(INTERNAL_ERR) + .into_string() + .expect(INTERNAL_ERR), + address: 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::String(self.name.clone()), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.address), + ), + ], + ); + 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 SetAddress { + const NAME: &'static str = "setAddress"; + 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 SetAddressManager { + pub address: Vec, + } + impl SetAddressManager { + const METHOD_ID: [u8; 4] = [6u8, 82u8, 181u8, 122u8]; + 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 { + address: 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.address))], + ); + 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 SetAddressManager { + const NAME: &'static str = "setAddressManager"; + 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 SetImplementationName { + pub address: Vec, + pub name: String, + } + impl SetImplementationName { + const METHOD_ID: [u8; 4] = [134u8, 15u8, 124u8, 218u8]; + 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::String], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + address: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + name: values + .pop() + .expect(INTERNAL_ERR) + .into_string() + .expect(INTERNAL_ERR), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.address), + ), + ethabi::Token::String(self.name.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 SetImplementationName { + const NAME: &'static str = "setImplementationName"; + 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 SetUpgrading { + pub upgrading: bool, + } + impl SetUpgrading { + const METHOD_ID: [u8; 4] = [7u8, 200u8, 247u8, 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::Bool], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + upgrading: values + .pop() + .expect(INTERNAL_ERR) + .into_bool() + .expect(INTERNAL_ERR), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::Bool(self.upgrading.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 SetUpgrading { + const NAME: &'static str = "setUpgrading"; + 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 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 Upgrade { + pub proxy: Vec, + pub implementation: Vec, + } + impl Upgrade { + const METHOD_ID: [u8; 4] = [153u8, 168u8, 142u8, 196u8]; + 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 { + proxy: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + implementation: 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.proxy)), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.implementation), + ), + ], + ); + 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 Upgrade { + const NAME: &'static str = "upgrade"; + 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 UpgradeAndCall { + pub proxy: Vec, + pub implementation: Vec, + pub data: Vec, + } + impl UpgradeAndCall { + const METHOD_ID: [u8; 4] = [150u8, 35u8, 96u8, 157u8]; + 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::Bytes, + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + proxy: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + implementation: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + data: values + .pop() + .expect(INTERNAL_ERR) + .into_bytes() + .expect(INTERNAL_ERR), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address(ethabi::Address::from_slice(&self.proxy)), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.implementation), + ), + ethabi::Token::Bytes(self.data.clone()), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for UpgradeAndCall { + const NAME: &'static str = "upgradeAndCall"; + 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 OwnershipTransferred { + pub previous_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 { + previous_owner: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'previous_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) + } + } + } \ No newline at end of file From 3701dfc9f9705686ed0419c08103a625c052e0e9 Mon Sep 17 00:00:00 2001 From: catalyst17 <37663786+catalyst17@users.noreply.github.com> Date: Thu, 4 Jan 2024 21:44:32 +0100 Subject: [PATCH 3/9] feat: index OP rollups creation --- proto/op_rollup.proto | 32 ++++++ src/lib.rs | 1 + src/map_index_op_rollup_creations.rs | 159 +++++++++++++++++++++++++++ src/pb/eth.transaction.v1.rs | 44 ++++++++ substreams.yaml | 8 ++ 5 files changed, 244 insertions(+) create mode 100644 proto/op_rollup.proto create mode 100644 src/map_index_op_rollup_creations.rs diff --git a/proto/op_rollup.proto b/proto/op_rollup.proto new file mode 100644 index 0000000..a0fb6ef --- /dev/null +++ b/proto/op_rollup.proto @@ -0,0 +1,32 @@ +syntax = "proto3"; + +package eth.transaction.v1; + +import "google/protobuf/timestamp.proto"; + +message OPRollups { + repeated OPRollup rollups = 1; +} + +message OPRollup { + optional string addressManagerAddress = 1; + optional string proxyAdminAddress = 2; + + optional string proxyToOptimismPortal = 3; + optional string proxyToL1CrossDomainMessenger = 4; + optional string proxyToL2OutputOracle = 5; + optional string proxyToOptimismMintableERC20Factory = 6; + optional string proxyToSystemConfig = 7; + optional string proxyToL1StandardBridge = 8; + optional string proxyToL1ERC721Bridge = 9; + + optional string implementationOptimismPortal = 10; + optional string implementationL1CrossDomainMessenger = 11; + optional string implementationL2OutputOracle = 12; + optional string implementationOptimismMintableERC20Factory = 13; + optional string implementationSystemConfig = 14; + optional string implementationL1StandardBridge = 15; + optional string implementationL1ERC721Bridge = 16; + + string deployerAddress = 17; +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 2b43c51..fa58de0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +mod map_index_op_rollup_creations; mod map_index_nitro_rollup_creations; mod map_filter_chronicle_transactions; mod map_filter_aa_transactions; diff --git a/src/map_index_op_rollup_creations.rs b/src/map_index_op_rollup_creations.rs new file mode 100644 index 0000000..627f360 --- /dev/null +++ b/src/map_index_op_rollup_creations.rs @@ -0,0 +1,159 @@ +use std::collections::HashMap; + +use crate::abi::rollups::op::proxy_admin::functions::{UpgradeAndCall, Upgrade}; +use crate::pb::eth::transaction::v1::{OpRollup, OpRollups}; +use substreams::{log, Hex}; +use substreams_ethereum::Function; +use substreams_ethereum::pb::eth::v2::{Block, TransactionTrace}; + + +#[substreams::handlers::map] +fn map_index_op_rollup_creations(blk: Block) -> Result> { + let hashes_of_contracts_code: HashMap, &str> = vec![ + ("23ff3128727914b22a2753aafff02d897826166b869a027a11b851863d379ddf", "AddressManager"), + ("aebd68b2a785d0af4b7e1f3e600efde438efa83b08f2ad8bcd9287322f396e5f", "ProxyAdmin"), + + ("0676bfdc76d647f7c152357a4e80baedfee179006b97d59bac2651848fa363dc", "OptimismPortal"), + ("cc41437cf2ce7579d78916cf908f36e830cc9e381b41344165a27477f7e0b3cf", "L1CrossDomainMessenger"), + ("59e283e0bb51f5d0833eaaea490964e1b96c7c110b3ead81f621e9b77da6378f", "L2OutputOracle"), + ("3f488ab22c60b2001f6bbd3e740be6cf330614381c93f9389b39c0fc0d5b2d8b", "OptimismMintableERC20Factory"), + ("30dd4c41053621e6ecb9d600526b682dcce4370e8c206f016e2ad0ff4ea6b6c8", "SystemConfig"), + ("3b5fd4117e40e0208c6b58506c88a39d3e514564bcb58c2d4739ec3389e43805", "L1StandardBridge"), + ("d4bcf3b7cc640f2c473a05bb03fe4f804ec84930b39cf7589fa5b8cf70d55d9b", "L1ERC721Bridge") + ].iter() + .filter_map(|(hash, name)| { + match Hex::decode(hash) { + Ok(decoded_hash) => Some((decoded_hash, *name)), + Err(_) => None, + } + }) + .collect(); + + let mut rollups: HashMap, OpRollup> = HashMap::new(); + + for trans in blk.transaction_traces.iter() { + // both try_enriching_if_* functions enrich the rollup object with either impl. or proxy addresses + try_enriching_if_implementation_contract_deployed(&mut rollups, trans, &hashes_of_contracts_code); + try_enriching_if_proxy_contract_set(&mut rollups, trans); + } + + Ok(OpRollups { rollups: rollups.values().cloned().collect() }) +} + +fn try_enriching_if_implementation_contract_deployed( + rollups: &mut HashMap, OpRollup>, + transaction: &TransactionTrace, + code_hashes_to_check_against: &HashMap, &str> +) { + for call in transaction.calls() { + if !call.call.account_creations.is_empty() { + for code_change in call.call.code_changes.iter() { + if let Some(contract_name) = code_hashes_to_check_against.get(&code_change.new_hash) { + log::info!("Deployment of {} contract found", contract_name); + + let rollup = rollups.entry(call.call.caller.clone()).or_insert_with(|| OpRollup { + address_manager_address: None, + proxy_admin_address: None, + proxy_to_optimism_portal: None, + proxy_to_l1_cross_domain_messenger: None, + proxy_to_l2_output_oracle: None, + proxy_to_optimism_mintable_erc20_factory: None, + proxy_to_system_config: None, + proxy_to_l1_standard_bridge: None, + proxy_to_l1erc721_bridge: None, + implementation_optimism_portal: None, + implementation_l1_cross_domain_messenger: None, + implementation_l2_output_oracle: None, + implementation_optimism_mintable_erc20_factory: None, + implementation_system_config: None, + implementation_l1_standard_bridge: None, + implementation_l1erc721_bridge: None, + deployer_address: Hex::encode(&call.call.caller) + }); + + match *contract_name { + "AddressManager" => { + rollup.address_manager_address = Some(Hex::encode(&code_change.address)) + }, + "ProxyAdmin" => { + rollup.proxy_admin_address = Some(Hex::encode(&code_change.address)) + }, + "OptimismPortal" => { + rollup.implementation_optimism_portal = Some(Hex::encode(&code_change.address)) + }, + "L1CrossDomainMessenger" => { + rollup.implementation_l1_cross_domain_messenger = Some(Hex::encode(&code_change.address)) + }, + "L2OutputOracle" => { + rollup.implementation_l2_output_oracle = Some(Hex::encode(&code_change.address)) + }, + "OptimismMintableERC20Factory" => { + rollup.implementation_optimism_mintable_erc20_factory = Some(Hex::encode(&code_change.address)) + }, + "SystemConfig" => { + rollup.implementation_system_config = Some(Hex::encode(&code_change.address)) + }, + "L1StandardBridge" => { + rollup.implementation_l1_standard_bridge = Some(Hex::encode(&code_change.address)) + }, + "L1ERC721Bridge" => { + rollup.implementation_l1erc721_bridge = Some(Hex::encode(&code_change.address)) + }, + _ => {} + } + } + } + } + } +} + +fn try_enriching_if_proxy_contract_set( + rollups: &mut HashMap, OpRollup>, + transaction: &TransactionTrace +) { + for call in transaction.calls() { + if let Some(decoded_call) = Upgrade::match_and_decode(call) { + enrich_with_proxy_address(rollups, decoded_call.proxy, decoded_call.implementation); + break; + } + if let Some(decoded_call) = UpgradeAndCall::match_and_decode(call) { + enrich_with_proxy_address(rollups, decoded_call.proxy, decoded_call.implementation); + break; + } + } +} + +fn enrich_with_proxy_address( + rollups: &mut HashMap, OpRollup>, + proxy_address: Vec, + implementation_address: Vec, +) { + let proxy_address_str = Hex::encode(proxy_address); + let implementation_address_str = Hex::encode(implementation_address); + for rollup in rollups.values_mut() { + match &implementation_address_str { + imp if Some(imp) == rollup.implementation_optimism_portal.as_ref() => { + rollup.proxy_to_optimism_portal = Some(proxy_address_str.clone()); + }, + imp if Some(imp) == rollup.implementation_l1_cross_domain_messenger.as_ref() => { + rollup.proxy_to_l1_cross_domain_messenger = Some(proxy_address_str.clone()); + }, + imp if Some(imp) == rollup.implementation_l2_output_oracle.as_ref() => { + rollup.proxy_to_l2_output_oracle = Some(proxy_address_str.clone()); + }, + imp if Some(imp) == rollup.implementation_optimism_mintable_erc20_factory.as_ref() => { + rollup.proxy_to_optimism_mintable_erc20_factory = Some(proxy_address_str.clone()); + }, + imp if Some(imp) == rollup.implementation_system_config.as_ref() => { + rollup.proxy_to_system_config = Some(proxy_address_str.clone()); + }, + imp if Some(imp) == rollup.implementation_l1_standard_bridge.as_ref() => { + rollup.proxy_to_l1_standard_bridge = Some(proxy_address_str.clone()); + }, + imp if Some(imp) == rollup.implementation_l1erc721_bridge.as_ref() => { + rollup.proxy_to_l1erc721_bridge = Some(proxy_address_str.clone()); + }, + _ => {} + } + } +} \ No newline at end of file diff --git a/src/pb/eth.transaction.v1.rs b/src/pb/eth.transaction.v1.rs index f711119..ea7a87a 100644 --- a/src/pb/eth.transaction.v1.rs +++ b/src/pb/eth.transaction.v1.rs @@ -47,6 +47,50 @@ pub struct AccountAbstractionTransaction { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] +pub struct OpRollups { + #[prost(message, repeated, tag="1")] + pub rollups: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OpRollup { + #[prost(string, optional, tag="1")] + pub address_manager_address: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="2")] + pub proxy_admin_address: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="3")] + pub proxy_to_optimism_portal: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="4")] + pub proxy_to_l1_cross_domain_messenger: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="5")] + pub proxy_to_l2_output_oracle: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="6")] + pub proxy_to_optimism_mintable_erc20_factory: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="7")] + pub proxy_to_system_config: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="8")] + pub proxy_to_l1_standard_bridge: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="9")] + pub proxy_to_l1erc721_bridge: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="10")] + pub implementation_optimism_portal: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="11")] + pub implementation_l1_cross_domain_messenger: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="12")] + pub implementation_l2_output_oracle: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="13")] + pub implementation_optimism_mintable_erc20_factory: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="14")] + pub implementation_system_config: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="15")] + pub implementation_l1_standard_bridge: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="16")] + pub implementation_l1erc721_bridge: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, tag="17")] + pub deployer_address: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] pub struct NitroRollups { #[prost(message, repeated, tag="1")] pub rollups: ::prost::alloc::vec::Vec, diff --git a/substreams.yaml b/substreams.yaml index 0d46bc4..c6d6886 100644 --- a/substreams.yaml +++ b/substreams.yaml @@ -12,6 +12,7 @@ protobuf: files: - chronicle_transaction.proto - aa_transaction.proto + - op_rollup.proto - nitro_rollup.proto - combined_transactions.proto importPaths: @@ -30,6 +31,13 @@ modules: output: type: proto:eth.transaction.v1.NitroRollups + - name: map_index_op_rollup_creations + kind: map + inputs: + - source: sf.ethereum.type.v2.Block + output: + type: proto:eth.transaction.v1.OpRollups + - name: map_filter_aa_transactions kind: map inputs: From ec762e4ff46611472696f898d5624261d388437f Mon Sep 17 00:00:00 2001 From: catalyst17 <37663786+catalyst17@users.noreply.github.com> Date: Thu, 4 Jan 2024 21:55:15 +0100 Subject: [PATCH 4/9] refactor: add logging --- src/map_index_op_rollup_creations.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/map_index_op_rollup_creations.rs b/src/map_index_op_rollup_creations.rs index 627f360..67341f3 100644 --- a/src/map_index_op_rollup_creations.rs +++ b/src/map_index_op_rollup_creations.rs @@ -49,7 +49,7 @@ fn try_enriching_if_implementation_contract_deployed( if !call.call.account_creations.is_empty() { for code_change in call.call.code_changes.iter() { if let Some(contract_name) = code_hashes_to_check_against.get(&code_change.new_hash) { - log::info!("Deployment of {} contract found", contract_name); + log::info!("Deployment of {} implementation contract found", contract_name); let rollup = rollups.entry(call.call.caller.clone()).or_insert_with(|| OpRollup { address_manager_address: None, @@ -130,6 +130,7 @@ fn enrich_with_proxy_address( ) { let proxy_address_str = Hex::encode(proxy_address); let implementation_address_str = Hex::encode(implementation_address); + log::info!("Upgrade of a proxy `0x{}` to the implementation `0x{}` found", proxy_address_str, implementation_address_str); for rollup in rollups.values_mut() { match &implementation_address_str { imp if Some(imp) == rollup.implementation_optimism_portal.as_ref() => { From f8b1db9ab6eeb83451f82fa14c964b779b41c0e3 Mon Sep 17 00:00:00 2001 From: catalyst17 <37663786+catalyst17@users.noreply.github.com> Date: Thu, 4 Jan 2024 21:55:25 +0100 Subject: [PATCH 5/9] refactor: imports --- src/map_index_nitro_rollup_creations.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/map_index_nitro_rollup_creations.rs b/src/map_index_nitro_rollup_creations.rs index 877bfaf..0e4d2c1 100644 --- a/src/map_index_nitro_rollup_creations.rs +++ b/src/map_index_nitro_rollup_creations.rs @@ -1,6 +1,6 @@ use crate::abi::rollups::arbitrum::rollup_creator::events::RollupCreated; +use crate::abi::rollups::arbitrum::rollup_creator::functions::CreateRollup; use crate::pb::eth::transaction::v1::{NitroRollup, NitroRollups}; -use crate::abi; use substreams::{log, Hex}; use substreams_ethereum::Event; use substreams_ethereum::block_view::CallView; @@ -25,7 +25,7 @@ fn apply_filter(transaction: &TransactionTrace) -> bool { } fn create_rollup_call_filter(call: &CallView) -> bool { - if abi::rollups::arbitrum::rollup_creator::functions::CreateRollup::match_call(&call.call) { + if CreateRollup::match_call(&call.call) { log::info!("createRollup() call found"); return true; } @@ -34,7 +34,7 @@ fn create_rollup_call_filter(call: &CallView) -> bool { } fn rollup_created_event_decode(log: &Log) -> Option { - return abi::rollups::arbitrum::rollup_creator::events::RollupCreated::match_and_decode(log); + return RollupCreated::match_and_decode(log); } fn extract_rollup_creation_event_data(transaction: &TransactionTrace, header: &BlockHeader) -> NitroRollup { From 5bd03478810f04b6f1db40571996a4e7a4e5405e Mon Sep 17 00:00:00 2001 From: catalyst17 <37663786+catalyst17@users.noreply.github.com> Date: Fri, 5 Jan 2024 13:08:08 +0100 Subject: [PATCH 6/9] refactor: move rollups to a diff package --- proto/nitro_rollup.proto | 2 +- proto/op_rollup.proto | 2 +- src/map_index_nitro_rollup_creations.rs | 2 +- src/map_index_op_rollup_creations.rs | 2 +- src/pb/eth.rollup.v1.rs | 68 +++++++++++++++++++++++++ src/pb/eth.transaction.v1.rs | 66 ------------------------ src/pb/mod.rs | 7 +++ substreams.yaml | 4 +- 8 files changed, 81 insertions(+), 72 deletions(-) create mode 100644 src/pb/eth.rollup.v1.rs diff --git a/proto/nitro_rollup.proto b/proto/nitro_rollup.proto index 0a148e7..6fe3d90 100644 --- a/proto/nitro_rollup.proto +++ b/proto/nitro_rollup.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -package eth.transaction.v1; +package eth.rollup.v1; import "google/protobuf/timestamp.proto"; diff --git a/proto/op_rollup.proto b/proto/op_rollup.proto index a0fb6ef..8d25007 100644 --- a/proto/op_rollup.proto +++ b/proto/op_rollup.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -package eth.transaction.v1; +package eth.rollup.v1; import "google/protobuf/timestamp.proto"; diff --git a/src/map_index_nitro_rollup_creations.rs b/src/map_index_nitro_rollup_creations.rs index 0e4d2c1..e3fc112 100644 --- a/src/map_index_nitro_rollup_creations.rs +++ b/src/map_index_nitro_rollup_creations.rs @@ -1,6 +1,6 @@ use crate::abi::rollups::arbitrum::rollup_creator::events::RollupCreated; use crate::abi::rollups::arbitrum::rollup_creator::functions::CreateRollup; -use crate::pb::eth::transaction::v1::{NitroRollup, NitroRollups}; +use crate::pb::eth::rollup::v1::{NitroRollup, NitroRollups}; use substreams::{log, Hex}; use substreams_ethereum::Event; use substreams_ethereum::block_view::CallView; diff --git a/src/map_index_op_rollup_creations.rs b/src/map_index_op_rollup_creations.rs index 67341f3..1505a33 100644 --- a/src/map_index_op_rollup_creations.rs +++ b/src/map_index_op_rollup_creations.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use crate::abi::rollups::op::proxy_admin::functions::{UpgradeAndCall, Upgrade}; -use crate::pb::eth::transaction::v1::{OpRollup, OpRollups}; +use crate::pb::eth::rollup::v1::{OpRollup, OpRollups}; use substreams::{log, Hex}; use substreams_ethereum::Function; use substreams_ethereum::pb::eth::v2::{Block, TransactionTrace}; diff --git a/src/pb/eth.rollup.v1.rs b/src/pb/eth.rollup.v1.rs new file mode 100644 index 0000000..e3b1e91 --- /dev/null +++ b/src/pb/eth.rollup.v1.rs @@ -0,0 +1,68 @@ +// @generated +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OpRollups { + #[prost(message, repeated, tag="1")] + pub rollups: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OpRollup { + #[prost(string, optional, tag="1")] + pub address_manager_address: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="2")] + pub proxy_admin_address: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="3")] + pub proxy_to_optimism_portal: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="4")] + pub proxy_to_l1_cross_domain_messenger: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="5")] + pub proxy_to_l2_output_oracle: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="6")] + pub proxy_to_optimism_mintable_erc20_factory: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="7")] + pub proxy_to_system_config: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="8")] + pub proxy_to_l1_standard_bridge: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="9")] + pub proxy_to_l1erc721_bridge: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="10")] + pub implementation_optimism_portal: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="11")] + pub implementation_l1_cross_domain_messenger: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="12")] + pub implementation_l2_output_oracle: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="13")] + pub implementation_optimism_mintable_erc20_factory: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="14")] + pub implementation_system_config: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="15")] + pub implementation_l1_standard_bridge: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag="16")] + pub implementation_l1erc721_bridge: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, tag="17")] + pub deployer_address: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct NitroRollups { + #[prost(message, repeated, tag="1")] + pub rollups: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct NitroRollup { + #[prost(string, tag="1")] + pub rollup_address: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub native_token_address: ::prost::alloc::string::String, + #[prost(string, tag="3")] + pub inbox_address: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub outbox_address: ::prost::alloc::string::String, + #[prost(string, tag="5")] + pub sequencer_inbox: ::prost::alloc::string::String, + #[prost(message, optional, tag="6")] + pub created_at: ::core::option::Option<::prost_types::Timestamp>, +} +// @@protoc_insertion_point(module) diff --git a/src/pb/eth.transaction.v1.rs b/src/pb/eth.transaction.v1.rs index ea7a87a..8b840f5 100644 --- a/src/pb/eth.transaction.v1.rs +++ b/src/pb/eth.transaction.v1.rs @@ -47,72 +47,6 @@ pub struct AccountAbstractionTransaction { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct OpRollups { - #[prost(message, repeated, tag="1")] - pub rollups: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct OpRollup { - #[prost(string, optional, tag="1")] - pub address_manager_address: ::core::option::Option<::prost::alloc::string::String>, - #[prost(string, optional, tag="2")] - pub proxy_admin_address: ::core::option::Option<::prost::alloc::string::String>, - #[prost(string, optional, tag="3")] - pub proxy_to_optimism_portal: ::core::option::Option<::prost::alloc::string::String>, - #[prost(string, optional, tag="4")] - pub proxy_to_l1_cross_domain_messenger: ::core::option::Option<::prost::alloc::string::String>, - #[prost(string, optional, tag="5")] - pub proxy_to_l2_output_oracle: ::core::option::Option<::prost::alloc::string::String>, - #[prost(string, optional, tag="6")] - pub proxy_to_optimism_mintable_erc20_factory: ::core::option::Option<::prost::alloc::string::String>, - #[prost(string, optional, tag="7")] - pub proxy_to_system_config: ::core::option::Option<::prost::alloc::string::String>, - #[prost(string, optional, tag="8")] - pub proxy_to_l1_standard_bridge: ::core::option::Option<::prost::alloc::string::String>, - #[prost(string, optional, tag="9")] - pub proxy_to_l1erc721_bridge: ::core::option::Option<::prost::alloc::string::String>, - #[prost(string, optional, tag="10")] - pub implementation_optimism_portal: ::core::option::Option<::prost::alloc::string::String>, - #[prost(string, optional, tag="11")] - pub implementation_l1_cross_domain_messenger: ::core::option::Option<::prost::alloc::string::String>, - #[prost(string, optional, tag="12")] - pub implementation_l2_output_oracle: ::core::option::Option<::prost::alloc::string::String>, - #[prost(string, optional, tag="13")] - pub implementation_optimism_mintable_erc20_factory: ::core::option::Option<::prost::alloc::string::String>, - #[prost(string, optional, tag="14")] - pub implementation_system_config: ::core::option::Option<::prost::alloc::string::String>, - #[prost(string, optional, tag="15")] - pub implementation_l1_standard_bridge: ::core::option::Option<::prost::alloc::string::String>, - #[prost(string, optional, tag="16")] - pub implementation_l1erc721_bridge: ::core::option::Option<::prost::alloc::string::String>, - #[prost(string, tag="17")] - pub deployer_address: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct NitroRollups { - #[prost(message, repeated, tag="1")] - pub rollups: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct NitroRollup { - #[prost(string, tag="1")] - pub rollup_address: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub native_token_address: ::prost::alloc::string::String, - #[prost(string, tag="3")] - pub inbox_address: ::prost::alloc::string::String, - #[prost(string, tag="4")] - pub outbox_address: ::prost::alloc::string::String, - #[prost(string, tag="5")] - pub sequencer_inbox: ::prost::alloc::string::String, - #[prost(message, optional, tag="6")] - pub created_at: ::core::option::Option<::prost_types::Timestamp>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] pub struct CombinedTransactions { #[prost(message, repeated, tag="1")] pub account_abstraction_transactions: ::prost::alloc::vec::Vec, diff --git a/src/pb/mod.rs b/src/pb/mod.rs index 72498b6..e2257e8 100644 --- a/src/pb/mod.rs +++ b/src/pb/mod.rs @@ -1,5 +1,12 @@ // @generated pub mod eth { + pub mod rollup { + // @@protoc_insertion_point(attribute:eth.rollup.v1) + pub mod v1 { + include!("eth.rollup.v1.rs"); + // @@protoc_insertion_point(eth.rollup.v1) + } + } pub mod transaction { // @@protoc_insertion_point(attribute:eth.transaction.v1) pub mod v1 { diff --git a/substreams.yaml b/substreams.yaml index c6d6886..f59c257 100644 --- a/substreams.yaml +++ b/substreams.yaml @@ -29,14 +29,14 @@ modules: inputs: - source: sf.ethereum.type.v2.Block output: - type: proto:eth.transaction.v1.NitroRollups + type: proto:eth.rollup.v1.NitroRollups - name: map_index_op_rollup_creations kind: map inputs: - source: sf.ethereum.type.v2.Block output: - type: proto:eth.transaction.v1.OpRollups + type: proto:eth.rollup.v1.OpRollups - name: map_filter_aa_transactions kind: map From be3c9ffe06c99c56806c0bd309fe3b0fb45277c5 Mon Sep 17 00:00:00 2001 From: catalyst17 <37663786+catalyst17@users.noreply.github.com> Date: Fri, 5 Jan 2024 13:15:20 +0100 Subject: [PATCH 7/9] feat: extend Nitro rollup data --- proto/nitro_rollup.proto | 12 ++++++++++-- src/map_index_nitro_rollup_creations.rs | 9 ++++++++- src/pb/eth.rollup.v1.rs | 18 ++++++++++++++++-- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/proto/nitro_rollup.proto b/proto/nitro_rollup.proto index 6fe3d90..260ffca 100644 --- a/proto/nitro_rollup.proto +++ b/proto/nitro_rollup.proto @@ -13,6 +13,14 @@ message NitroRollup { string nativeTokenAddress = 2; string inboxAddress = 3; string outboxAddress = 4; - string sequencerInbox = 5; - google.protobuf.Timestamp createdAt = 6; + string rollupEventInboxAddress = 5; + string challengeManagerAddress = 6; + string adminProxyAddress = 7; + string sequencerInboxAddress = 8; + string bridgeAddress = 9; + string upgradeExecutorAddress = 10; + string validatorUtilsAddress = 11; + string validatorWalletCreatorAddress = 12; + + google.protobuf.Timestamp createdAt = 13; } \ No newline at end of file diff --git a/src/map_index_nitro_rollup_creations.rs b/src/map_index_nitro_rollup_creations.rs index e3fc112..8cad63e 100644 --- a/src/map_index_nitro_rollup_creations.rs +++ b/src/map_index_nitro_rollup_creations.rs @@ -46,7 +46,14 @@ fn extract_rollup_creation_event_data(transaction: &TransactionTrace, header: &B native_token_address: Hex::encode(creation_event.native_token), inbox_address: Hex::encode(creation_event.inbox_address), outbox_address: Hex::encode(creation_event.outbox), - sequencer_inbox: Hex::encode(creation_event.sequencer_inbox), + rollup_event_inbox_address: Hex::encode(creation_event.rollup_event_inbox), + challenge_manager_address: Hex::encode(creation_event.challenge_manager), + admin_proxy_address: Hex::encode(creation_event.admin_proxy), + sequencer_inbox_address: Hex::encode(creation_event.sequencer_inbox), + bridge_address: Hex::encode(creation_event.bridge), + upgrade_executor_address: Hex::encode(creation_event.upgrade_executor), + validator_utils_address: Hex::encode(creation_event.validator_utils), + validator_wallet_creator_address: Hex::encode(creation_event.validator_wallet_creator), created_at: Some(header.timestamp.as_ref().unwrap().clone()) }) }); diff --git a/src/pb/eth.rollup.v1.rs b/src/pb/eth.rollup.v1.rs index e3b1e91..5a099f7 100644 --- a/src/pb/eth.rollup.v1.rs +++ b/src/pb/eth.rollup.v1.rs @@ -61,8 +61,22 @@ pub struct NitroRollup { #[prost(string, tag="4")] pub outbox_address: ::prost::alloc::string::String, #[prost(string, tag="5")] - pub sequencer_inbox: ::prost::alloc::string::String, - #[prost(message, optional, tag="6")] + pub rollup_event_inbox_address: ::prost::alloc::string::String, + #[prost(string, tag="6")] + pub challenge_manager_address: ::prost::alloc::string::String, + #[prost(string, tag="7")] + pub admin_proxy_address: ::prost::alloc::string::String, + #[prost(string, tag="8")] + pub sequencer_inbox_address: ::prost::alloc::string::String, + #[prost(string, tag="9")] + pub bridge_address: ::prost::alloc::string::String, + #[prost(string, tag="10")] + pub upgrade_executor_address: ::prost::alloc::string::String, + #[prost(string, tag="11")] + pub validator_utils_address: ::prost::alloc::string::String, + #[prost(string, tag="12")] + pub validator_wallet_creator_address: ::prost::alloc::string::String, + #[prost(message, optional, tag="13")] pub created_at: ::core::option::Option<::prost_types::Timestamp>, } // @@protoc_insertion_point(module) From 45bc7017520dd5b2702a7d5e1693b84bb12cc307 Mon Sep 17 00:00:00 2001 From: catalyst17 <37663786+catalyst17@users.noreply.github.com> Date: Fri, 5 Jan 2024 13:26:20 +0100 Subject: [PATCH 8/9] feat: combined rollups map module --- Makefile | 6 +++--- proto/combined_rollups.proto | 11 +++++++++++ src/lib.rs | 1 + src/map_combine_rollups.rs | 9 +++++++++ src/pb/eth.rollup.v1.rs | 8 ++++++++ substreams.yaml | 13 +++++++++++-- 6 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 proto/combined_rollups.proto create mode 100644 src/map_combine_rollups.rs diff --git a/Makefile b/Makefile index 04070ab..094448d 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ -include .env export -START_BLOCK ?= 18664500 +START_BLOCK ?= 4051031 STOP_BLOCK ?= 0 .PHONY: build @@ -10,7 +10,7 @@ build: .PHONY: run run: build - substreams run -e $(ENDPOINT) substreams.yaml map_combine_transactions -s $(START_BLOCK) -t $(STOP_BLOCK) + substreams run -e $(ENDPOINT) substreams.yaml map_combine_rollups -s $(START_BLOCK) -t $(STOP_BLOCK) .PHONY: sink sink: build @@ -19,7 +19,7 @@ sink: build .PHONY: gui gui: build - substreams gui -e $(ENDPOINT) substreams.yaml map_combine_transactions -s $(START_BLOCK) -t $(STOP_BLOCK) + substreams gui -e $(ENDPOINT) substreams.yaml map_combine_rollups -s $(START_BLOCK) -t $(STOP_BLOCK) .PHONY: protogen protogen: diff --git a/proto/combined_rollups.proto b/proto/combined_rollups.proto new file mode 100644 index 0000000..564e657 --- /dev/null +++ b/proto/combined_rollups.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +package eth.rollup.v1; + +import "nitro_rollup.proto"; +import "op_rollup.proto"; + +message CombinedRollups { + repeated NitroRollup nitroRollups = 1; + repeated OPRollup opRollups = 2; +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index fa58de0..f612189 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ mod map_index_op_rollup_creations; mod map_index_nitro_rollup_creations; +mod map_combine_rollups; mod map_filter_chronicle_transactions; mod map_filter_aa_transactions; mod map_combine_transactions; diff --git a/src/map_combine_rollups.rs b/src/map_combine_rollups.rs new file mode 100644 index 0000000..548db4b --- /dev/null +++ b/src/map_combine_rollups.rs @@ -0,0 +1,9 @@ +use crate::pb::eth::rollup::v1::{CombinedRollups, NitroRollups, OpRollups}; + +#[substreams::handlers::map] +fn map_combine_rollups( + nitro_rollups: NitroRollups, + op_rollups: OpRollups +) -> Result> { + Ok(CombinedRollups { nitro_rollups: nitro_rollups.rollups, op_rollups: op_rollups.rollups }) +} \ No newline at end of file diff --git a/src/pb/eth.rollup.v1.rs b/src/pb/eth.rollup.v1.rs index 5a099f7..1385ecc 100644 --- a/src/pb/eth.rollup.v1.rs +++ b/src/pb/eth.rollup.v1.rs @@ -79,4 +79,12 @@ pub struct NitroRollup { #[prost(message, optional, tag="13")] pub created_at: ::core::option::Option<::prost_types::Timestamp>, } +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CombinedRollups { + #[prost(message, repeated, tag="1")] + pub nitro_rollups: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="2")] + pub op_rollups: ::prost::alloc::vec::Vec, +} // @@protoc_insertion_point(module) diff --git a/substreams.yaml b/substreams.yaml index f59c257..700dae6 100644 --- a/substreams.yaml +++ b/substreams.yaml @@ -10,10 +10,11 @@ network: mainnet protobuf: files: - - chronicle_transaction.proto - - aa_transaction.proto - op_rollup.proto - nitro_rollup.proto + - combined_rollups.proto + - chronicle_transaction.proto + - aa_transaction.proto - combined_transactions.proto importPaths: - ./proto @@ -37,6 +38,14 @@ modules: - source: sf.ethereum.type.v2.Block output: type: proto:eth.rollup.v1.OpRollups + + - name: map_combine_rollups + kind: map + inputs: + - map: map_index_nitro_rollup_creations + - map: map_index_op_rollup_creations + output: + type: proto:eth.rollup.v1.CombinedRollups - name: map_filter_aa_transactions kind: map From ed8a20d8a9c4d9ccec59d59067e24dbd65b451ba Mon Sep 17 00:00:00 2001 From: catalyst17 <37663786+catalyst17@users.noreply.github.com> Date: Fri, 5 Jan 2024 14:04:07 +0100 Subject: [PATCH 9/9] chore: upgrade version --- substreams.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substreams.yaml b/substreams.yaml index 700dae6..e188615 100644 --- a/substreams.yaml +++ b/substreams.yaml @@ -1,7 +1,7 @@ specVersion: v0.1.0 package: name: "blocktorch_substreams" - version: v0.1.0 + version: v0.1.1 imports: sql: https://github.com/streamingfast/substreams-sink-sql/releases/download/protodefs-v1.0.3/substreams-sink-sql-protodefs-v1.0.3.spkg