-
Notifications
You must be signed in to change notification settings - Fork 19
/
ephemeral_tick_data_provider.rs
111 lines (104 loc) · 3.6 KB
/
ephemeral_tick_data_provider.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//! ## Ephemeral Tick Data Provider
//! 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_primitives::{aliases::I24, Address};
use derive_more::Deref;
use uniswap_lens::pool_lens;
/// A data provider that fetches ticks using an ephemeral contract in a single `eth_call`.
#[derive(Clone, Debug, PartialEq, Deref)]
pub struct EphemeralTickDataProvider<I = I24> {
pub pool: Address,
pub tick_lower: I,
pub tick_upper: I,
pub tick_spacing: I,
pub block_id: Option<BlockId>,
#[deref]
pub ticks: Vec<Tick<I>>,
}
impl<I: TickIndex> EphemeralTickDataProvider<I> {
#[inline]
pub async fn new<T, P>(
pool: Address,
provider: P,
tick_lower: Option<I>,
tick_upper: Option<I>,
block_id: Option<BlockId>,
) -> Result<Self, Error>
where
T: Transport + Clone,
P: Provider<T>,
{
let tick_lower = tick_lower.map_or(MIN_TICK, I::to_i24);
let tick_upper = tick_upper.map_or(MAX_TICK, I::to_i24);
let (ticks, tick_spacing) = pool_lens::get_populated_ticks_in_range(
pool, tick_lower, tick_upper, provider, block_id,
)
.await
.map_err(Error::LensError)?;
let ticks: Vec<_> = ticks
.into_iter()
.map(|tick| {
Tick::new(
I::from_i24(tick.tick),
tick.liquidityGross,
tick.liquidityNet,
)
})
.collect();
Ok(Self {
pool,
tick_lower: I::from_i24(tick_lower),
tick_upper: I::from_i24(tick_upper),
tick_spacing: I::from_i24(tick_spacing),
block_id,
ticks,
})
}
}
impl<I: TickIndex> From<EphemeralTickDataProvider<I>> for TickListDataProvider<I> {
#[inline]
fn from(provider: EphemeralTickDataProvider<I>) -> Self {
assert!(!provider.ticks.is_empty());
Self::new(provider.ticks, provider.tick_spacing)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tests::*;
use alloy_primitives::address;
const TICK_SPACING: i32 = 10;
#[tokio::test]
async fn test_ephemeral_tick_data_provider() -> Result<(), Error> {
let provider = EphemeralTickDataProvider::new(
address!("88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"),
PROVIDER.clone(),
None,
None,
*BLOCK_ID,
)
.await?;
assert!(!provider.ticks.is_empty());
provider.ticks.validate_list(TICK_SPACING);
let tick = provider.get_tick(-92110)?;
assert_eq!(tick.liquidity_gross, 398290794261);
assert_eq!(tick.liquidity_net, 398290794261);
let (tick, initialized) = provider.next_initialized_tick_within_one_word(
MIN_TICK_I32 + TICK_SPACING,
true,
TICK_SPACING,
)?;
assert!(initialized);
assert_eq!(tick, -887270);
let (tick, initialized) =
provider.next_initialized_tick_within_one_word(0, false, TICK_SPACING)?;
assert!(initialized);
assert_eq!(tick, 100);
let provider: TickListDataProvider = provider.into();
let tick = provider.get_tick(-92110)?;
assert_eq!(tick.liquidity_gross, 398290794261);
assert_eq!(tick.liquidity_net, 398290794261);
Ok(())
}
}