diff --git a/Cargo.toml b/Cargo.toml index f1a8d6a..deb86d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uniswap-v3-sdk" -version = "3.4.0" +version = "3.5.0" edition = "2021" authors = ["Shuhui Luo "] description = "Uniswap V3 SDK for Rust" @@ -15,7 +15,7 @@ exclude = [".github", ".gitignore", "rustfmt.toml"] all-features = true [dependencies] -alloy = { version = "0.9", optional = true, features = ["contract"] } +alloy = { version = "0.11", optional = true, features = ["contract"] } alloy-primitives = "0.8" alloy-sol-types = "0.8" anyhow = { version = "1.0", optional = true } @@ -29,7 +29,7 @@ once_cell = "1.20" regex = { version = "1.11", optional = true } serde_json = { version = "1.0", optional = true } thiserror = { version = "2", default-features = false } -uniswap-lens = { version = "0.10", optional = true } +uniswap-lens = { version = "0.11", optional = true } uniswap-sdk-core = "3.4.0" [features] @@ -38,11 +38,11 @@ extensions = ["alloy", "anyhow", "base64", "regex", "serde_json", "uniswap-lens" std = ["alloy?/std", "thiserror/std", "uniswap-sdk-core/std", "uniswap-lens?/std"] [dev-dependencies] -alloy = { version = "0.9", features = ["provider-anvil-node", "signer-local"] } +alloy = { version = "0.11", features = ["provider-anvil-node", "signer-local"] } criterion = "0.5.1" dotenv = "0.15.0" -tokio = { version = "1.40", features = ["full"] } -uniswap_v3_math = "0.5.2" +tokio = { version = "1.43", features = ["full"] } +uniswap_v3_math = "0.5.3" [[bench]] name = "bit_math" diff --git a/examples/nonfungible_position_manager.rs b/examples/nonfungible_position_manager.rs index 9da1cbb..471bf96 100644 --- a/examples/nonfungible_position_manager.rs +++ b/examples/nonfungible_position_manager.rs @@ -1,14 +1,14 @@ use alloy::{ eips::BlockId, + network::{Network, TransactionBuilder}, node_bindings::WEI_IN_ETHER, providers::{ext::AnvilApi, Provider, ProviderBuilder}, - rpc::types::TransactionRequest, signers::{ k256::ecdsa::SigningKey, local::{LocalSigner, PrivateKeySigner}, SignerSync, }, - transports::{http::reqwest::Url, Transport}, + transports::http::reqwest::Url, }; use alloy_primitives::{address, Address, U256}; use uniswap_lens::bindings::ierc721enumerable::IERC721Enumerable; @@ -30,13 +30,11 @@ async fn main() { let npm = *NONFUNGIBLE_POSITION_MANAGER_ADDRESSES.get(&1).unwrap(); // Create an Anvil fork - let provider = ProviderBuilder::new() - .with_recommended_fillers() - .on_anvil_with_config(|anvil| { - anvil - .fork(rpc_url) - .fork_block_number(block_id.as_u64().unwrap()) - }); + let provider = ProviderBuilder::new().on_anvil_with_config(|anvil| { + anvil + .fork(rpc_url) + .fork_block_number(block_id.as_u64().unwrap()) + }); provider.anvil_auto_impersonate_account(true).await.unwrap(); let account: LocalSigner = PrivateKeySigner::random(); provider @@ -120,10 +118,10 @@ async fn main() { } /// Mint a position -async fn mint_liquidity(position: &mut Position, from: Address, provider: &P) -> U256 +async fn mint_liquidity(position: &mut Position, from: Address, provider: &P) -> U256 where - T: Transport + Clone, - P: Provider, + N: Network, + P: Provider, { let npm = *NONFUNGIBLE_POSITION_MANAGER_ADDRESSES.get(&1).unwrap(); @@ -139,10 +137,10 @@ where }), }; let params = add_call_parameters(position, options).unwrap(); - let tx = TransactionRequest::default() - .from(from) - .to(npm) - .input(params.calldata.into()); + let tx = N::TransactionRequest::default() + .with_from(from) + .with_to(npm) + .with_input(params.calldata); provider .send_transaction(tx) .await @@ -160,15 +158,15 @@ where } /// Burn a position with a permit -async fn burn_liquidity( +async fn burn_liquidity( token_id: U256, position: &Position, owner: &LocalSigner, sender: Address, provider: &P, ) where - T: Transport + Clone, - P: Provider, + N: Network, + P: Provider, { let npm = *NONFUNGIBLE_POSITION_MANAGER_ADDRESSES.get(&1).unwrap(); @@ -213,10 +211,10 @@ async fn burn_liquidity( }, }; let params = remove_call_parameters(position, options).unwrap(); - let tx = TransactionRequest::default() - .from(sender) - .to(npm) - .input(params.calldata.into()); + let tx = N::TransactionRequest::default() + .with_from(sender) + .with_to(npm) + .with_input(params.calldata); provider .send_transaction(tx) .await diff --git a/examples/self_permit.rs b/examples/self_permit.rs index a7621f8..23906fc 100644 --- a/examples/self_permit.rs +++ b/examples/self_permit.rs @@ -38,13 +38,11 @@ async fn main() { let block_id = BlockId::from(17000000); // Create an Anvil fork - let provider = ProviderBuilder::new() - .with_recommended_fillers() - .on_anvil_with_config(|anvil| { - anvil - .fork(rpc_url) - .fork_block_number(block_id.as_u64().unwrap()) - }); + let provider = ProviderBuilder::new().on_anvil_with_config(|anvil| { + anvil + .fork(rpc_url) + .fork_block_number(block_id.as_u64().unwrap()) + }); provider.anvil_auto_impersonate_account(true).await.unwrap(); let usdc = token!(1, "A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", 6); diff --git a/examples/swap_router.rs b/examples/swap_router.rs index e4be5fc..f1136f8 100644 --- a/examples/swap_router.rs +++ b/examples/swap_router.rs @@ -65,13 +65,11 @@ async fn main() { println!("Quoter amount out: {}", amount_out); // Create an Anvil fork - let provider = ProviderBuilder::new() - .with_recommended_fillers() - .on_anvil_with_config(|anvil| { - anvil - .fork(rpc_url) - .fork_block_number(block_id.as_u64().unwrap()) - }); + let provider = ProviderBuilder::new().on_anvil_with_config(|anvil| { + anvil + .fork(rpc_url) + .fork_block_number(block_id.as_u64().unwrap()) + }); let account = provider.get_accounts().await.unwrap()[0]; // Build the swap transaction diff --git a/src/entities/trade.rs b/src/entities/trade.rs index 39950e7..51321b0 100644 --- a/src/entities/trade.rs +++ b/src/entities/trade.rs @@ -114,14 +114,14 @@ where /// Returns the input currency of the swap #[inline] - pub fn input_currency(&self) -> &TInput { - &self.input_amount.currency + pub const fn input_currency(&self) -> &TInput { + &self.input_amount.meta.currency } /// Returns the output currency of the swap #[inline] - pub fn output_currency(&self) -> &TOutput { - &self.output_amount.currency + pub const fn output_currency(&self) -> &TOutput { + &self.output_amount.meta.currency } } diff --git a/src/extensions/ephemeral_tick_data_provider.rs b/src/extensions/ephemeral_tick_data_provider.rs index 358f016..b0ad435 100644 --- a/src/extensions/ephemeral_tick_data_provider.rs +++ b/src/extensions/ephemeral_tick_data_provider.rs @@ -2,7 +2,7 @@ //! A data provider that fetches ticks using an [ephemeral contract](https://github.com/Aperture-Finance/Aperture-Lens/blob/904101e4daed59e02fd4b758b98b0749e70b583b/contracts/EphemeralGetPopulatedTicksInRange.sol) in a single `eth_call`. use crate::prelude::*; -use alloy::{eips::BlockId, providers::Provider, transports::Transport}; +use alloy::{eips::BlockId, network::Network, providers::Provider}; use alloy_primitives::{aliases::I24, Address}; use derive_more::Deref; use uniswap_lens::pool_lens; @@ -21,7 +21,7 @@ pub struct EphemeralTickDataProvider { impl EphemeralTickDataProvider { #[inline] - pub async fn new( + pub async fn new( pool: Address, provider: P, tick_lower: Option, @@ -29,8 +29,8 @@ impl EphemeralTickDataProvider { block_id: Option, ) -> Result where - T: Transport + Clone, - P: Provider, + N: Network, + P: Provider, { let tick_lower = tick_lower.map_or(MIN_TICK, I::to_i24); let tick_upper = tick_upper.map_or(MAX_TICK, I::to_i24); diff --git a/src/extensions/ephemeral_tick_map_data_provider.rs b/src/extensions/ephemeral_tick_map_data_provider.rs index 602f725..7359523 100644 --- a/src/extensions/ephemeral_tick_map_data_provider.rs +++ b/src/extensions/ephemeral_tick_map_data_provider.rs @@ -2,7 +2,7 @@ //! A data provider that fetches ticks using an [ephemeral contract](https://github.com/Aperture-Finance/Aperture-Lens/blob/904101e4daed59e02fd4b758b98b0749e70b583b/contracts/EphemeralGetPopulatedTicksInRange.sol) in a single `eth_call`. use crate::prelude::*; -use alloy::{eips::BlockId, providers::Provider, transports::Transport}; +use alloy::{eips::BlockId, network::Network, providers::Provider}; use alloy_primitives::{aliases::I24, Address}; use derive_more::Deref; @@ -20,7 +20,7 @@ pub struct EphemeralTickMapDataProvider { impl EphemeralTickMapDataProvider { #[inline] - pub async fn new( + pub async fn new( pool: Address, provider: P, tick_lower: Option, @@ -28,8 +28,8 @@ impl EphemeralTickMapDataProvider { block_id: Option, ) -> Result where - T: Transport + Clone, - P: Provider, + N: Network, + P: Provider, { let provider = EphemeralTickDataProvider::new(pool, provider, tick_lower, tick_upper, block_id) diff --git a/src/extensions/pool.rs b/src/extensions/pool.rs index c197239..9151b00 100644 --- a/src/extensions/pool.rs +++ b/src/extensions/pool.rs @@ -6,8 +6,8 @@ use crate::prelude::*; use alloy::{ eips::{BlockId, BlockNumberOrTag}, + network::Network, providers::Provider, - transports::Transport, }; use alloy_primitives::{Address, ChainId, B256}; use uniswap_lens::{ @@ -19,16 +19,16 @@ use uniswap_lens::{ use uniswap_sdk_core::{prelude::Token, token}; #[inline] -pub fn get_pool_contract( +pub fn get_pool_contract( factory: Address, token_a: Address, token_b: Address, fee: FeeAmount, provider: P, -) -> IUniswapV3PoolInstance +) -> IUniswapV3PoolInstance<(), P, N> where - T: Transport + Clone, - P: Provider, + N: Network, + P: Provider, { IUniswapV3PoolInstance::new( compute_pool_address(factory, token_a, token_b, fee, None, None), @@ -49,7 +49,7 @@ impl Pool { /// * `provider`: The alloy provider /// * `block_id`: Optional block number to query. #[inline] - pub async fn from_pool_key( + pub async fn from_pool_key( chain_id: ChainId, factory: Address, token_a: Address, @@ -59,13 +59,13 @@ impl Pool { block_id: Option, ) -> Result where - T: Transport + Clone, - P: Provider + Clone, + N: Network, + P: Provider, { let block_id = block_id.unwrap_or(BlockId::Number(BlockNumberOrTag::Latest)); - let pool_contract = get_pool_contract(factory, token_a, token_b, fee, provider.clone()); - let token_a_contract = IERC20Metadata::new(token_a, provider.clone()); - let token_b_contract = IERC20Metadata::new(token_b, provider); + let pool_contract = get_pool_contract(factory, token_a, token_b, fee, provider.root()); + let token_a_contract = IERC20Metadata::new(token_a, provider.root()); + let token_b_contract = IERC20Metadata::new(token_b, provider.root()); // TODO: use multicall let slot_0 = pool_contract.slot0().block(block_id).call().await?; let liquidity = pool_contract.liquidity().block(block_id).call().await?._0; @@ -146,7 +146,7 @@ impl Pool> { /// } /// ``` #[inline] - pub async fn from_pool_key_with_tick_data_provider( + pub async fn from_pool_key_with_tick_data_provider( chain_id: ChainId, factory: Address, token_a: Address, @@ -156,8 +156,8 @@ impl Pool> { block_id: Option, ) -> Result where - T: Transport + Clone, - P: Provider + Clone, + N: Network, + P: Provider, { let pool = Pool::from_pool_key( chain_id, @@ -165,7 +165,7 @@ impl Pool> { token_a, token_b, fee, - provider.clone(), + provider.root(), block_id, ) .await?; @@ -265,7 +265,7 @@ pub fn reconstruct_liquidity_array( /// /// An array of ticks and corresponding cumulative liquidity. #[inline] -pub async fn get_liquidity_array_for_pool( +pub async fn get_liquidity_array_for_pool( pool: Pool, tick_lower: TP::Index, tick_upper: TP::Index, @@ -276,8 +276,8 @@ pub async fn get_liquidity_array_for_pool( ) -> Result, Error> where TP: TickDataProvider, - T: Transport + Clone, - P: Provider, + N: Network, + P: Provider, { let (tick_current_aligned, tick_lower, tick_upper) = normalize_ticks( pool.tick_current, diff --git a/src/extensions/position.rs b/src/extensions/position.rs index c303fdd..aab70d7 100644 --- a/src/extensions/position.rs +++ b/src/extensions/position.rs @@ -6,8 +6,8 @@ use crate::prelude::{Error, *}; use alloy::{ eips::{BlockId, BlockNumberOrTag}, + network::Network, providers::Provider, - transports::Transport, }; use alloy_primitives::{Address, ChainId, U256}; use anyhow::Result; @@ -26,13 +26,13 @@ use uniswap_lens::{ use uniswap_sdk_core::{prelude::*, token}; #[inline] -pub const fn get_nonfungible_position_manager_contract( +pub const fn get_nonfungible_position_manager_contract( nonfungible_position_manager: Address, provider: P, -) -> IUniswapV3NonfungiblePositionManagerInstance +) -> IUniswapV3NonfungiblePositionManagerInstance<(), P, N> where - T: Transport + Clone, - P: Provider, + N: Network, + P: Provider, { IUniswapV3NonfungiblePositionManagerInstance::new(nonfungible_position_manager, provider) } @@ -47,7 +47,7 @@ where /// * `provider`: The alloy provider /// * `block_id`: Optional block number to query #[inline] -pub async fn get_position( +pub async fn get_position( chain_id: ChainId, nonfungible_position_manager: Address, token_id: U256, @@ -55,12 +55,12 @@ pub async fn get_position( block_id: Option, ) -> Result where - T: Transport + Clone, - P: Provider + Clone, + N: Network, + P: Provider, { let block_id_ = block_id.unwrap_or(BlockId::Number(BlockNumberOrTag::Latest)); let npm_contract = - get_nonfungible_position_manager_contract(nonfungible_position_manager, provider.clone()); + get_nonfungible_position_manager_contract(nonfungible_position_manager, provider.root()); // TODO: use multicall let factory = npm_contract.factory().block(block_id_).call().await?._0; let position = npm_contract @@ -107,7 +107,7 @@ impl Position { /// * `provider`: The alloy provider /// * `block_id`: Optional block number to query #[inline] - pub async fn from_token_id( + pub async fn from_token_id( chain_id: ChainId, nonfungible_position_manager: Address, token_id: U256, @@ -115,8 +115,8 @@ impl Position { block_id: Option, ) -> Result where - T: Transport + Clone, - P: Provider, + N: Network, + P: Provider, { let EphemeralGetPosition::PositionState { position, @@ -164,7 +164,7 @@ impl Position> { /// /// [`Position>`] #[inline] - pub async fn from_token_id_with_tick_data_provider( + pub async fn from_token_id_with_tick_data_provider( chain_id: ChainId, nonfungible_position_manager: Address, token_id: U256, @@ -172,14 +172,14 @@ impl Position> { block_id: Option, ) -> Result where - T: Transport + Clone, - P: Provider + Clone, + N: Network, + P: Provider, { let position = Position::from_token_id( chain_id, nonfungible_position_manager, token_id, - provider.clone(), + provider.root(), block_id, ) .await?; @@ -224,15 +224,15 @@ impl Position> { /// * `provider`: The alloy provider /// * `block_id`: Optional block number to query #[inline] -pub async fn get_all_positions_by_owner( +pub async fn get_all_positions_by_owner( nonfungible_position_manager: Address, owner: Address, provider: P, block_id: Option, ) -> Result, Error> where - T: Transport + Clone, - P: Provider, + N: Network, + P: Provider, { position_lens::get_all_positions_by_owner( nonfungible_position_manager, @@ -258,7 +258,7 @@ where /// /// A tuple of the collectable token amounts. #[inline] -pub async fn get_collectable_token_amounts( +pub async fn get_collectable_token_amounts( _chain_id: ChainId, nonfungible_position_manager: Address, token_id: U256, @@ -266,12 +266,12 @@ pub async fn get_collectable_token_amounts( block_id: Option, ) -> Result<(U256, U256)> where - T: Transport + Clone, - P: Provider + Clone, + N: Network, + P: Provider, { let block_id_ = block_id.unwrap_or(BlockId::Number(BlockNumberOrTag::Latest)); let npm_contract = - get_nonfungible_position_manager_contract(nonfungible_position_manager, provider.clone()); + get_nonfungible_position_manager_contract(nonfungible_position_manager, provider.root()); // TODO: use multicall let factory = npm_contract.factory().block(block_id_).call().await?._0; let position = npm_contract @@ -357,15 +357,15 @@ where /// * `provider`: The alloy provider /// * `block_id`: Optional block number to query #[inline] -pub async fn get_token_svg( +pub async fn get_token_svg( nonfungible_position_manager: Address, token_id: U256, provider: P, block_id: Option, ) -> Result where - T: Transport + Clone, - P: Provider, + N: Network, + P: Provider, { let uri = get_nonfungible_position_manager_contract(nonfungible_position_manager, provider) .tokenURI(token_id) diff --git a/src/extensions/state_overrides.rs b/src/extensions/state_overrides.rs index 8464dbb..34d3e93 100644 --- a/src/extensions/state_overrides.rs +++ b/src/extensions/state_overrides.rs @@ -5,12 +5,9 @@ use crate::prelude::Error; use alloc::vec::Vec; use alloy::{ eips::eip2930::{AccessList, AccessListItem}, + network::{Network, TransactionBuilder}, providers::Provider, - rpc::types::{ - state::{AccountOverride, StateOverride}, - TransactionRequest, - }, - transports::Transport, + rpc::types::state::{AccountOverride, StateOverride}, }; use alloy_primitives::{ map::{B256HashMap, B256HashSet}, @@ -20,7 +17,7 @@ use alloy_sol_types::SolCall; use uniswap_lens::bindings::ierc20::IERC20; #[inline] -pub async fn get_erc20_state_overrides( +pub async fn get_erc20_state_overrides( token: Address, owner: Address, spender: Address, @@ -28,17 +25,17 @@ pub async fn get_erc20_state_overrides( provider: &P, ) -> Result where - T: Transport + Clone, - P: Provider, + N: Network, + P: Provider, { - let balance_tx = TransactionRequest::default() - .to(token) - .gas_limit(0x11E1A300) // avoids "intrinsic gas too low" error - .input(IERC20::balanceOfCall { account: owner }.abi_encode().into()); - let allowance_tx = TransactionRequest::default() - .to(token) - .gas_limit(0x11E1A300) - .input(IERC20::allowanceCall { owner, spender }.abi_encode().into()); + let balance_tx = N::TransactionRequest::default() + .with_to(token) + .with_gas_limit(0x11E1A300) // avoids "intrinsic gas too low" error + .with_input(IERC20::balanceOfCall { account: owner }.abi_encode()); + let allowance_tx = N::TransactionRequest::default() + .with_to(token) + .with_gas_limit(0x11E1A300) + .with_input(IERC20::allowanceCall { owner, spender }.abi_encode()); let balance_access_list = provider.create_access_list(&balance_tx).await?.access_list; let allowance_access_list = provider .create_access_list(&allowance_tx) @@ -51,10 +48,20 @@ where return Err(Error::InvalidAccessList); } // get rid of the storage key of implementation address - let balance_slots_set = - B256HashSet::from_iter(filtered_balance_access_list[0].storage_keys.clone()); - let allowance_slots_set = - B256HashSet::from_iter(filtered_allowance_access_list[0].storage_keys.clone()); + let balance_slots_set = B256HashSet::from_iter( + filtered_balance_access_list + .into_iter() + .next() + .unwrap() + .storage_keys, + ); + let allowance_slots_set = B256HashSet::from_iter( + filtered_allowance_access_list + .into_iter() + .next() + .unwrap() + .storage_keys, + ); let state_diff = B256HashMap::from_iter( balance_slots_set .symmetric_difference(&allowance_slots_set) diff --git a/src/tests.rs b/src/tests.rs index 152045f..4a43946 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -130,8 +130,11 @@ pub(crate) static RPC_URL: Lazy = Lazy::n }); #[cfg(feature = "extensions")] -pub(crate) static PROVIDER: Lazy = - Lazy::new(|| alloy::providers::ProviderBuilder::new().on_http(RPC_URL.clone())); +pub(crate) static PROVIDER: Lazy = Lazy::new(|| { + alloy::providers::ProviderBuilder::new() + .disable_recommended_fillers() + .on_http(RPC_URL.clone()) +}); #[cfg(feature = "extensions")] pub(crate) static BLOCK_ID: Lazy> =