Skip to content

Commit

Permalink
feat: return tick spacing in tick lens (#9)
Browse files Browse the repository at this point in the history
Introduce `tickSpacing` to the function `getPopulatedTicksInRange`. This change updates function calls, return types, and test cases to handle the new `tickSpacing` parameter. Major version bump and dependency updates included.
  • Loading branch information
shuhuiluo authored Sep 12, 2024
1 parent a3beba9 commit 65e217d
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 24 deletions.
8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "uniswap-lens"
version = "0.2.1"
version = "0.3.0"
edition = "2021"
authors = ["Shuhui Luo <twitter.com/aureliano_law>"]
description = "A library for querying Uniswap V3 using ephemeral lens contracts."
Expand All @@ -11,16 +11,16 @@ keywords = ["alloy", "ethereum", "solidity", "uniswap"]
include = ["src/**/*.rs"]

[dependencies]
alloy = { version = "0.3.0", features = ["contract", "rpc-types"] }
alloy = { version = "0.3", features = ["contract", "rpc-types"] }
anyhow = "1"

[features]
default = []
std = ["alloy/std"]

[dev-dependencies]
alloy = { version = "0.3.0", features = ["transport-http"] }
dotenv = "0.15.0"
alloy = { version = "0.3", features = ["transport-http"] }
dotenv = "0.15"
futures = "0.3"
once_cell = "1.19"
ruint = "1.12"
Expand Down
12 changes: 8 additions & 4 deletions contracts/EphemeralGetPopulatedTicksInRange.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ import "./PoolUtils.sol";
/// revert data, and decoded by `abi.decode(data, (PopulatedTick[]))`
contract EphemeralGetPopulatedTicksInRange is PoolUtils {
constructor(V3PoolCallee pool, int24 tickLower, int24 tickUpper) payable {
PopulatedTick[] memory populatedTicks = getPopulatedTicksInRange(pool, tickLower, tickUpper);
bytes memory returnData = abi.encode(populatedTicks);
(PopulatedTick[] memory populatedTicks, int24 tickSpacing) = getPopulatedTicksInRange(
pool,
tickLower,
tickUpper
);
bytes memory returnData = abi.encode(populatedTicks, tickSpacing);
assembly ("memory-safe") {
revert(add(returnData, 0x20), mload(returnData))
}
Expand All @@ -25,10 +29,10 @@ contract EphemeralGetPopulatedTicksInRange is PoolUtils {
V3PoolCallee pool,
int24 tickLower,
int24 tickUpper
) public payable returns (PopulatedTick[] memory populatedTicks) {
) public payable returns (PopulatedTick[] memory populatedTicks, int24 tickSpacing) {
require(tickLower <= tickUpper);
// checks that the pool exists
int24 tickSpacing = IUniswapV3Pool(V3PoolCallee.unwrap(pool)).tickSpacing();
tickSpacing = IUniswapV3Pool(V3PoolCallee.unwrap(pool)).tickSpacing();
(int16 wordPosLower, int16 wordPosUpper) = getWordPositions(tickLower, tickUpper, tickSpacing);
unchecked {
(uint256[] memory tickBitmap, uint256 count) = getTickBitmapAndCount(pool, wordPosLower, wordPosUpper);
Expand Down
2 changes: 1 addition & 1 deletion src/caller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ macro_rules! call_ephemeral_contract {
match deploy_builder.call_raw().await {
Err(Error::TransportError(err)) => match err {
TransportError::ErrorResp(payload) => {
let data: Bytes = payload.try_data_as().unwrap().unwrap();
let data: Bytes = payload.as_revert_data().unwrap();
Ok(<$call_type>::abi_decode_returns(data.as_ref(), true).unwrap())
}
_ => panic!("should be an error response: {:?}", err),
Expand Down
36 changes: 23 additions & 13 deletions src/pool_lens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,19 @@
use crate::{
bindings::{
ephemeralgetpopulatedticksinrange::EphemeralGetPopulatedTicksInRange::{
getPopulatedTicksInRangeCall, getPopulatedTicksInRangeReturn,
EphemeralGetPopulatedTicksInRangeInstance, PopulatedTick,
ephemeralgetpopulatedticksinrange::{
EphemeralGetPopulatedTicksInRange::{
getPopulatedTicksInRangeCall, getPopulatedTicksInRangeReturn,
EphemeralGetPopulatedTicksInRangeInstance,
},
PoolUtils::PopulatedTick,
},
ephemeralpoolpositions::EphemeralPoolPositions::{
EphemeralPoolPositionsInstance, PositionKey,
ephemeralpoolpositions::{
EphemeralPoolPositions::EphemeralPoolPositionsInstance, PoolUtils::PositionKey,
},
ephemeralpoolslots::EphemeralPoolSlots::{
getSlotsCall, getSlotsReturn, EphemeralPoolSlotsInstance, Slot,
ephemeralpoolslots::{
EphemeralPoolSlots::{getSlotsCall, getSlotsReturn, EphemeralPoolSlotsInstance},
PoolUtils::Slot,
},
ephemeralpooltickbitmap::EphemeralPoolTickBitmap::EphemeralPoolTickBitmapInstance,
ephemeralpoolticks::EphemeralPoolTicks::EphemeralPoolTicksInstance,
Expand Down Expand Up @@ -49,7 +53,7 @@ pub async fn get_populated_ticks_in_range<T, P>(
tick_upper: I24,
provider: P,
block_id: Option<BlockId>,
) -> Result<Vec<PopulatedTick>>
) -> Result<(Vec<PopulatedTick>, I24)>
where
T: Transport + Clone,
P: Provider<T>,
Expand All @@ -58,10 +62,16 @@ where
provider, pool, tick_lower, tick_upper,
);
match call_ephemeral_contract!(deploy_builder, getPopulatedTicksInRangeCall, block_id) {
Ok(getPopulatedTicksInRangeReturn { populatedTicks }) => Ok(populatedTicks
.into_iter()
.filter(|PopulatedTick { tick, .. }| *tick >= tick_lower && *tick <= tick_upper)
.collect()),
Ok(getPopulatedTicksInRangeReturn {
populatedTicks,
tickSpacing,
}) => Ok((
populatedTicks
.into_iter()
.filter(|PopulatedTick { tick, .. }| *tick >= tick_lower && *tick <= tick_upper)
.collect(),
tickSpacing,
)),
Err(err) => Err(err.into()),
}
}
Expand Down Expand Up @@ -202,7 +212,7 @@ mod tests {
let pool = IUniswapV3PoolInstance::new(POOL_ADDRESS, provider.clone());
let tick_current = pool.slot0().block(BLOCK_NUMBER).call().await?.tick;
let tick_spacing = pool.tickSpacing().block(BLOCK_NUMBER).call().await?._0;
let ticks = get_populated_ticks_in_range(
let (ticks, _) = get_populated_ticks_in_range(
POOL_ADDRESS,
tick_current,
tick_current + (tick_spacing << 8),
Expand Down
6 changes: 5 additions & 1 deletion test/foundry/TickLens.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ contract TickLensTest is BaseTest, PoolUtils {
tick + 128 * tickSpacing
)
{} catch (bytes memory returnData) {
PopulatedTick[] memory populatedTicks = abi.decode(returnData, (PopulatedTick[]));
(PopulatedTick[] memory populatedTicks, int24 _tickSpacing) = abi.decode(
returnData,
(PopulatedTick[], int24)
);
assertEq(_tickSpacing, IUniswapV3Pool(pool).tickSpacing(), "tickSpacing");
console2.log("length", populatedTicks.length);
verifyTicks(populatedTicks);
}
Expand Down
2 changes: 1 addition & 1 deletion test/hardhat/univ3_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ describe("Pool lens test with UniV3 on mainnet", () => {

it("Test getting populated ticks", async () => {
const [, tickCurrent] = await poolContract.read.slot0({ blockNumber });
const ticks = await getPopulatedTicksInRange(pool, tickCurrent, tickCurrent, publicClient, blockNumber);
const [ticks] = await getPopulatedTicksInRange(pool, tickCurrent, tickCurrent, publicClient, blockNumber);
await Promise.all(
ticks.map(async ({ tick, liquidityGross, liquidityNet }) => {
const [_liquidityGross, _liquidityNet] = await poolContract.read.ticks([tick], { blockNumber });
Expand Down

0 comments on commit 65e217d

Please sign in to comment.