diff --git a/Cargo.toml b/Cargo.toml index d6c0b3d..2e8fd8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,3 +61,7 @@ harness = false [[bench]] name = "tick_math" harness = false + +[[example]] +name = "from_pool_key_with_tick_data_provider" +required-features = ["extensions"] diff --git a/README.md b/README.md index a57e96f..c00f470 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,33 @@ use uniswap_v3_sdk::prelude::*; By default, this library does not depend on the standard library (`std`). However, the `std` feature can be enabled to use `thiserror` for error handling. +## Examples + +The code below shows an example of creating a pool with a tick map data provider and simulating a swap with it. + +```rust +#[tokio::main] +async fn main() { + // Create a pool with a tick map data provider + let pool = Pool::::from_pool_key_with_tick_data_provider( + 1, + FACTORY_ADDRESS, + wbtc.address(), + weth.address(), + FeeAmount::LOW, + provider.clone(), + block_id, + ) + .await + .unwrap(); + // Get the output amount from the pool + let amount_in = CurrencyAmount::from_raw_amount(wbtc.clone(), 100000000).unwrap(); + let (amount_out, _pool_after) = pool.get_output_amount(&amount_in, None).unwrap(); +} +``` + +For runnable examples, see the [examples](./examples) directory. + ## Contributing Contributions are welcome. Please open an issue if you have any questions or suggestions. diff --git a/examples/from_pool_key_with_tick_data_provider.rs b/examples/from_pool_key_with_tick_data_provider.rs new file mode 100644 index 0000000..0ebd387 --- /dev/null +++ b/examples/from_pool_key_with_tick_data_provider.rs @@ -0,0 +1,69 @@ +//! Example demonstrating pool creation with tick data provider and swap simulation +//! +//! # Prerequisites +//! - Environment variable MAINNET_RPC_URL must be set +//! - Requires the "extensions" feature +//! +//! # Note +//! This example uses mainnet block 17000000 for consistent results + +use alloy::{ + eips::BlockId, + providers::{Provider, ProviderBuilder}, + rpc::types::TransactionRequest, +}; +use alloy_primitives::{address, ruint::aliases::U256, U160}; +use alloy_sol_types::SolValue; +use uniswap_sdk_core::{prelude::*, token}; +use uniswap_v3_sdk::prelude::*; + +#[tokio::main] +async fn main() { + dotenv::dotenv().ok(); + let rpc_url = std::env::var("MAINNET_RPC_URL").unwrap().parse().unwrap(); + let provider = ProviderBuilder::new().on_http(rpc_url); + let block_id = BlockId::from(17000000); + let wbtc = token!(1, "2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", 8, "WBTC"); + let weth = token!(1, "C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", 18, "WETH"); + + // Create a pool with a tick map data provider + let pool = Pool::::from_pool_key_with_tick_data_provider( + 1, + FACTORY_ADDRESS, + wbtc.address(), + weth.address(), + FeeAmount::LOW, + provider.clone(), + Some(block_id), + ) + .await + .unwrap(); + // Get the output amount from the pool + let amount_in = CurrencyAmount::from_raw_amount(wbtc.clone(), 100000000).unwrap(); + let (local_amount_out, _pool_after) = pool.get_output_amount(&amount_in, None).unwrap(); + println!("Local amount out: {}", local_amount_out.quotient()); + + let route = Route::new(vec![pool.clone()], wbtc, weth); + let params = quote_call_parameters( + &route, + &amount_in, + TradeType::ExactInput, + Some(QuoteOptions { + sqrt_price_limit_x96: U160::ZERO, + use_quoter_v2: false, + }), + ); + let quoter_addr = *QUOTER_ADDRESSES.get(&1).unwrap(); + let tx = TransactionRequest { + to: Some(quoter_addr.into()), + input: params.calldata.into(), + ..Default::default() + }; + // Get the output amount from the quoter + let res = provider.call(&tx).block(block_id).await.unwrap(); + let amount_out = U256::abi_decode(res.as_ref(), true).unwrap(); + println!("Quoter amount out: {}", amount_out); + + // Compare local calculation with on-chain quoter to ensure accuracy + assert_eq!(U256::from_big_int(local_amount_out.quotient()), amount_out); +} diff --git a/src/extensions/pool.rs b/src/extensions/pool.rs index 69048d2..8ad168a 100644 --- a/src/extensions/pool.rs +++ b/src/extensions/pool.rs @@ -103,6 +103,48 @@ impl Pool { } impl Pool> { + /// Get a [`Pool`] struct with tick data provider from pool key + /// + /// ## Arguments + /// + /// * `chain_id`: The chain id + /// * `factory`: The factory address + /// * `token_a`: One of the tokens in the pool + /// * `token_b`: The other token in the pool + /// * `fee`: Fee tier of the pool + /// * `provider`: The alloy provider + /// * `block_id`: Optional block number to query. + /// + /// ## Returns + /// + /// A [`Pool`] struct with tick data provider + /// + /// ## Examples + /// + /// ``` + /// use alloy::{eips::BlockId, providers::ProviderBuilder}; + /// use alloy_primitives::address; + /// use uniswap_v3_sdk::prelude::*; + /// + /// #[tokio::main] + /// async fn main() { + /// dotenv::dotenv().ok(); + /// let rpc_url = std::env::var("MAINNET_RPC_URL").unwrap().parse().unwrap(); + /// let provider = ProviderBuilder::new().on_http(rpc_url); + /// let block_id = Some(BlockId::from(17000000)); + /// let pool = Pool::::from_pool_key_with_tick_data_provider( + /// 1, + /// FACTORY_ADDRESS, + /// address!("2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"), + /// address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), + /// FeeAmount::LOW, + /// provider, + /// block_id, + /// ) + /// .await + /// .unwrap(); + /// } + /// ``` #[inline] pub async fn from_pool_key_with_tick_data_provider( chain_id: ChainId,