diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 928c767..d3c161a 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -75,38 +75,6 @@ jobs: - name: cargo clippy --workspace --all-targets --all-features -- -D warnings run: cargo clippy --workspace --all-targets --all-features -- -D warnings - cargo-fix: - name: cargo fix - runs-on: ubuntu-latest - steps: - - name: Check-Out - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - with: - version: stable - - - uses: Swatinem/rust-cache@v2 - with: - key: cargo-fix - cache-on-failure: true - - - name: cargo clippy --workspace --all-targets --all-features -- -D warnings - run: | - # Run cargo fix on the project - cargo clippy --workspace --all-targets --all-features -- -D warnings - - # Check for local git changes - if ! git diff --exit-code; then - echo "There are local changes after running 'cargo clippy --workspace --all-targets --all-features' ❌" - exit 1 - else - echo "No changes detected after running 'cargo clippy --workspace --all-targets --all-features' ✅" - fi - cargo-test: name: cargo test runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 7cadd1a..3786f51 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /target .vscode/ .DS_Store -.env \ No newline at end of file +.env +.claude \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index ce841fc..7905879 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4098,6 +4098,7 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" name = "lib-reth" version = "0.1.0" dependencies = [ + "alloy-eips", "alloy-network", "alloy-primitives", "alloy-provider", @@ -10348,10 +10349,11 @@ dependencies = [ "async-trait", "auto_impl", "dotenv", - "eth-network-exts", "eyre", "futures", "itertools 0.14.0", + "op-alloy-network", + "reth-optimism-rpc", "reth-provider", "reth-rpc", "reth-rpc-convert", diff --git a/crates/eth-network-exts/src/impls/base_mainnet.rs b/crates/eth-network-exts/src/impls/base_mainnet.rs index 7286f96..950a98d 100644 --- a/crates/eth-network-exts/src/impls/base_mainnet.rs +++ b/crates/eth-network-exts/src/impls/base_mainnet.rs @@ -1,12 +1,12 @@ +use std::marker::PhantomData; + use op_alloy_network::Optimism; use reth_optimism_node::OpNode; use crate::{AllExtensions, EthNetworkExt}; -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct BaseMainnetExt(Extension) -where - Extension: AllExtensions; +#[derive(Default, Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct BaseMainnetExt(PhantomData); impl EthNetworkExt for BaseMainnetExt { type AlloyNetwork = Optimism; diff --git a/crates/eth-network-exts/src/impls/mainnet.rs b/crates/eth-network-exts/src/impls/mainnet.rs index 4b271b6..a9052c5 100644 --- a/crates/eth-network-exts/src/impls/mainnet.rs +++ b/crates/eth-network-exts/src/impls/mainnet.rs @@ -1,12 +1,12 @@ +use std::marker::PhantomData; + use alloy_network::Ethereum; use reth_node_ethereum::EthereumNode; use crate::{AllExtensions, EthNetworkExt}; -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct MainnetExt(Extension) -where - Extension: AllExtensions; +#[derive(Default, Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct MainnetExt(PhantomData); impl EthNetworkExt for MainnetExt { type AlloyNetwork = Ethereum; diff --git a/crates/eth-network-exts/src/impls/sepolia_testnet.rs b/crates/eth-network-exts/src/impls/sepolia_testnet.rs index 459f06f..552d88b 100644 --- a/crates/eth-network-exts/src/impls/sepolia_testnet.rs +++ b/crates/eth-network-exts/src/impls/sepolia_testnet.rs @@ -1,12 +1,12 @@ +use std::marker::PhantomData; + use alloy_network::Ethereum; use reth_node_ethereum::EthereumNode; use crate::{AllExtensions, EthNetworkExt}; -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct SepoliaTestnetExt(Extension) -where - Extension: AllExtensions; +#[derive(Default, Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct SepoliaTestnetExt(PhantomData); impl EthNetworkExt for SepoliaTestnetExt { type AlloyNetwork = Ethereum; diff --git a/crates/eth-network-exts/src/impls/unichain_mainnet.rs b/crates/eth-network-exts/src/impls/unichain_mainnet.rs index e8515bf..854e9d5 100644 --- a/crates/eth-network-exts/src/impls/unichain_mainnet.rs +++ b/crates/eth-network-exts/src/impls/unichain_mainnet.rs @@ -1,12 +1,12 @@ +use std::marker::PhantomData; + use op_alloy_network::Optimism; use reth_optimism_node::OpNode; use crate::{AllExtensions, EthNetworkExt}; -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct UnichainMainnetExt(Extension) -where - Extension: AllExtensions; +#[derive(Default, Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct UnichainMainnetExt(PhantomData); impl EthNetworkExt for UnichainMainnetExt { type AlloyNetwork = Optimism; diff --git a/crates/eth-network-exts/src/lib.rs b/crates/eth-network-exts/src/lib.rs index 5daf21e..83118b0 100644 --- a/crates/eth-network-exts/src/lib.rs +++ b/crates/eth-network-exts/src/lib.rs @@ -2,7 +2,7 @@ mod impls; pub use impls::*; pub trait EthNetworkExt: Send + Sync { - type AlloyNetwork: alloy_network::Network; + type AlloyNetwork: alloy_network::Network + Unpin; type RethNode: reth_node_types::NodeTypes; /// an arbitrary type extension type TypeExt; diff --git a/crates/lib-reth/Cargo.toml b/crates/lib-reth/Cargo.toml index 1654455..ce7cf71 100644 --- a/crates/lib-reth/Cargo.toml +++ b/crates/lib-reth/Cargo.toml @@ -63,6 +63,7 @@ alloy-rpc-types = { workspace = true, default-features = false, features = [ "eth", ] } alloy-primitives = { workspace = true, default-features = false } +alloy-eips = { workspace = true, optional = true } op-alloy-network = { workspace = true, optional = true } op-alloy-consensus = { workspace = true, optional = true } @@ -126,6 +127,6 @@ reth-libmdbx = [ "dep:reth-storage-api", ] -uniswap-storage = ["dep:uniswap-storage"] +uniswap-storage = ["dep:uniswap-storage", "dep:alloy-eips"] ci = [] diff --git a/crates/lib-reth/src/lib.rs b/crates/lib-reth/src/lib.rs index 828af0d..2ac4b13 100644 --- a/crates/lib-reth/src/lib.rs +++ b/crates/lib-reth/src/lib.rs @@ -20,6 +20,7 @@ pub use regular_reth::*; mod regular_reth { pub use reth_chainspec::*; pub use reth_node_ethereum::EthereumNode; + pub use reth_node_types::NodeTypes; pub use reth_rpc_eth_api::*; pub use reth_storage_api::*; pub use revm::*; diff --git a/crates/lib-reth/src/reth_libmdbx/node_types/mod.rs b/crates/lib-reth/src/reth_libmdbx/node_types/mod.rs index 873acca..61fa8db 100644 --- a/crates/lib-reth/src/reth_libmdbx/node_types/mod.rs +++ b/crates/lib-reth/src/reth_libmdbx/node_types/mod.rs @@ -1,5 +1,7 @@ use std::sync::Arc; +#[cfg(feature = "revm")] +use alloy_eips::BlockId; use alloy_provider::{IpcConnect, RootProvider, WsConnect, builder}; use eth_network_exts::EthNetworkExt; use reth_node_types::NodeTypes; @@ -9,8 +11,6 @@ use reth_provider::{ use reth_rpc_eth_api::{EthApiTypes, FullEthApiServer, RpcNodeCore, helpers::FullEthApi}; use reth_tasks::TaskSpawner; -#[cfg(feature = "revm")] -use crate::traits::BlockNumberOrHash; use crate::{reth_libmdbx::DbConfig, traits::EthStream}; pub mod node; @@ -126,17 +126,10 @@ where { type InnerDb = crate::traits::reth_revm_utils::RethLibmdbxDatabaseRef; - fn make_inner_db>(&self, block: T) -> eyre::Result { + fn make_inner_db(&self, block: BlockId) -> eyre::Result { use reth_provider::StateProviderFactory; - let block: BlockNumberOrHash = block.into(); - - let state_provider = match block { - BlockNumberOrHash::Number(num) => self - .eth_db_provider() - .state_by_block_number_or_tag(num.into())?, - BlockNumberOrHash::Hash(hash) => self.eth_db_provider().state_by_block_hash(hash)? - }; + let state_provider = self.eth_db_provider().state_by_block_id(block)?; let this = reth_revm::database::StateProviderDatabase::new(state_provider); Ok(crate::traits::reth_revm_utils::RethLibmdbxDatabaseRef::new(this)) diff --git a/crates/lib-reth/src/traits/reth_revm_utils.rs b/crates/lib-reth/src/traits/reth_revm_utils.rs index a92687d..7e42896 100644 --- a/crates/lib-reth/src/traits/reth_revm_utils.rs +++ b/crates/lib-reth/src/traits/reth_revm_utils.rs @@ -95,6 +95,7 @@ impl From for RevmUtilError { #[cfg(feature = "uniswap-storage")] mod _uniswap_storage { + use alloy_eips::BlockId; use alloy_primitives::{Address, StorageKey, StorageValue}; use eth_network_exts::EthNetworkExt; use reth_provider::StateProvider; @@ -108,7 +109,8 @@ mod _uniswap_storage { #[async_trait::async_trait] impl StorageSlotFetcher for RethLibmdbxDatabaseRef { - async fn storage_at(&self, address: Address, key: StorageKey, _: Option) -> eyre::Result { + async fn storage_at(&self, address: Address, key: StorageKey, block_id: BlockId) -> eyre::Result { + let _ = block_id; let db = self.0.lock().map_err(|e| eyre::eyre!("{e}"))?; Ok(db.storage(address, key)?.unwrap_or_default()) } @@ -119,15 +121,10 @@ mod _uniswap_storage { where Ext::RethNode: NodeClientSpec { - async fn storage_at( - &self, - address: Address, - key: StorageKey, - block_number: Option - ) -> eyre::Result { + async fn storage_at(&self, address: Address, key: StorageKey, block_id: BlockId) -> eyre::Result { Ok(self .eth_api() - .storage_at(address, key.into(), block_number.map(Into::into)) + .storage_at(address, key.into(), Some(block_id)) .await? .into()) } diff --git a/crates/lib-reth/src/traits/revm.rs b/crates/lib-reth/src/traits/revm.rs index 48ee587..0117105 100644 --- a/crates/lib-reth/src/traits/revm.rs +++ b/crates/lib-reth/src/traits/revm.rs @@ -1,4 +1,4 @@ -use alloy_primitives::B256; +use alloy_eips::BlockId; use revm::{ Context, DatabaseRef, MainBuilder, MainContext, context::{BlockEnv, CfgEnv, Evm, TxEnv}, @@ -15,39 +15,21 @@ pub type RevmEvm = Evm< EthFrame >; -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum BlockNumberOrHash { - Number(u64), - Hash(B256) -} - -impl From for BlockNumberOrHash { - fn from(value: u64) -> Self { - Self::Number(value) - } -} - -impl From for BlockNumberOrHash { - fn from(value: B256) -> Self { - Self::Hash(value) - } -} - /// revm utils pub trait EthRevm { type InnerDb: DatabaseRef; /// `makes the inner database fetcher` - fn make_inner_db>(&self, block: T) -> eyre::Result; + fn make_inner_db(&self, block_id: BlockId) -> eyre::Result; /// `makes a new cache db` - fn make_cache_db>(&self, block: T) -> eyre::Result> { - Ok(CacheDB::new(self.make_inner_db(block)?)) + fn make_cache_db(&self, block_id: BlockId) -> eyre::Result> { + Ok(CacheDB::new(self.make_inner_db(block_id)?)) } /// `makes a new cache db` - fn make_empty_evm>(&self, block: T) -> eyre::Result>> { - let cache = self.make_cache_db(block)?; + fn make_empty_evm(&self, block_id: BlockId) -> eyre::Result>> { + let cache = self.make_cache_db(block_id)?; let evm = Context::mainnet().with_db(cache).build_mainnet(); Ok(evm) } diff --git a/crates/uniswap-storage/Cargo.toml b/crates/uniswap-storage/Cargo.toml index f7c1ed0..3a908c3 100644 --- a/crates/uniswap-storage/Cargo.toml +++ b/crates/uniswap-storage/Cargo.toml @@ -21,31 +21,35 @@ alloy-network.workspace = true revm-database = { workspace = true, optional = true, features = ["alloydb"] } reth-provider = { workspace = true, optional = true } +reth-optimism-rpc = { workspace = true, optional = true } reth-rpc = { workspace = true, optional = true } reth-rpc-convert = { workspace = true, optional = true } -eth-network-exts.workspace = true futures.workspace = true serde = { version = "1", features = ["derive"] } -auto_impl = "1.3" -eyre = "0.6.12" +auto_impl.workspace = true +eyre.workspace = true itertools = "0.14" -async-trait = "0" +async-trait.workspace = true + [dev-dependencies] -alloy-provider = { version = "1.1.3", default-features = false, features = [ +alloy-provider = { workspace = true, default-features = false, features = [ "pubsub", "ws", ] } -tokio = { version = "1", features = ["full"] } +tokio = { workspace = true, features = ["full"] } dotenv = "0.15" +op-alloy-network = { version = "0.23.1", default-features = false } [features] -default = ["full", "revm"] -full = ["v4", "v3", "angstrom"] +default = ["v4", "v3", "l1-angstrom", "revm"] +full = ["v4", "v3", "l1-angstrom", "l2-angstrom"] + v4 = [] v3 = [] -angstrom = [] +l1-angstrom = ["v4"] +l2-angstrom = ["v4"] revm = ["dep:revm-database"] local-reth = [ @@ -53,4 +57,5 @@ local-reth = [ "dep:reth-provider", "dep:reth-rpc", "dep:reth-rpc-convert", + "dep:reth-optimism-rpc", ] diff --git a/crates/uniswap-storage/src/angstrom/l2/angstrom_l2.rs b/crates/uniswap-storage/src/angstrom/l2/angstrom_l2.rs index 4b82a53..70195de 100644 --- a/crates/uniswap-storage/src/angstrom/l2/angstrom_l2.rs +++ b/crates/uniswap-storage/src/angstrom/l2/angstrom_l2.rs @@ -10,24 +10,22 @@ |-----------------------+-----------------------------------------------------------+------+--------+-------+-------------------------------| | liquidityBeforeSwap | struct tuint256 | 3 | 0 | 32 | src/AngstromL2.sol:AngstromL2 | |-----------------------+-----------------------------------------------------------+------+--------+-------+-------------------------------| -| slot0BeforeSwapStore | struct tbytes32 | 4 | 0 | 32 | src/AngstromL2.sol:AngstromL2 | +| swapFee | struct tuint256 | 4 | 0 | 32 | src/AngstromL2.sol:AngstromL2 | |-----------------------+-----------------------------------------------------------+------+--------+-------+-------------------------------| -| poolKeys | struct PoolKey[] | 5 | 0 | 32 | src/AngstromL2.sol:AngstromL2 | +| slot0BeforeSwapStore | struct tbytes32 | 5 | 0 | 32 | src/AngstromL2.sol:AngstromL2 | +|-----------------------+-----------------------------------------------------------+------+--------+-------+-------------------------------| +| poolKeys | struct PoolKey[] | 6 | 0 | 32 | src/AngstromL2.sol:AngstromL2 | +|-----------------------+-----------------------------------------------------------+------+--------+-------+-------------------------------| +| priorityFeeTaxFloor | uint256 | 7 | 0 | 32 | src/AngstromL2.sol:AngstromL2 | +|-----------------------+-----------------------------------------------------------+------+--------+-------+-------------------------------| +| jitTaxEnabled | bool | 8 | 0 | 1 | src/AngstromL2.sol:AngstromL2 | ╰-----------------------+-----------------------------------------------------------+------+--------+-------+-------------------------------╯ -struct PoolRewards { - mapping(bytes32 uniPositionKey => Position position) positions; - mapping(int24 tick => uint256 growthOutsideX128) rewardGrowthOutsideX128; - uint256 globalGrowthX128; -} - -struct Position { - uint256 lastGrowthInsideX128; -} */ use std::pin::Pin; +use alloy_eips::BlockId; use alloy_primitives::{ Address, B256, U160, U256, aliases::{I24, U24}, @@ -38,49 +36,81 @@ use futures::{Stream, StreamExt, stream::FuturesUnordered}; use crate::{ StorageSlotFetcher, + angstrom::l2::AngstromL2PoolFeeConfiguration, v4::{V4PoolKey, utils::encode_position_key} }; pub const ANGSTROM_L2_REWARDS_SLOT: u64 = 0; pub const ANGSTROM_L2_POOL_FEE_CONFIG_SLOT: u64 = 2; -pub const ANGSTROM_L2_POOL_KEYS_SLOT: u64 = 5; +pub const ANGSTROM_L2_POOL_KEYS_SLOT: u64 = 6; +pub const ANGSTROM_L2_PRIORITY_FEE_TAX_FLOOR_SLOT: u64 = 7; +pub const ANGSTROM_L2_JIT_TAX_ENABLED_SLOT: u64 = 8; + +// Backward compatibility with pre-swapFee deployments. +const ANGSTROM_L2_LEGACY_POOL_KEYS_SLOT: u64 = 5; + +async fn angstrom_l2_pool_keys_slot_and_length( + slot_fetcher: &F, + hook_address: Address, + block_id: BlockId +) -> eyre::Result<(u64, u64)> { + let current_length = slot_fetcher + .storage_at(hook_address, U256::from(ANGSTROM_L2_POOL_KEYS_SLOT).into(), block_id) + .await? + .to::(); + + if current_length != 0 { + return Ok((ANGSTROM_L2_POOL_KEYS_SLOT, current_length)); + } + + let legacy_length = slot_fetcher + .storage_at(hook_address, U256::from(ANGSTROM_L2_LEGACY_POOL_KEYS_SLOT).into(), block_id) + .await? + .to::(); + + if legacy_length != 0 { + return Ok((ANGSTROM_L2_LEGACY_POOL_KEYS_SLOT, legacy_length)); + } + + Ok((ANGSTROM_L2_POOL_KEYS_SLOT, 0)) +} pub async fn angstrom_l2_pool_keys_stream( slot_fetcher: &F, hook_address: Address, - block_number: Option + block_id: BlockId ) -> eyre::Result> + Send + '_>>>> { - let length_slot = U256::from(ANGSTROM_L2_POOL_KEYS_SLOT); - let array_length = slot_fetcher - .storage_at(hook_address, length_slot.into(), block_number) - .await?; - - let length = array_length.to::(); + let (pool_keys_slot, length) = angstrom_l2_pool_keys_slot_and_length(slot_fetcher, hook_address, block_id).await?; if length == 0 { return Ok(None); } + let length_slot = U256::from(pool_keys_slot); let array_data_base_slot = keccak256(length_slot.abi_encode()); let base_slot_value = U256::from_be_bytes(array_data_base_slot.0); let stream = (0..length) .map(|i| async move { - let element_offset = i * 5; + let element_offset = i * 3; - let futures = (0..5).map(|j| { + let futures = (0..3).map(|j| { let slot = base_slot_value + U256::from(element_offset) + U256::from(j); - slot_fetcher.storage_at(hook_address, slot.into(), block_number) + slot_fetcher.storage_at(hook_address, slot.into(), block_id) }); let slots: Vec = futures::future::try_join_all(futures).await?; + let packed_currency1_fee_tick_spacing = slots[1]; + let currency_mask = U256::from(U160::MAX); + let fee = U24::from(U256::to::(&((packed_currency1_fee_tick_spacing >> 160) & U256::from(0xFFFFFF)))); + let tick_spacing_bits = U256::to::(&((packed_currency1_fee_tick_spacing >> 184) & U256::from(0xFFFFFF))); let pool_key = V4PoolKey { - currency0: Address::from(U160::from(slots[0])), - currency1: Address::from(U160::from(slots[1])), - fee: U24::from(slots[2].to::() & 0xFFFFFF), - tickSpacing: I24::unchecked_from(((slots[3].to::() & 0xFFFFFF) as i32) << 8 >> 8), - hooks: Address::from(U160::from(slots[4])) + currency0: Address::from(U160::from(slots[0])), + currency1: Address::from(U160::from(packed_currency1_fee_tick_spacing & currency_mask)), + fee, + tickSpacing: I24::unchecked_from(((tick_spacing_bits as i32) << 8) >> 8), + hooks: Address::from(U160::from(slots[2])) }; eyre::Ok(pool_key) @@ -93,14 +123,14 @@ pub async fn angstrom_l2_pool_keys_stream( pub async fn angstrom_l2_pool_keys_filter( slot_fetcher: &F, hook_address: Address, - block_number: Option, + block_id: BlockId, search_fn: impl Fn(V4PoolKey) -> bool, find_count: usize ) -> eyre::Result> { assert_ne!(find_count, 0); let mut pool_keys = Vec::new(); - if let Some(mut key_stream) = angstrom_l2_pool_keys_stream(slot_fetcher, hook_address, block_number).await? { + if let Some(mut key_stream) = angstrom_l2_pool_keys_stream(slot_fetcher, hook_address, block_id).await? { while let Some(pool_key_res) = key_stream.next().await { let pool_key = pool_key_res?; if search_fn(pool_key) { @@ -131,12 +161,12 @@ pub async fn angstrom_l2_growth_inside( current_pool_tick: I24, tick_lower: I24, tick_upper: I24, - block_number: Option + block_id: BlockId ) -> eyre::Result { let (lower_growth, upper_growth, global_growth) = futures::try_join!( - angstrom_l2_tick_growth_outside(slot_fetcher, hook_address, pool_id, tick_lower, block_number,), - angstrom_l2_tick_growth_outside(slot_fetcher, hook_address, pool_id, tick_upper, block_number,), - angstrom_l2_global_growth(slot_fetcher, hook_address, pool_id, block_number,), + angstrom_l2_tick_growth_outside(slot_fetcher, hook_address, pool_id, tick_lower, block_id,), + angstrom_l2_tick_growth_outside(slot_fetcher, hook_address, pool_id, tick_upper, block_id,), + angstrom_l2_global_growth(slot_fetcher, hook_address, pool_id, block_id,), )?; let rewards = if current_pool_tick < tick_lower { @@ -156,11 +186,11 @@ pub async fn angstrom_l2_global_growth( slot_fetcher: &F, hook_address: Address, pool_id: B256, - block_number: Option + block_id: BlockId ) -> eyre::Result { let pool_rewards_slot_base = U256::from_be_bytes(angstrom_l2_pool_rewards_slot(pool_id).0); let global_growth = slot_fetcher - .storage_at(hook_address, (pool_rewards_slot_base + U256::from(2)).into(), block_number) + .storage_at(hook_address, (pool_rewards_slot_base + U256::from(2)).into(), block_id) .await?; Ok(global_growth) @@ -171,7 +201,7 @@ pub async fn angstrom_l2_tick_growth_outside( hook_address: Address, pool_id: B256, tick: I24, - block_number: Option + block_id: BlockId ) -> eyre::Result { let pool_rewards_slot_base = U256::from_be_bytes(angstrom_l2_pool_rewards_slot(pool_id).0); let tick_mapping_slot = pool_rewards_slot_base + U256::from(1); @@ -179,7 +209,7 @@ pub async fn angstrom_l2_tick_growth_outside( let tick_growth_slot = keccak256((tick, tick_mapping_slot).abi_encode()); let growth_outside = slot_fetcher - .storage_at(hook_address, tick_growth_slot, block_number) + .storage_at(hook_address, tick_growth_slot, block_id) .await?; Ok(growth_outside) @@ -193,27 +223,18 @@ pub async fn angstrom_l2_last_growth_inside( position_token_id: U256, tick_lower: I24, tick_upper: I24, - block_number: Option + block_id: BlockId ) -> eyre::Result { let position_key = encode_position_key(position_manager_address, position_token_id, tick_lower, tick_upper); let position_slot = U256::from_be_bytes(angstrom_l2_position_slot(pool_id, position_key).0); let growth = slot_fetcher - .storage_at(hook_address, position_slot.into(), block_number) + .storage_at(hook_address, position_slot.into(), block_id) .await?; Ok(growth) } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct AngstromL2PoolFeeConfiguration { - pub is_initialized: bool, - pub creator_tax_fee_e6: u32, - pub protocol_tax_fee_e6: u32, - pub creator_swap_fee_e6: u32, - pub protocol_swap_fee_e6: u32 -} - pub fn angstrom_l2_pool_fee_config_slot(pool_id: B256) -> B256 { keccak256((pool_id, U256::from(ANGSTROM_L2_POOL_FEE_CONFIG_SLOT)).abi_encode()) } @@ -222,27 +243,15 @@ pub async fn angstrom_l2_pool_fee_config( slot_fetcher: &F, hook_address: Address, pool_id: B256, - block_number: Option + block_id: BlockId ) -> eyre::Result { let config_slot = angstrom_l2_pool_fee_config_slot(pool_id); let packed_config = slot_fetcher - .storage_at(hook_address, config_slot, block_number) + .storage_at(hook_address, config_slot, block_id) .await?; - let is_initialized = (packed_config & U256::from(1)) != U256::ZERO; - let creator_tax_fee_e6 = U256::to::(&((packed_config >> 8) & U256::from(0xFFFFFF))); - let protocol_tax_fee_e6 = U256::to::(&((packed_config >> 32) & U256::from(0xFFFFFF))); - let creator_swap_fee_e6 = U256::to::(&((packed_config >> 56) & U256::from(0xFFFFFF))); - let protocol_swap_fee_e6 = U256::to::(&((packed_config >> 80) & U256::from(0xFFFFFF))); - - Ok(AngstromL2PoolFeeConfiguration { - is_initialized, - creator_tax_fee_e6, - protocol_tax_fee_e6, - creator_swap_fee_e6, - protocol_swap_fee_e6 - }) + Ok(AngstromL2PoolFeeConfiguration::from(packed_config)) } /// Checks if a pool is initialized @@ -250,9 +259,9 @@ pub async fn angstrom_l2_is_pool_initialized( slot_fetcher: &F, hook_address: Address, pool_id: B256, - block_number: Option + block_id: BlockId ) -> eyre::Result { - let config = angstrom_l2_pool_fee_config(slot_fetcher, hook_address, pool_id, block_number).await?; + let config = angstrom_l2_pool_fee_config(slot_fetcher, hook_address, pool_id, block_id).await?; Ok(config.is_initialized) } @@ -261,9 +270,9 @@ pub async fn angstrom_l2_total_swap_fee_rate_e6( slot_fetcher: &F, hook_address: Address, pool_id: B256, - block_number: Option + block_id: BlockId ) -> eyre::Result { - let config = angstrom_l2_pool_fee_config(slot_fetcher, hook_address, pool_id, block_number).await?; + let config = angstrom_l2_pool_fee_config(slot_fetcher, hook_address, pool_id, block_id).await?; Ok(config.creator_swap_fee_e6 + config.protocol_swap_fee_e6) } @@ -272,8 +281,220 @@ pub async fn angstrom_l2_total_tax_fee_rate_e6( slot_fetcher: &F, hook_address: Address, pool_id: B256, - block_number: Option + block_id: BlockId ) -> eyre::Result { - let config = angstrom_l2_pool_fee_config(slot_fetcher, hook_address, pool_id, block_number).await?; + let config = angstrom_l2_pool_fee_config(slot_fetcher, hook_address, pool_id, block_id).await?; Ok(config.creator_tax_fee_e6 + config.protocol_tax_fee_e6) } + +pub async fn angstrom_l2_priority_fee_tax_floor( + slot_fetcher: &F, + hook_address: Address, + block_id: BlockId +) -> eyre::Result { + slot_fetcher + .storage_at(hook_address, U256::from(ANGSTROM_L2_PRIORITY_FEE_TAX_FLOOR_SLOT).into(), block_id) + .await +} + +pub async fn angstrom_l2_jit_tax_enabled( + slot_fetcher: &F, + hook_address: Address, + block_id: BlockId +) -> eyre::Result { + let packed = slot_fetcher + .storage_at(hook_address, U256::from(ANGSTROM_L2_JIT_TAX_ENABLED_SLOT).into(), block_id) + .await?; + + Ok((packed & U256::from(0xFF)) != U256::ZERO) +} + +#[cfg(test)] +mod test { + use alloy_eips::BlockId; + use alloy_primitives::{address, aliases::I24, b256}; + use futures::StreamExt; + + use super::*; + use crate::{angstrom::l2::ANGSTROM_L2_CONSTANTS_BASE_MAINNET, test_utils::eth_base_provider}; + + const HOOK_ADDRESS: Address = address!("0xC7F6fFDb7a058ac431b852Bc1bF00cc0Fd4c65Cf"); + const POOL_ID: B256 = b256!("0x343ee3036741f45b5512ebf7ad0d8ab259dbb8e5a38ff0d19022da176ee04574"); + const BLOCK_NUMBER: u64 = 40426000; + + #[tokio::test] + async fn test_angstrom_l2_pool_keys_stream() { + let provider = eth_base_provider().await; + + let stream = angstrom_l2_pool_keys_stream(&provider, HOOK_ADDRESS, BlockId::number(BLOCK_NUMBER)) + .await + .unwrap(); + + assert!(stream.is_some()); + let mut stream = stream.unwrap(); + + let first_key = stream.next().await; + assert!(first_key.is_some()); + let pool_key = first_key.unwrap().unwrap(); + + assert_eq!(pool_key.hooks, HOOK_ADDRESS); + } + + #[tokio::test] + async fn test_angstrom_l2_pool_keys_filter() { + let provider = eth_base_provider().await; + + let result = angstrom_l2_pool_keys_filter( + &provider, + HOOK_ADDRESS, + BlockId::number(BLOCK_NUMBER), + |key| key.hooks == HOOK_ADDRESS, + 1 + ) + .await + .unwrap(); + + assert!(!result.is_empty()); + assert_eq!(result[0].hooks, HOOK_ADDRESS); + } + + #[tokio::test] + async fn test_angstrom_l2_priority_fee_tax_floor() { + let provider = eth_base_provider().await; + + let result = angstrom_l2_priority_fee_tax_floor(&provider, HOOK_ADDRESS, BlockId::number(BLOCK_NUMBER)) + .await + .unwrap(); + + assert_eq!(result, U256::ZERO); + } + + #[tokio::test] + async fn test_angstrom_l2_jit_tax_enabled() { + let provider = eth_base_provider().await; + + let result = angstrom_l2_jit_tax_enabled(&provider, HOOK_ADDRESS, BlockId::number(BLOCK_NUMBER)) + .await + .unwrap(); + + assert!(!result); + } + + #[tokio::test] + async fn test_angstrom_l2_global_growth() { + let provider = eth_base_provider().await; + + let result = angstrom_l2_global_growth(&provider, HOOK_ADDRESS, POOL_ID, BlockId::number(BLOCK_NUMBER)) + .await + .unwrap(); + + assert_eq!(result, U256::ZERO); + } + + #[tokio::test] + async fn test_angstrom_l2_tick_growth_outside() { + let provider = eth_base_provider().await; + + let tick = I24::ZERO; + + let result = angstrom_l2_tick_growth_outside(&provider, HOOK_ADDRESS, POOL_ID, tick, BlockId::number(BLOCK_NUMBER)) + .await + .unwrap(); + + assert_eq!(result, U256::ZERO); + } + + #[tokio::test] + async fn test_angstrom_l2_growth_inside() { + let provider = eth_base_provider().await; + + let current_tick = I24::ZERO; + let tick_lower = I24::unchecked_from(-100); + let tick_upper = I24::unchecked_from(100); + + let result = angstrom_l2_growth_inside( + &provider, + HOOK_ADDRESS, + POOL_ID, + current_tick, + tick_lower, + tick_upper, + BlockId::number(BLOCK_NUMBER) + ) + .await + .unwrap(); + + assert_eq!(result, U256::ZERO); + } + + #[tokio::test] + async fn test_angstrom_l2_last_growth_inside() { + let provider = eth_base_provider().await; + + let position_manager = ANGSTROM_L2_CONSTANTS_BASE_MAINNET + .uniswap_constants() + .position_manager(); + let token_id = U256::from(1); + let tick_lower = I24::unchecked_from(-100); + let tick_upper = I24::unchecked_from(100); + + let result = angstrom_l2_last_growth_inside( + &provider, + HOOK_ADDRESS, + position_manager, + POOL_ID, + token_id, + tick_lower, + tick_upper, + BlockId::number(BLOCK_NUMBER) + ) + .await + .unwrap(); + + assert_eq!(result, U256::ZERO); + } + + #[tokio::test] + async fn test_angstrom_l2_pool_fee_config() { + let provider = eth_base_provider().await; + + let result = angstrom_l2_pool_fee_config(&provider, HOOK_ADDRESS, POOL_ID, BlockId::number(BLOCK_NUMBER)) + .await + .unwrap(); + + assert!(!result.is_initialized); + } + + #[tokio::test] + async fn test_angstrom_l2_is_pool_initialized() { + let provider = eth_base_provider().await; + + let result = angstrom_l2_is_pool_initialized(&provider, HOOK_ADDRESS, POOL_ID, BlockId::number(BLOCK_NUMBER)) + .await + .unwrap(); + + assert!(!result); + } + + #[tokio::test] + async fn test_angstrom_l2_total_swap_fee_rate_e6() { + let provider = eth_base_provider().await; + + let result = angstrom_l2_total_swap_fee_rate_e6(&provider, HOOK_ADDRESS, POOL_ID, BlockId::number(BLOCK_NUMBER)) + .await + .unwrap(); + + assert_eq!(result, 0); + } + + #[tokio::test] + async fn test_angstrom_l2_total_tax_fee_rate_e6() { + let provider = eth_base_provider().await; + + let result = angstrom_l2_total_tax_fee_rate_e6(&provider, HOOK_ADDRESS, POOL_ID, BlockId::number(BLOCK_NUMBER)) + .await + .unwrap(); + + assert_eq!(result, 0); + } +} diff --git a/crates/uniswap-storage/src/angstrom/l2/angstrom_l2_factory.rs b/crates/uniswap-storage/src/angstrom/l2/angstrom_l2_factory.rs index d57b2bd..a4ff1e4 100644 --- a/crates/uniswap-storage/src/angstrom/l2/angstrom_l2_factory.rs +++ b/crates/uniswap-storage/src/angstrom/l2/angstrom_l2_factory.rs @@ -8,69 +8,58 @@ |------------------------------------+----------------------------------------+------+--------+-------+---------------------------------------------| | defaultProtocolTaxFeeE6 | uint24 | 0 | 4 | 3 | src/AngstromL2Factory.sol:AngstromL2Factory | |------------------------------------+----------------------------------------+------+--------+-------+---------------------------------------------| -| isVerifiedHook | mapping(contract AngstromL2 => bool) | 1 | 0 | 32 | src/AngstromL2Factory.sol:AngstromL2Factory | +| defaultJITTaxEnabled | bool | 0 | 7 | 1 | src/AngstromL2Factory.sol:AngstromL2Factory | |------------------------------------+----------------------------------------+------+--------+-------+---------------------------------------------| -| allHooks | contract AngstromL2[] | 2 | 0 | 32 | src/AngstromL2Factory.sol:AngstromL2Factory | +| defaultPriorityFeeTaxFloor | uint256 | 1 | 0 | 32 | src/AngstromL2Factory.sol:AngstromL2Factory | |------------------------------------+----------------------------------------+------+--------+-------+---------------------------------------------| -| hookPoolIds | mapping(PoolId => contract AngstromL2) | 3 | 0 | 32 | src/AngstromL2Factory.sol:AngstromL2Factory | +| isVerifiedHook | mapping(contract AngstromL2 => bool) | 2 | 0 | 32 | src/AngstromL2Factory.sol:AngstromL2Factory | +|------------------------------------+----------------------------------------+------+--------+-------+---------------------------------------------| +| allHooks | contract AngstromL2[] | 3 | 0 | 32 | src/AngstromL2Factory.sol:AngstromL2Factory | +|------------------------------------+----------------------------------------+------+--------+-------+---------------------------------------------| +| hookPoolIds | mapping(PoolId => contract AngstromL2) | 4 | 0 | 32 | src/AngstromL2Factory.sol:AngstromL2Factory | ╰------------------------------------+----------------------------------------+------+--------+-------+---------------------------------------------╯ -AngstromL2 is `Address` -PoolId is `B256` */ +use alloy_eips::BlockId; use alloy_primitives::{Address, B256, U160, U256, keccak256}; use alloy_sol_types::SolValue; +use futures::{StreamExt, stream::FuturesUnordered}; -use crate::StorageSlotFetcher; +use crate::{StorageSlotFetcher, angstrom::l2::AngstromL2FactorySlot0}; // Storage slot constants -pub const ANGSTROM_L2_FACTORY_SLOT_0: u64 = 0; // withdrawOnly, defaultProtocolSwapFeeAsMultipleE6, defaultProtocolTaxFeeE6 -pub const ANGSTROM_L2_FACTORY_IS_VERIFIED_HOOK_SLOT: u64 = 1; -pub const ANGSTROM_L2_FACTORY_ALL_HOOKS_SLOT: u64 = 2; -pub const ANGSTROM_L2_FACTORY_HOOK_POOL_IDS_SLOT: u64 = 3; +pub const ANGSTROM_L2_FACTORY_SLOT_0: u64 = 0; // withdrawOnly, defaultProtocolSwapFeeAsMultipleE6, defaultProtocolTaxFeeE6, defaultJITTaxEnabled +pub const ANGSTROM_L2_FACTORY_DEFAULT_PRIORITY_FEE_TAX_FLOOR_SLOT: u64 = 1; +pub const ANGSTROM_L2_FACTORY_IS_VERIFIED_HOOK_SLOT: u64 = 2; +pub const ANGSTROM_L2_FACTORY_ALL_HOOKS_SLOT: u64 = 3; +pub const ANGSTROM_L2_FACTORY_HOOK_POOL_IDS_SLOT: u64 = 4; /// Gets the packed slot 0 data which contains withdrawOnly, -/// defaultProtocolSwapFeeAsMultipleE6, and defaultProtocolTaxFeeE6 -pub async fn angstrom_l2_factory_get_slot_0( +/// defaultProtocolSwapFeeAsMultipleE6, defaultProtocolTaxFeeE6, and +/// defaultJITTaxEnabled +pub async fn angstrom_l2_factory_get_slot0( slot_fetcher: &F, factory_address: Address, - block_number: Option -) -> eyre::Result { - slot_fetcher - .storage_at(factory_address, U256::from(ANGSTROM_L2_FACTORY_SLOT_0).into(), block_number) - .await -} - -/// Gets whether the factory is in withdraw-only mode -pub async fn angstrom_l2_factory_withdraw_only( - slot_fetcher: &F, - factory_address: Address, - block_number: Option -) -> eyre::Result { - let slot_0 = angstrom_l2_factory_get_slot_0(slot_fetcher, factory_address, block_number).await?; - Ok((slot_0 & U256::from(0xFF)) != U256::ZERO) -} + block_id: BlockId +) -> eyre::Result { + let out = slot_fetcher + .storage_at(factory_address, U256::from(ANGSTROM_L2_FACTORY_SLOT_0).into(), block_id) + .await?; -/// Gets the default protocol swap fee as multiple in E6 format -pub async fn angstrom_l2_factory_default_protocol_swap_fee_as_multiple_e6( - slot_fetcher: &F, - factory_address: Address, - block_number: Option -) -> eyre::Result { - let slot_0 = angstrom_l2_factory_get_slot_0(slot_fetcher, factory_address, block_number).await?; - Ok(U256::to::(&((slot_0 >> 8) & U256::from(0xFFFFFF)))) + Ok(AngstromL2FactorySlot0::from(out)) } -/// Gets the default protocol tax fee in E6 format -pub async fn angstrom_l2_factory_default_protocol_tax_fee_e6( +/// Gets defaultPriorityFeeTaxFloor +pub async fn angstrom_l2_factory_default_priority_fee_tax_floor( slot_fetcher: &F, factory_address: Address, - block_number: Option -) -> eyre::Result { - let slot_0 = angstrom_l2_factory_get_slot_0(slot_fetcher, factory_address, block_number).await?; - Ok(U256::to::(&((slot_0 >> 32) & U256::from(0xFFFFFF)))) + block_id: BlockId +) -> eyre::Result { + slot_fetcher + .storage_at(factory_address, U256::from(ANGSTROM_L2_FACTORY_DEFAULT_PRIORITY_FEE_TAX_FLOOR_SLOT).into(), block_id) + .await } /// Checks if a hook is verified @@ -78,13 +67,13 @@ pub async fn angstrom_l2_factory_is_verified_hook( slot_fetcher: &F, factory_address: Address, hook_address: Address, - block_number: Option + block_id: BlockId ) -> eyre::Result { // Compute the slot for isVerifiedHook[hook_address] let slot = keccak256((hook_address, U256::from(ANGSTROM_L2_FACTORY_IS_VERIFIED_HOOK_SLOT)).abi_encode()); let is_verified = slot_fetcher - .storage_at(factory_address, slot, block_number) + .storage_at(factory_address, slot, block_id) .await?; Ok(is_verified != U256::ZERO) @@ -94,10 +83,10 @@ pub async fn angstrom_l2_factory_is_verified_hook( pub async fn angstrom_l2_factory_all_hooks_length( slot_fetcher: &F, factory_address: Address, - block_number: Option + block_id: BlockId ) -> eyre::Result { let length = slot_fetcher - .storage_at(factory_address, U256::from(ANGSTROM_L2_FACTORY_ALL_HOOKS_SLOT).into(), block_number) + .storage_at(factory_address, U256::from(ANGSTROM_L2_FACTORY_ALL_HOOKS_SLOT).into(), block_id) .await?; Ok(length.to::()) @@ -108,14 +97,14 @@ pub async fn angstrom_l2_factory_all_hooks_at( slot_fetcher: &F, factory_address: Address, index: u64, - block_number: Option + block_id: BlockId ) -> eyre::Result
{ // Calculate the slot for array element at index let base_slot = keccak256(U256::from(ANGSTROM_L2_FACTORY_ALL_HOOKS_SLOT).abi_encode()); let element_slot = U256::from_be_bytes(base_slot.0) + U256::from(index); let hook_address = slot_fetcher - .storage_at(factory_address, element_slot.into(), block_number) + .storage_at(factory_address, element_slot.into(), block_id) .await?; Ok(Address::from(U160::from(hook_address))) @@ -125,36 +114,165 @@ pub async fn angstrom_l2_factory_all_hooks_at( pub async fn angstrom_l2_factory_all_hooks( slot_fetcher: &F, factory_address: Address, - block_number: Option + block_id: BlockId ) -> eyre::Result> { - let length = angstrom_l2_factory_all_hooks_length(slot_fetcher, factory_address, block_number).await?; + let length = angstrom_l2_factory_all_hooks_length(slot_fetcher, factory_address, block_id).await?; if length == 0 { return Ok(Vec::new()); } - let mut hooks = Vec::with_capacity(length as usize); - for i in 0..length { - let hook = angstrom_l2_factory_all_hooks_at(slot_fetcher, factory_address, i, block_number).await?; - hooks.push(hook); - } + let hook_futs = (0..length) + .map(|i| angstrom_l2_factory_all_hooks_at(slot_fetcher, factory_address, i, block_id)) + .collect::>(); + + let hooks = hook_futs.collect::>().await; - Ok(hooks) + hooks.into_iter().collect() } /// Gets the hook address for a specific pool ID -pub async fn angstrom_l2_factory_hook_pool_id( +pub async fn angstrom_l2_factory_hook_address_for_pool_id( slot_fetcher: &F, factory_address: Address, pool_id: B256, - block_number: Option + block_id: BlockId ) -> eyre::Result> { // Compute the slot for hookPoolIds[pool_id] let slot = keccak256((pool_id, U256::from(ANGSTROM_L2_FACTORY_HOOK_POOL_IDS_SLOT)).abi_encode()); let hook_address = slot_fetcher - .storage_at(factory_address, slot, block_number) + .storage_at(factory_address, slot, block_id) .await?; - if hook_address == U256::ZERO { Ok(None) } else { Ok(Some(Address::from(U160::from(hook_address)))) } + Ok((!hook_address.is_zero()).then_some(Address::from(U160::from(hook_address)))) +} + +#[cfg(test)] +mod test { + use alloy_eips::BlockId; + use alloy_primitives::{U256, address, aliases::U24, b256}; + + use super::*; + use crate::{angstrom::l2::ANGSTROM_L2_CONSTANTS_BASE_MAINNET, test_utils::eth_base_provider}; + + const HOOK_ADDRESS: Address = address!("0xC7F6fFDb7a058ac431b852Bc1bF00cc0Fd4c65Cf"); + const POOL_ID: B256 = b256!("0x343ee3036741f45b5512ebf7ad0d8ab259dbb8e5a38ff0d19022da176ee04574"); + const BLOCK_NUMBER: u64 = 40426000; + + #[tokio::test] + async fn test_angstrom_l2_factory_get_slot0() { + let provider = eth_base_provider().await; + + let result = angstrom_l2_factory_get_slot0( + &provider, + ANGSTROM_L2_CONSTANTS_BASE_MAINNET.angstrom_l2_factory(), + BlockId::number(BLOCK_NUMBER) + ) + .await + .unwrap(); + + let expected = AngstromL2FactorySlot0 { + withdraw_only: false, + default_protocol_swap_fee_as_multiple_e6: U24::ZERO, + default_protocol_tax_fee_e6: U24::ZERO, + default_jit_tax_enabled: false + }; + + assert_eq!(result, expected); + } + + #[tokio::test] + async fn test_angstrom_l2_factory_default_priority_fee_tax_floor() { + let provider = eth_base_provider().await; + + let result = angstrom_l2_factory_default_priority_fee_tax_floor( + &provider, + ANGSTROM_L2_CONSTANTS_BASE_MAINNET.angstrom_l2_factory(), + BlockId::number(BLOCK_NUMBER) + ) + .await + .unwrap(); + + assert_eq!(result, U256::ZERO); + } + + #[tokio::test] + async fn test_angstrom_l2_factory_is_verified_hook() { + let provider = eth_base_provider().await; + + let result = angstrom_l2_factory_is_verified_hook( + &provider, + ANGSTROM_L2_CONSTANTS_BASE_MAINNET.angstrom_l2_factory(), + HOOK_ADDRESS, + BlockId::number(BLOCK_NUMBER) + ) + .await + .unwrap(); + + assert!(result); + } + + #[tokio::test] + async fn test_angstrom_l2_factory_all_hooks_length() { + let provider = eth_base_provider().await; + + let result = angstrom_l2_factory_all_hooks_length( + &provider, + ANGSTROM_L2_CONSTANTS_BASE_MAINNET.angstrom_l2_factory(), + BlockId::number(BLOCK_NUMBER) + ) + .await + .unwrap(); + + assert_eq!(result, 1); + } + + #[tokio::test] + async fn test_angstrom_l2_factory_all_hooks_at() { + let provider = eth_base_provider().await; + + let result = angstrom_l2_factory_all_hooks_at( + &provider, + ANGSTROM_L2_CONSTANTS_BASE_MAINNET.angstrom_l2_factory(), + 0, + BlockId::number(BLOCK_NUMBER) + ) + .await + .unwrap(); + + assert_eq!(result, HOOK_ADDRESS); + } + + #[tokio::test] + async fn test_angstrom_l2_factory_all_hooks() { + let provider = eth_base_provider().await; + + let result = angstrom_l2_factory_all_hooks( + &provider, + ANGSTROM_L2_CONSTANTS_BASE_MAINNET.angstrom_l2_factory(), + BlockId::number(BLOCK_NUMBER) + ) + .await + .unwrap(); + + assert_eq!(result, vec![HOOK_ADDRESS]); + } + + #[tokio::test] + async fn test_angstrom_l2_factory_hook_address_for_pool_id() { + let provider = eth_base_provider().await; + + let result = angstrom_l2_factory_hook_address_for_pool_id( + &provider, + ANGSTROM_L2_CONSTANTS_BASE_MAINNET.angstrom_l2_factory(), + POOL_ID, + BlockId::number(BLOCK_NUMBER) + ) + .await + .unwrap() + .unwrap(); + + assert_eq!(result, HOOK_ADDRESS); + } } diff --git a/crates/uniswap-storage/src/angstrom/l2/constants.rs b/crates/uniswap-storage/src/angstrom/l2/constants.rs index 3bb4477..9d18303 100644 --- a/crates/uniswap-storage/src/angstrom/l2/constants.rs +++ b/crates/uniswap-storage/src/angstrom/l2/constants.rs @@ -54,9 +54,9 @@ impl AngstromL2Constants { } pub const ANGSTROM_L2_CONSTANTS_BASE_MAINNET: AngstromL2Constants = AngstromL2Constants { - angstrom_l2_factory: address!("0x000000000000a0220e791bAe32b16C0406980C42"), - hook_address_miner: address!("0x801988754b99f142C5C5CA19ca9656CFf31A898a"), - angstrom_deploy_block: 36617377, + angstrom_l2_factory: address!("0xF5705a709C99429449b77ad91d7bED1E667e979A"), + hook_address_miner: address!("0x16eD937987753a50f9Eb293eFffA753aC4313db0"), + angstrom_deploy_block: 40425432, chain_id: 8453, angstrom_eip712_domain: alloy_sol_types::eip712_domain!( name: "Angstrom", @@ -68,7 +68,7 @@ pub const ANGSTROM_L2_CONSTANTS_BASE_MAINNET: AngstromL2Constants = AngstromL2Co }; pub const ANGSTROM_L2_CONSTANTS_UNICHAIN_MAINNET: AngstromL2Constants = AngstromL2Constants { - angstrom_l2_factory: address!("0x000000000000a0220e791bae32b16c0406980c42"), + angstrom_l2_factory: address!("0x000000000000a0220e791bAe32b16C0406980C42"), hook_address_miner: address!("0x98bD6680eE62C006730A5a4dFB2f0Da6645A10f5"), angstrom_deploy_block: 29275745, chain_id: 130, diff --git a/crates/uniswap-storage/src/angstrom/l2/mod.rs b/crates/uniswap-storage/src/angstrom/l2/mod.rs index b597e4f..c05d1b9 100644 --- a/crates/uniswap-storage/src/angstrom/l2/mod.rs +++ b/crates/uniswap-storage/src/angstrom/l2/mod.rs @@ -2,3 +2,5 @@ pub mod angstrom_l2; pub mod angstrom_l2_factory; mod constants; pub use constants::*; +mod types; +pub use types::*; diff --git a/crates/uniswap-storage/src/angstrom/l2/types.rs b/crates/uniswap-storage/src/angstrom/l2/types.rs new file mode 100644 index 0000000..e958895 --- /dev/null +++ b/crates/uniswap-storage/src/angstrom/l2/types.rs @@ -0,0 +1,53 @@ +use alloy_primitives::{U256, aliases::U24}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] +pub struct AngstromL2FactorySlot0 { + pub withdraw_only: bool, + pub default_protocol_swap_fee_as_multiple_e6: U24, + pub default_protocol_tax_fee_e6: U24, + pub default_jit_tax_enabled: bool +} + +impl From for AngstromL2FactorySlot0 { + fn from(value: U256) -> Self { + Self { + withdraw_only: (value & U256::from(0xFF)) != U256::ZERO, + default_protocol_swap_fee_as_multiple_e6: U24::from(U256::to::(&((value >> 8) & U256::from(0xFFFFFF)))), + default_protocol_tax_fee_e6: U24::from(U256::to::(&((value >> 32) & U256::from(0xFFFFFF)))), + default_jit_tax_enabled: ((value >> 56) & U256::from(0xFF)) != U256::ZERO + } + } +} + +impl From<&U256> for AngstromL2FactorySlot0 { + fn from(value: &U256) -> Self { + AngstromL2FactorySlot0::from(*value) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AngstromL2PoolFeeConfiguration { + pub is_initialized: bool, + pub creator_tax_fee_e6: u32, + pub protocol_tax_fee_e6: u32, + pub creator_swap_fee_e6: u32, + pub protocol_swap_fee_e6: u32 +} + +impl From for AngstromL2PoolFeeConfiguration { + fn from(value: U256) -> Self { + let is_initialized = (value & U256::from(1)) != U256::ZERO; + let creator_tax_fee_e6 = U256::to::(&((value >> 8) & U256::from(0xFFFFFF))); + let protocol_tax_fee_e6 = U256::to::(&((value >> 32) & U256::from(0xFFFFFF))); + let creator_swap_fee_e6 = U256::to::(&((value >> 56) & U256::from(0xFFFFFF))); + let protocol_swap_fee_e6 = U256::to::(&((value >> 80) & U256::from(0xFFFFFF))); + Self { is_initialized, creator_tax_fee_e6, protocol_tax_fee_e6, creator_swap_fee_e6, protocol_swap_fee_e6 } + } +} + +impl From<&U256> for AngstromL2PoolFeeConfiguration { + fn from(value: &U256) -> Self { + AngstromL2PoolFeeConfiguration::from(*value) + } +} diff --git a/crates/uniswap-storage/src/angstrom/mainnet/angstrom.rs b/crates/uniswap-storage/src/angstrom/mainnet/angstrom.rs index c99c842..6f29e83 100644 --- a/crates/uniswap-storage/src/angstrom/mainnet/angstrom.rs +++ b/crates/uniswap-storage/src/angstrom/mainnet/angstrom.rs @@ -1,3 +1,4 @@ +use alloy_eips::BlockId; use alloy_primitives::{Address, B256, U256, aliases::I24, keccak256}; use alloy_sol_types::SolValue; @@ -25,12 +26,12 @@ pub async fn angstrom_growth_inside( current_pool_tick: I24, tick_lower: I24, tick_upper: I24, - block_number: Option + block_id: BlockId ) -> eyre::Result { let (lower_growth, upper_growth, global_growth) = futures::try_join!( - angstrom_tick_growth_outside(slot_fetcher, angstrom_address, pool_id, tick_lower, block_number,), - angstrom_tick_growth_outside(slot_fetcher, angstrom_address, pool_id, tick_upper, block_number,), - angstrom_global_growth(slot_fetcher, angstrom_address, pool_id, block_number,), + angstrom_tick_growth_outside(slot_fetcher, angstrom_address, pool_id, tick_lower, block_id,), + angstrom_tick_growth_outside(slot_fetcher, angstrom_address, pool_id, tick_upper, block_id,), + angstrom_global_growth(slot_fetcher, angstrom_address, pool_id, block_id,), )?; let rewards = if current_pool_tick < tick_lower { @@ -48,14 +49,14 @@ pub async fn angstrom_global_growth( slot_fetcher: &F, angstrom_address: Address, pool_id: B256, - block_number: Option + block_id: BlockId ) -> eyre::Result { let pool_rewards_slot_base = U256::from_be_bytes(angstrom_pool_rewards_slot(pool_id).0); let global_growth = slot_fetcher .storage_at( angstrom_address, (pool_rewards_slot_base + U256::from(ANGSTROM_POOL_REWARDS_GROWTH_ARRAY_SIZE)).into(), - block_number + block_id ) .await?; @@ -67,14 +68,14 @@ pub async fn angstrom_tick_growth_outside( angstrom_address: Address, pool_id: B256, tick: I24, - block_number: Option + block_id: BlockId ) -> eyre::Result { let pool_rewards_slot_base = U256::from_be_bytes(angstrom_pool_rewards_slot(pool_id).0); let growth_outside = slot_fetcher .storage_at( angstrom_address, (pool_rewards_slot_base + U256::from_be_slice(&tick.to_be_bytes::<3>())).into(), - block_number + block_id ) .await?; @@ -89,13 +90,13 @@ pub async fn angstrom_last_growth_inside( position_token_id: U256, tick_lower: I24, tick_upper: I24, - block_number: Option + block_id: BlockId ) -> eyre::Result { let position_key = encode_position_key(position_manager_address, position_token_id, tick_lower, tick_upper); let position_slot_base = U256::from_be_bytes(angstrom_position_slot(pool_id, position_key).0); let growth = slot_fetcher - .storage_at(angstrom_address, position_slot_base.into(), block_number) + .storage_at(angstrom_address, position_slot_base.into(), block_id) .await?; Ok(growth) @@ -104,6 +105,7 @@ pub async fn angstrom_last_growth_inside( #[cfg(test)] mod tests { + use alloy_eips::BlockId; use alloy_primitives::aliases::U24; use super::*; @@ -133,7 +135,7 @@ mod tests { I24::unchecked_from(190088), I24::unchecked_from(-887270), I24::unchecked_from(887270), - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); @@ -162,7 +164,7 @@ mod tests { U256::from(96348_u64), I24::unchecked_from(193290), I24::unchecked_from(196300), - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); @@ -187,7 +189,7 @@ mod tests { &provider, ANGSTROM_L1_CONSTANTS_MAINNET.angstrom_address(), pool_key.into(), - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); @@ -213,7 +215,7 @@ mod tests { ANGSTROM_L1_CONSTANTS_MAINNET.angstrom_address(), pool_key.into(), I24::unchecked_from(193290), - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); diff --git a/crates/uniswap-storage/src/angstrom/mod.rs b/crates/uniswap-storage/src/angstrom/mod.rs index d034cf6..e08cadc 100644 --- a/crates/uniswap-storage/src/angstrom/mod.rs +++ b/crates/uniswap-storage/src/angstrom/mod.rs @@ -1,2 +1,4 @@ +#[cfg(feature = "l2-angstrom")] pub mod l2; +#[cfg(feature = "l1-angstrom")] pub mod mainnet; diff --git a/crates/uniswap-storage/src/lib.rs b/crates/uniswap-storage/src/lib.rs index f17c512..c1ddbcd 100644 --- a/crates/uniswap-storage/src/lib.rs +++ b/crates/uniswap-storage/src/lib.rs @@ -1,6 +1,6 @@ #![allow(clippy::too_many_arguments)] -#[cfg(feature = "angstrom")] +#[cfg(any(feature = "l1-angstrom", feature = "l2-angstrom"))] pub mod angstrom; #[cfg(feature = "v3")] pub mod v3; diff --git a/crates/uniswap-storage/src/storage_fetcher.rs b/crates/uniswap-storage/src/storage_fetcher.rs index 38a0039..35d2df3 100644 --- a/crates/uniswap-storage/src/storage_fetcher.rs +++ b/crates/uniswap-storage/src/storage_fetcher.rs @@ -6,21 +6,21 @@ use auto_impl::auto_impl; #[auto_impl(&, Box, Arc)] pub trait StorageSlotFetcherSync { - fn storage_at(&self, address: Address, key: StorageKey, block_number: Option) -> eyre::Result; + fn storage_at(&self, address: Address, key: StorageKey, block_id: BlockId) -> eyre::Result; } #[async_trait::async_trait] #[auto_impl(&, Box, Arc)] pub trait StorageSlotFetcher: Sync { - async fn storage_at(&self, address: Address, key: StorageKey, block_number: Option) -> eyre::Result; + async fn storage_at(&self, address: Address, key: StorageKey, block_id: BlockId) -> eyre::Result; } #[async_trait::async_trait] impl StorageSlotFetcher for RootProvider { - async fn storage_at(&self, address: Address, key: StorageKey, block_number: Option) -> eyre::Result { + async fn storage_at(&self, address: Address, key: StorageKey, block_id: BlockId) -> eyre::Result { Ok(self .get_storage_at(address, key.into()) - .block_id(block_number.map(Into::into).unwrap_or(BlockId::latest())) + .block_id(block_id) .await?) } } @@ -33,14 +33,16 @@ mod revm_impls { #[async_trait::async_trait] impl, N: Network> StorageSlotFetcher for AlloyDB { - async fn storage_at(&self, address: Address, key: StorageKey, _: Option) -> eyre::Result { + async fn storage_at(&self, address: Address, key: StorageKey, block_id: BlockId) -> eyre::Result { + let _ = block_id; Ok(self.storage_async_ref(address, key.into()).await?) } } #[async_trait::async_trait] impl StorageSlotFetcher for WrapDatabaseAsync { - async fn storage_at(&self, address: Address, key: StorageKey, _: Option) -> eyre::Result { + async fn storage_at(&self, address: Address, key: StorageKey, block_id: BlockId) -> eyre::Result { + let _ = block_id; self.storage_ref(address, key.into()) .map_err(|e| eyre::eyre!("{e:?}")) } @@ -48,21 +50,24 @@ mod revm_impls { #[async_trait::async_trait] impl StorageSlotFetcher for CacheDB { - async fn storage_at(&self, address: Address, key: StorageKey, _: Option) -> eyre::Result { + async fn storage_at(&self, address: Address, key: StorageKey, block_id: BlockId) -> eyre::Result { + let _ = block_id; self.storage_ref(address, key.into()) .map_err(|e| eyre::eyre!("{e:?}")) } } impl StorageSlotFetcherSync for WrapDatabaseAsync { - fn storage_at(&self, address: Address, key: StorageKey, _: Option) -> eyre::Result { + fn storage_at(&self, address: Address, key: StorageKey, block_id: BlockId) -> eyre::Result { + let _ = block_id; self.storage_ref(address, key.into()) .map_err(|e| eyre::eyre!("{e:?}")) } } impl StorageSlotFetcherSync for CacheDB { - fn storage_at(&self, address: Address, key: StorageKey, _: Option) -> eyre::Result { + fn storage_at(&self, address: Address, key: StorageKey, block_id: BlockId) -> eyre::Result { + let _ = block_id; self.storage_ref(address, key.into()) .map_err(|e| eyre::eyre!("{e:?}")) } @@ -84,13 +89,7 @@ mod reth_db_impls { N: RpcNodeCore, Rpc: RpcConvert { - async fn storage_at( - &self, - address: Address, - key: StorageKey, - block_number: Option - ) -> eyre::Result { - let block_id = block_number.map(Into::into).unwrap_or_else(BlockId::latest); + async fn storage_at(&self, address: Address, key: StorageKey, block_id: BlockId) -> eyre::Result { let state_provider = self.provider().state_by_block_id(block_id)?; Ok(state_provider.storage(address, key)?.unwrap_or_default()) @@ -102,11 +101,23 @@ mod reth_db_impls { N: RpcNodeCore, Rpc: RpcConvert { - fn storage_at(&self, address: Address, key: StorageKey, block_number: Option) -> eyre::Result { - let block_id = block_number.map(Into::into).unwrap_or_else(BlockId::latest); + fn storage_at(&self, address: Address, key: StorageKey, block_id: BlockId) -> eyre::Result { let state_provider = self.provider().state_by_block_id(block_id)?; Ok(state_provider.storage(address, key)?.unwrap_or_default()) } } + + #[async_trait::async_trait] + impl StorageSlotFetcher for reth_optimism_rpc::OpEthApi + where + N: RpcNodeCore, + Rpc: RpcConvert + { + async fn storage_at(&self, address: Address, key: StorageKey, block_id: BlockId) -> eyre::Result { + let state_provider = self.eth_api().provider().state_by_block_id(block_id)?; + + Ok(state_provider.storage(address, key)?.unwrap_or_default()) + } + } } diff --git a/crates/uniswap-storage/src/test_utils.rs b/crates/uniswap-storage/src/test_utils.rs index 0530434..4d80f6f 100644 --- a/crates/uniswap-storage/src/test_utils.rs +++ b/crates/uniswap-storage/src/test_utils.rs @@ -1,11 +1,18 @@ +use alloy_network::Network; use alloy_primitives::{Address, address}; use alloy_provider::{Provider, ProviderBuilder, RootProvider, WsConnect}; +use op_alloy_network::Optimism; pub async fn eth_provider() -> RootProvider { - dotenv::dotenv().ok(); + __eth_provider("ETH_WS_URL").await +} - let url = std::env::var("ETH_WS_URL").expect("no ETH_WS_URL in .env"); - ProviderBuilder::new() +async fn __eth_provider(env: &str) -> RootProvider { + dotenv::dotenv().ok(); + let url = std::env::var(env) + .map_err(|e| format!("no {env} in .env:\n{e:?}")) + .unwrap(); + ProviderBuilder::<_, _, N>::default() .connect_ws(WsConnect::new(url)) .await .unwrap() @@ -13,5 +20,9 @@ pub async fn eth_provider() -> RootProvider { .clone() } +pub async fn eth_base_provider() -> RootProvider { + __eth_provider("BASE_WS_URL").await +} + pub const USDC: Address = address!("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"); pub const WETH: Address = address!("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"); diff --git a/crates/uniswap-storage/src/v3/pool.rs b/crates/uniswap-storage/src/v3/pool.rs index 97315e8..172e0d9 100644 --- a/crates/uniswap-storage/src/v3/pool.rs +++ b/crates/uniswap-storage/src/v3/pool.rs @@ -1,15 +1,12 @@ +use alloy_eips::BlockId; use alloy_primitives::{Address, StorageValue, U160, U256, aliases::I24}; use crate::{StorageSlotFetcher, types::TickData, v3::utils::*}; -pub async fn v3_current_tick( - provider: &P, - pool: Address, - block_number: Option -) -> eyre::Result { +pub async fn v3_current_tick(provider: &P, pool: Address, block_id: BlockId) -> eyre::Result { let slot0_key = U256::from(SLOT0_SLOT); let slot0_value = provider - .storage_at(pool, slot0_key.into(), block_number) + .storage_at(pool, slot0_key.into(), block_id) .await?; let tick_raw: U256 = (slot0_value >> 160) & U256::from((1u64 << 24) - 1); @@ -27,11 +24,11 @@ pub async fn v3_current_tick( pub async fn v3_current_liquidity( provider: &P, pool: Address, - block_number: Option + block_id: BlockId ) -> eyre::Result { let liquidity_key = U256::from(LIQUIDITY_SLOT); let liquidity = provider - .storage_at(pool, liquidity_key.into(), block_number) + .storage_at(pool, liquidity_key.into(), block_id) .await?; Ok(liquidity & U256::from(u128::MAX)) @@ -40,27 +37,23 @@ pub async fn v3_current_liquidity( pub async fn v3_fee_growth_global( provider: &P, pool: Address, - block_number: Option + block_id: BlockId ) -> eyre::Result<(U256, U256)> { let fee_growth_global0_key = U256::from(FEE_GROWTH_GLOBAL_0X128_SLOT); let fee_growth_global1_key = U256::from(FEE_GROWTH_GLOBAL_1X128_SLOT); let (fee_growth_global0, fee_growth_global1) = futures::try_join!( - provider.storage_at(pool, fee_growth_global0_key.into(), block_number), - provider.storage_at(pool, fee_growth_global1_key.into(), block_number), + provider.storage_at(pool, fee_growth_global0_key.into(), block_id), + provider.storage_at(pool, fee_growth_global1_key.into(), block_id), )?; Ok((fee_growth_global0, fee_growth_global1)) } -pub async fn v3_sqrt_price_x96( - provider: &P, - pool: Address, - block_number: Option -) -> eyre::Result { +pub async fn v3_sqrt_price_x96(provider: &P, pool: Address, block_id: BlockId) -> eyre::Result { let slot0_key = U256::from(SLOT0_SLOT); let slot0_value = provider - .storage_at(pool, slot0_key.into(), block_number) + .storage_at(pool, slot0_key.into(), block_id) .await?; Ok(U160::from(slot0_value & U256::from(U160::MAX))) @@ -70,7 +63,7 @@ pub async fn v3_tick_data( provider: &P, pool: Address, tick: I24, - block_number: Option + block_id: BlockId ) -> eyre::Result { let tick_slot = v3_tick_slot(tick); let tick_slot_base = U256::from_be_slice(tick_slot.as_slice()); @@ -88,10 +81,10 @@ pub async fn v3_tick_data( StorageValue, StorageValue ) = futures::try_join!( - provider.storage_at(pool, slot0.into(), block_number), - provider.storage_at(pool, slot1.into(), block_number), - provider.storage_at(pool, slot2.into(), block_number), - provider.storage_at(pool, slot3.into(), block_number) + provider.storage_at(pool, slot0.into(), block_id), + provider.storage_at(pool, slot1.into(), block_id), + provider.storage_at(pool, slot2.into(), block_id), + provider.storage_at(pool, slot3.into(), block_id) )?; let liquidity_gross_u128 = (slot0_data & U256::from(u128::MAX)).to::(); @@ -113,10 +106,10 @@ async fn v3_tick_bitmap_from_word( provider: &P, pool: Address, word_pos: i16, - block_number: Option + block_id: BlockId ) -> eyre::Result { let bitmap_slot = v3_tick_bitmap_slot(word_pos); - let bitmap_value = provider.storage_at(pool, bitmap_slot, block_number).await?; + let bitmap_value = provider.storage_at(pool, bitmap_slot, block_id).await?; Ok(bitmap_value) } @@ -126,10 +119,10 @@ pub async fn v3_next_initialized_tick_within_one_word( tick: I24, tick_spacing: I24, lte: bool, - block_number: Option + block_id: BlockId ) -> eyre::Result<(I24, bool)> { let (compressed, (word_pos, bit_pos)) = position_compressed_tick(tick, tick_spacing, lte); - let bitmap = v3_tick_bitmap_from_word::

(provider, pool, word_pos, block_number).await?; + let bitmap = v3_tick_bitmap_from_word::

(provider, pool, word_pos, block_id).await?; if lte { let mask = (U256::ONE << bit_pos) - U256::ONE + (U256::ONE << bit_pos); let masked = bitmap & mask; @@ -158,6 +151,7 @@ pub async fn v3_next_initialized_tick_within_one_word( #[cfg(test)] mod tests { + use alloy_eips::BlockId; use alloy_primitives::address; use alloy_provider::RootProvider; @@ -172,7 +166,7 @@ mod tests { let provider = eth_provider().await; - let result = v3_current_tick::(&provider, POOL_ADDRESS, Some(block_number)) + let result = v3_current_tick::(&provider, POOL_ADDRESS, BlockId::number(block_number)) .await .unwrap(); let expected = I24::unchecked_from(193335); @@ -186,7 +180,7 @@ mod tests { let provider = eth_provider().await; - let result = v3_current_liquidity::(&provider, POOL_ADDRESS, Some(block_number)) + let result = v3_current_liquidity::(&provider, POOL_ADDRESS, BlockId::number(block_number)) .await .unwrap(); let expected = U256::from(2088207984683946894_u128); @@ -200,7 +194,7 @@ mod tests { let provider = eth_provider().await; - let result = v3_fee_growth_global::(&provider, POOL_ADDRESS, Some(block_number)) + let result = v3_fee_growth_global::(&provider, POOL_ADDRESS, BlockId::number(block_number)) .await .unwrap(); let expected = ( @@ -217,7 +211,7 @@ mod tests { let provider = eth_provider().await; - let result = v3_sqrt_price_x96::(&provider, POOL_ADDRESS, Some(block_number)) + let result = v3_sqrt_price_x96::(&provider, POOL_ADDRESS, BlockId::number(block_number)) .await .unwrap(); let expected = U160::from(1249291445425461764422472060708837_u128); @@ -232,7 +226,7 @@ mod tests { let provider = eth_provider().await; let tick = I24::unchecked_from(193320); - let result = v3_tick_data::(&provider, POOL_ADDRESS, tick, Some(block_number)) + let result = v3_tick_data::(&provider, POOL_ADDRESS, tick, BlockId::number(block_number)) .await .unwrap(); let expected = TickData { @@ -260,7 +254,7 @@ mod tests { tick, I24::unchecked_from(10), false, - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); @@ -282,7 +276,7 @@ mod tests { tick, I24::unchecked_from(10), true, - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); diff --git a/crates/uniswap-storage/src/v4/pool_manager/pool_state.rs b/crates/uniswap-storage/src/v4/pool_manager/pool_state.rs index 1a3260f..94f178a 100644 --- a/crates/uniswap-storage/src/v4/pool_manager/pool_state.rs +++ b/crates/uniswap-storage/src/v4/pool_manager/pool_state.rs @@ -1,3 +1,4 @@ +use alloy_eips::BlockId; use alloy_primitives::{Address, B256, U256, keccak256}; use alloy_sol_types::SolValue; @@ -20,7 +21,7 @@ pub async fn pool_manager_pool_fee_growth_global( slot_fetcher: &F, pool_manager_address: Address, pool_id: B256, - block_number: Option + block_id: BlockId ) -> eyre::Result<(U256, U256)> { let pool_state_slot = pool_manager_pool_state_slot(pool_id.into()); let pool_state_slot_base = U256::from_be_slice(pool_state_slot.as_slice()); @@ -31,8 +32,8 @@ pub async fn pool_manager_pool_fee_growth_global( pool_state_slot_base + U256::from(POOL_MANAGER_POOL_FEE_GROWTH_GLOBAL1_X128_SLOT_OFFSET); let (fee_growth_global0_x128, fee_growth_global1_x128) = futures::try_join!( - slot_fetcher.storage_at(pool_manager_address, fee_growth_global0_x128_slot.into(), block_number), - slot_fetcher.storage_at(pool_manager_address, fee_growth_global1_x128_slot.into(), block_number) + slot_fetcher.storage_at(pool_manager_address, fee_growth_global0_x128_slot.into(), block_id), + slot_fetcher.storage_at(pool_manager_address, fee_growth_global1_x128_slot.into(), block_id) )?; Ok((fee_growth_global0_x128, fee_growth_global1_x128)) @@ -42,12 +43,12 @@ pub async fn pool_manager_pool_slot0( slot_fetcher: &F, pool_manager_address: Address, pool_id: B256, - block_number: Option + block_id: BlockId ) -> eyre::Result { let pool_state_slot = pool_manager_pool_state_slot(pool_id.into()); let packed_slot0 = slot_fetcher - .storage_at(pool_manager_address, pool_state_slot, block_number) + .storage_at(pool_manager_address, pool_state_slot, block_id) .await?; Ok(packed_slot0.unpack_slot0()) @@ -57,7 +58,7 @@ pub async fn pool_manager_pool_liquidity( slot_fetcher: &F, pool_manager_address: Address, pool_id: B256, - block_number: Option + block_id: BlockId ) -> eyre::Result { let pool_state_slot = pool_manager_pool_state_slot(pool_id.into()); let pool_state_slot_base = U256::from_be_slice(pool_state_slot.as_slice()); @@ -65,7 +66,7 @@ pub async fn pool_manager_pool_liquidity( let liquidity_slot = pool_state_slot_base + U256::from(POOL_MANAGER_POOL_LIQUIDITY_SLOT_OFFSET); let liquidity = slot_fetcher - .storage_at(pool_manager_address, liquidity_slot.into(), block_number) + .storage_at(pool_manager_address, liquidity_slot.into(), block_id) .await?; Ok(liquidity) @@ -73,7 +74,7 @@ pub async fn pool_manager_pool_liquidity( #[cfg(test)] mod tests { - + use alloy_eips::BlockId; use alloy_primitives::{ U160, aliases::{I24, U24} @@ -103,7 +104,7 @@ mod tests { &provider, UNISWAP_V4_CONSTANTS_MAINNET.pool_manager(), pool_key.into(), - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); @@ -134,7 +135,7 @@ mod tests { &provider, UNISWAP_V4_CONSTANTS_MAINNET.pool_manager(), pool_key.into(), - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); @@ -166,7 +167,7 @@ mod tests { &provider, UNISWAP_V4_CONSTANTS_MAINNET.pool_manager(), pool_key.into(), - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); diff --git a/crates/uniswap-storage/src/v4/pool_manager/pool_tick_state.rs b/crates/uniswap-storage/src/v4/pool_manager/pool_tick_state.rs index 388649c..bf8226d 100644 --- a/crates/uniswap-storage/src/v4/pool_manager/pool_tick_state.rs +++ b/crates/uniswap-storage/src/v4/pool_manager/pool_tick_state.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; +use alloy_eips::BlockId; use alloy_primitives::{Address, B256, U256, aliases::I24, keccak256}; use alloy_sol_types::SolValue; use futures::StreamExt; @@ -39,7 +40,7 @@ pub async fn pool_manager_pool_tick_fee_growth_outside( pool_manager_address: Address, pool_id: B256, tick: I24, - block_number: Option + block_id: BlockId ) -> eyre::Result<(U256, U256)> { let pool_tick_slot = pool_manager_pool_tick_slot(pool_id.into(), tick); let pool_tick_slot_base = U256::from_be_slice(pool_tick_slot.as_slice()); @@ -50,8 +51,8 @@ pub async fn pool_manager_pool_tick_fee_growth_outside( pool_tick_slot_base + U256::from(POOL_MANAGER_POOL_TICK_FEE_GROWTH_OUTSIDE1_X128_SLOT_OFFSET); let (fee_growth_outside0_x128, fee_growth_outside1_x128) = futures::try_join!( - slot_fetcher.storage_at(pool_manager_address, fee_growth_outside0_x128_slot.into(), block_number), - slot_fetcher.storage_at(pool_manager_address, fee_growth_outside1_x128_slot.into(), block_number) + slot_fetcher.storage_at(pool_manager_address, fee_growth_outside0_x128_slot.into(), block_id), + slot_fetcher.storage_at(pool_manager_address, fee_growth_outside1_x128_slot.into(), block_id) )?; Ok((fee_growth_outside0_x128, fee_growth_outside1_x128)) @@ -64,7 +65,7 @@ pub async fn pool_manager_load_tick_map( tick_spacing: I24, start_tick: Option, end_tick: Option, - block_number: Option + block_id: BlockId ) -> eyre::Result> { let start_tick = start_tick .map(|t| normalize_tick(t, tick_spacing)) @@ -76,8 +77,7 @@ pub async fn pool_manager_load_tick_map( let mut ct = start_tick; let mut initialized_ticks = Vec::new(); while ct <= end_tick { - let (_, tick) = - next_tick_gt(slot_fetcher, pool_manager_address, tick_spacing, pool_id, ct, true, block_number).await?; + let (_, tick) = next_tick_gt(slot_fetcher, pool_manager_address, tick_spacing, pool_id, ct, true, block_id).await?; initialized_ticks.push(tick); ct = tick; } @@ -86,7 +86,7 @@ pub async fn pool_manager_load_tick_map( .map(async |tick| { let tick = I24::unchecked_from(tick); - pool_manager_load_tick_data(slot_fetcher, pool_manager_address, tick_spacing, pool_id, tick, block_number) + pool_manager_load_tick_data(slot_fetcher, pool_manager_address, tick_spacing, pool_id, tick, block_id) .await .map(|d| (tick, d)) }) @@ -107,7 +107,7 @@ pub async fn pool_manager_load_tick_data( tick_spacing: I24, pool_id: B256, tick: I24, - block_number: Option + block_id: BlockId ) -> eyre::Result { let pool_tick_slot = pool_manager_pool_tick_slot(pool_id.into(), tick); let pool_tick_slot_base = U256::from_be_slice(pool_tick_slot.as_slice()); @@ -119,10 +119,10 @@ pub async fn pool_manager_load_tick_data( pool_tick_slot_base + U256::from(POOL_MANAGER_POOL_TICK_FEE_GROWTH_OUTSIDE1_X128_SLOT_OFFSET); let (liquidity, fee_growth_outside0_x128, fee_growth_outside1_x128, is_initialized) = futures::try_join!( - slot_fetcher.storage_at(pool_manager_address, liquidity_slot.into(), block_number), - slot_fetcher.storage_at(pool_manager_address, fee_growth_outside0_x128_slot.into(), block_number), - slot_fetcher.storage_at(pool_manager_address, fee_growth_outside1_x128_slot.into(), block_number), - tick_initialized(slot_fetcher, pool_manager_address, tick_spacing, pool_id, tick, block_number,) + slot_fetcher.storage_at(pool_manager_address, liquidity_slot.into(), block_id), + slot_fetcher.storage_at(pool_manager_address, fee_growth_outside0_x128_slot.into(), block_id), + slot_fetcher.storage_at(pool_manager_address, fee_growth_outside1_x128_slot.into(), block_id), + tick_initialized(slot_fetcher, pool_manager_address, tick_spacing, pool_id, tick, block_id,) )?; let liquidity_bytes: [u8; 32] = liquidity.to_be_bytes(); @@ -139,6 +139,7 @@ pub async fn pool_manager_load_tick_data( #[cfg(test)] mod tests { + use alloy_eips::BlockId; use alloy_primitives::aliases::U24; use super::*; @@ -166,7 +167,7 @@ mod tests { UNISWAP_V4_CONSTANTS_MAINNET.pool_manager(), pool_key.into(), I24::unchecked_from(191000), - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); @@ -200,7 +201,7 @@ mod tests { tick_spacing, Some(I24::unchecked_from(194000)), Some(I24::unchecked_from(195000)), - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); @@ -228,7 +229,7 @@ mod tests { I24::unchecked_from(10), pool_key.into(), tick, - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); diff --git a/crates/uniswap-storage/src/v4/pool_manager/position_state.rs b/crates/uniswap-storage/src/v4/pool_manager/position_state.rs index d495f6d..0f87235 100644 --- a/crates/uniswap-storage/src/v4/pool_manager/position_state.rs +++ b/crates/uniswap-storage/src/v4/pool_manager/position_state.rs @@ -1,3 +1,4 @@ +use alloy_eips::BlockId; use alloy_primitives::{Address, B256, U256, aliases::I24, keccak256}; use alloy_sol_types::SolValue; @@ -30,16 +31,16 @@ pub async fn pool_manager_position_fee_growth_inside( current_tick: I24, tick_lower: I24, tick_upper: I24, - block_number: Option + block_id: BlockId ) -> eyre::Result<(U256, U256)> { let ( (fee_growth_global0_x128, fee_growth_global1_x128), (tick_lower_fee_growth_outside0_x128, tick_lower_fee_growth_outside1_x128), (tick_upper_fee_growth_outside0_x128, tick_upper_fee_growth_outside1_x128) ) = futures::try_join!( - pool_manager_pool_fee_growth_global(slot_fetcher, pool_manager_address, pool_id, block_number,), - pool_manager_pool_tick_fee_growth_outside(slot_fetcher, pool_manager_address, pool_id, tick_lower, block_number,), - pool_manager_pool_tick_fee_growth_outside(slot_fetcher, pool_manager_address, pool_id, tick_upper, block_number,) + pool_manager_pool_fee_growth_global(slot_fetcher, pool_manager_address, pool_id, block_id,), + pool_manager_pool_tick_fee_growth_outside(slot_fetcher, pool_manager_address, pool_id, tick_lower, block_id,), + pool_manager_pool_tick_fee_growth_outside(slot_fetcher, pool_manager_address, pool_id, tick_upper, block_id,) )?; let (fee_growth_inside0_x128, fee_growth_inside1_x128) = if current_tick < tick_lower { @@ -70,7 +71,7 @@ pub async fn pool_manager_position_state_last_fee_growth_inside + block_id: BlockId ) -> eyre::Result<(U256, U256)> { let position_key = U256::from_be_slice( encode_position_key(position_manager_address, position_token_id, tick_lower, tick_upper).as_slice() @@ -84,8 +85,8 @@ pub async fn pool_manager_position_state_last_fee_growth_inside( position_token_id: U256, tick_lower: I24, tick_upper: I24, - block_number: Option + block_id: BlockId ) -> eyre::Result { let position_key = U256::from_be_slice( encode_position_key(position_manager_address, position_token_id, tick_lower, tick_upper).as_slice() @@ -107,7 +108,7 @@ pub async fn pool_manager_position_state_liquidity( let position_state_slot = pool_manager_position_state_slot(pool_id.into(), position_key); let liquidity = slot_fetcher - .storage_at(pool_manager_address, position_state_slot, block_number) + .storage_at(pool_manager_address, position_state_slot, block_id) .await?; Ok(liquidity.to()) @@ -116,6 +117,7 @@ pub async fn pool_manager_position_state_liquidity( #[cfg(test)] mod tests { + use alloy_eips::BlockId; use alloy_primitives::aliases::U24; use super::*; @@ -145,7 +147,7 @@ mod tests { I24::unchecked_from(190088), I24::unchecked_from(-887270), I24::unchecked_from(887270), - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); @@ -180,7 +182,7 @@ mod tests { U256::from(14328_u64), I24::unchecked_from(-887270), I24::unchecked_from(887270), - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); @@ -209,7 +211,7 @@ mod tests { U256::from(14328_u64), I24::unchecked_from(-887270), I24::unchecked_from(887270), - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); diff --git a/crates/uniswap-storage/src/v4/pool_manager/tick_bitmap.rs b/crates/uniswap-storage/src/v4/pool_manager/tick_bitmap.rs index 4921a22..1b0558d 100644 --- a/crates/uniswap-storage/src/v4/pool_manager/tick_bitmap.rs +++ b/crates/uniswap-storage/src/v4/pool_manager/tick_bitmap.rs @@ -1,3 +1,4 @@ +use alloy_eips::BlockId; use alloy_primitives::{Address, B256, I64, U256, aliases::I24}; use serde::{Deserialize, Serialize}; @@ -101,13 +102,13 @@ pub async fn next_initialized_tick_within_one_word( tick: I24, tick_spacing: I24, lte: bool, - block_number: Option + block_id: BlockId ) -> eyre::Result<(I24, bool)> { let mut compressed = compress_tick(tick, tick_spacing); if lte { let (word_pos, bit_pos) = _tick_position_from_compressed(compressed); let mask = U256::MAX >> (U256::from(u8::MAX) - U256::from(bit_pos)); - let masked = tick_bitmap_from_word(slot_fetcher, pool_manager_address, pool_id, word_pos, block_number) + let masked = tick_bitmap_from_word(slot_fetcher, pool_manager_address, pool_id, word_pos, block_id) .await? .0 & mask; @@ -123,7 +124,7 @@ pub async fn next_initialized_tick_within_one_word( compressed += I24::ONE; let (word_pos, bit_pos) = _tick_position_from_compressed(compressed); let mask = !((U256::ONE << bit_pos) - U256::ONE); - let masked = tick_bitmap_from_word(slot_fetcher, pool_manager_address, pool_id, word_pos, block_number) + let masked = tick_bitmap_from_word(slot_fetcher, pool_manager_address, pool_id, word_pos, block_id) .await? .0 & mask; @@ -167,12 +168,12 @@ pub async fn tick_bitmap_from_word( pool_manager_address: Address, pool_id: B256, word_pos: i16, - block_number: Option + block_id: BlockId ) -> eyre::Result { let pool_tick_bitmap_slot = pool_manager_pool_tick_bitmap_slot(pool_id.into(), word_pos); let tick_bitmap = slot_fetcher - .storage_at(pool_manager_address, pool_tick_bitmap_slot, block_number) + .storage_at(pool_manager_address, pool_tick_bitmap_slot, block_id) .await?; Ok(TickBitmap(tick_bitmap)) @@ -184,11 +185,11 @@ pub async fn tick_bitmap_from_tick( pool_id: B256, tick: I24, tick_spacing: I24, - block_number: Option + block_id: BlockId ) -> eyre::Result { let (word_pos, _) = tick_position_from_compressed(tick, tick_spacing); - tick_bitmap_from_word(slot_fetcher, pool_manager_address, pool_id, word_pos, block_number).await + tick_bitmap_from_word(slot_fetcher, pool_manager_address, pool_id, word_pos, block_id).await } pub async fn tick_initialized( @@ -197,10 +198,10 @@ pub async fn tick_initialized( tick_spacing: I24, pool_id: B256, tick: I24, - block_number: Option + block_id: BlockId ) -> eyre::Result { let (word_pos, bit_pos) = tick_position_from_compressed(tick, tick_spacing); - let tick_bitmap = tick_bitmap_from_word(slot_fetcher, pool_manager_address, pool_id, word_pos, block_number).await?; + let tick_bitmap = tick_bitmap_from_word(slot_fetcher, pool_manager_address, pool_id, word_pos, block_id).await?; Ok(tick_bitmap.is_initialized(bit_pos)) } @@ -212,14 +213,14 @@ pub async fn next_tick_gt( pool_id: B256, tick: I24, initialized_only: bool, - block_number: Option + block_id: BlockId ) -> eyre::Result<(bool, I24)> { if is_tick_at_bounds(tick, tick_spacing, false) { return Ok((false, tick)); } let (word_pos, bit_pos) = tick_position_from_compressed_inequality(tick, tick_spacing, I24::unchecked_from(1)); - let tick_bitmap = tick_bitmap_from_word(slot_fetcher, pool_manager_address, pool_id, word_pos, block_number).await?; + let tick_bitmap = tick_bitmap_from_word(slot_fetcher, pool_manager_address, pool_id, word_pos, block_id).await?; let (is_initialized, next_bit_pos) = tick_bitmap.next_bit_pos_gte(bit_pos); let next_tick = tick_from_word_and_bit_pos(word_pos, next_bit_pos, tick_spacing); @@ -233,7 +234,7 @@ pub async fn next_tick_gt( pool_id, next_tick, initialized_only, - block_number + block_id )) .await } @@ -246,14 +247,14 @@ pub async fn next_tick_lt( pool_id: B256, tick: I24, initialized_only: bool, - block_number: Option + block_id: BlockId ) -> eyre::Result<(bool, I24)> { if is_tick_at_bounds(tick, tick_spacing, true) { return Ok((false, tick)); } let (word_pos, bit_pos) = tick_position_from_compressed_inequality(tick, tick_spacing, I24::unchecked_from(-1)); - let tick_bitmap = tick_bitmap_from_word(slot_fetcher, pool_manager_address, pool_id, word_pos, block_number).await?; + let tick_bitmap = tick_bitmap_from_word(slot_fetcher, pool_manager_address, pool_id, word_pos, block_id).await?; let (is_initialized, next_bit_pos) = tick_bitmap.next_bit_pos_lte(bit_pos); let next_tick = tick_from_word_and_bit_pos(word_pos, next_bit_pos, tick_spacing); @@ -267,7 +268,7 @@ pub async fn next_tick_lt( pool_id, next_tick, initialized_only, - block_number + block_id )) .await } @@ -280,14 +281,14 @@ pub async fn next_tick_le( pool_id: B256, tick: I24, initialized_only: bool, - block_number: Option + block_id: BlockId ) -> eyre::Result<(bool, I24)> { if is_tick_at_bounds(tick, tick_spacing, true) { return Ok((false, tick)); } let (word_pos, bit_pos) = tick_position_from_compressed(tick, tick_spacing); - let tick_bitmap = tick_bitmap_from_word(slot_fetcher, pool_manager_address, pool_id, word_pos, block_number).await?; + let tick_bitmap = tick_bitmap_from_word(slot_fetcher, pool_manager_address, pool_id, word_pos, block_id).await?; let (is_initialized, next_bit_pos) = tick_bitmap.next_bit_pos_lte(bit_pos); let next_tick = tick_from_word_and_bit_pos(word_pos, next_bit_pos, tick_spacing); @@ -301,7 +302,7 @@ pub async fn next_tick_le( pool_id, next_tick, initialized_only, - block_number + block_id )) .await } @@ -318,6 +319,7 @@ fn is_tick_at_bounds(tick: I24, tick_spacing: I24, is_decreasing: bool) -> bool #[cfg(test)] mod tests { + use alloy_eips::BlockId; use alloy_primitives::{aliases::U24, b256}; use super::*; @@ -390,10 +392,15 @@ mod tests { }; let pool_id = pool_key.into(); - let results = - tick_bitmap_from_word(&provider, UNISWAP_V4_CONSTANTS_MAINNET.pool_manager(), pool_id, 346, Some(block_number)) - .await - .unwrap(); + let results = tick_bitmap_from_word( + &provider, + UNISWAP_V4_CONSTANTS_MAINNET.pool_manager(), + pool_id, + 346, + BlockId::number(block_number) + ) + .await + .unwrap(); assert_eq!(results.0, U256::from_str_radix("2854495385411919762116571938898990272765493248", 10).unwrap()); } @@ -419,7 +426,7 @@ mod tests { tick_spacing, pool_id, tick, - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); @@ -449,7 +456,7 @@ mod tests { pool_id, tick, true, - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); @@ -480,7 +487,7 @@ mod tests { pool_id, tick, true, - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); @@ -511,7 +518,7 @@ mod tests { pool_id, tick, true, - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); @@ -535,7 +542,7 @@ mod tests { tick, tick_spacing, false, - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); @@ -560,7 +567,7 @@ mod tests { tick, tick_spacing, true, - Some(block_number) + BlockId::number(block_number) ) .await .unwrap(); diff --git a/crates/uniswap-storage/src/v4/position_manager.rs b/crates/uniswap-storage/src/v4/position_manager.rs index b29b41d..fd27ce5 100644 --- a/crates/uniswap-storage/src/v4/position_manager.rs +++ b/crates/uniswap-storage/src/v4/position_manager.rs @@ -1,3 +1,4 @@ +use alloy_eips::BlockId; use alloy_primitives::{ Address, B256, Bytes, U256, aliases::{I24, U24}, @@ -32,13 +33,13 @@ pub fn position_manager_pool_key_and_info_slot(position_info: U256) -> B256 { pub async fn position_manager_position_info( slot_fetcher: &F, position_manager_address: Address, - block_number: Option, + block_id: BlockId, token_id: U256 ) -> eyre::Result { let position_info_slot = position_manager_position_info_slot(token_id); let position_info = slot_fetcher - .storage_at(position_manager_address, position_info_slot, block_number) + .storage_at(position_manager_address, position_info_slot, block_id) .await?; Ok(position_info) @@ -47,17 +48,16 @@ pub async fn position_manager_position_info( pub async fn position_manager_pool_key_and_info( slot_fetcher: &F, position_manager_address: Address, - block_number: Option, + block_id: BlockId, token_id: U256 ) -> eyre::Result<(V4PoolKey, UnpackedPositionInfo)> { - let position_info = - position_manager_position_info(slot_fetcher, position_manager_address, block_number, token_id).await?; + let position_info = position_manager_position_info(slot_fetcher, position_manager_address, block_id, token_id).await?; let pool_key_slot_base = U256::from_be_slice(position_manager_pool_key_and_info_slot(position_info).as_slice()); let (slot0, slot1, slot2) = futures::try_join!( - slot_fetcher.storage_at(position_manager_address, pool_key_slot_base.into(), block_number), - slot_fetcher.storage_at(position_manager_address, (pool_key_slot_base + U256::from(1_u8)).into(), block_number), - slot_fetcher.storage_at(position_manager_address, (pool_key_slot_base + U256::from(2_u8)).into(), block_number) + slot_fetcher.storage_at(position_manager_address, pool_key_slot_base.into(), block_id), + slot_fetcher.storage_at(position_manager_address, (pool_key_slot_base + U256::from(1_u8)).into(), block_id), + slot_fetcher.storage_at(position_manager_address, (pool_key_slot_base + U256::from(2_u8)).into(), block_id) )?; let concatted_bytes = Bytes::from(concat([slot0.to_be_bytes_vec(), slot1.to_be_bytes_vec(), slot2.to_be_bytes_vec()])); @@ -76,13 +76,13 @@ pub async fn position_manager_pool_key_and_info( pub async fn position_manager_owner_of( slot_fetcher: &F, position_manager_address: Address, - block_number: Option, + block_id: BlockId, token_id: U256 ) -> eyre::Result

{ let owner_of_slot = position_manager_owner_of_slot(token_id); let owner_of = slot_fetcher - .storage_at(position_manager_address, owner_of_slot, block_number) + .storage_at(position_manager_address, owner_of_slot, block_id) .await?; Ok(Address::from_slice(&owner_of.to_be_bytes_vec()[12..32])) @@ -91,10 +91,10 @@ pub async fn position_manager_owner_of( pub async fn position_manager_next_token_id( slot_fetcher: &F, position_manager_address: Address, - block_number: Option + block_id: BlockId ) -> eyre::Result { let next_token_id = slot_fetcher - .storage_at(position_manager_address, U256::from(POSITION_MANAGER_NEXT_TOKEN_ID_SLOT).into(), block_number) + .storage_at(position_manager_address, U256::from(POSITION_MANAGER_NEXT_TOKEN_ID_SLOT).into(), block_id) .await?; Ok(next_token_id) @@ -103,6 +103,7 @@ pub async fn position_manager_next_token_id( #[cfg(test)] mod tests { + use alloy_eips::BlockId; use alloy_primitives::address; use super::*; @@ -120,7 +121,7 @@ mod tests { let results = position_manager_position_info( &provider, UNISWAP_V4_CONSTANTS_MAINNET.position_manager(), - Some(block_number), + BlockId::number(block_number), U256::from(96348_u64) ) .await @@ -148,7 +149,7 @@ mod tests { let (results, _) = position_manager_pool_key_and_info( &provider, UNISWAP_V4_CONSTANTS_MAINNET.position_manager(), - Some(block_number), + BlockId::number(block_number), U256::from(96348_u64) ) .await @@ -165,7 +166,7 @@ mod tests { let results = position_manager_owner_of( &provider, UNISWAP_V4_CONSTANTS_MAINNET.position_manager(), - Some(block_number), + BlockId::number(block_number), U256::from(96348_u64) ) .await @@ -179,10 +180,13 @@ mod tests { let provider = eth_provider().await; let block_number = 23998000; - let results = - position_manager_next_token_id(&provider, UNISWAP_V4_CONSTANTS_MAINNET.position_manager(), Some(block_number)) - .await - .unwrap(); + let results = position_manager_next_token_id( + &provider, + UNISWAP_V4_CONSTANTS_MAINNET.position_manager(), + BlockId::number(block_number) + ) + .await + .unwrap(); assert_eq!(results, U256::from(111343_u128)); }