Skip to content
This repository was archived by the owner on Oct 16, 2025. It is now read-only.

Commit 993bc0e

Browse files
authored
add the oracle get earliest observation method (#9)
1 parent 75a2dc8 commit 993bc0e

File tree

4 files changed

+72
-2
lines changed

4 files changed

+72
-2
lines changed

.tool-versions

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
scarb 2.8.1
1+
scarb 2.8.2

Scarb.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,4 @@ block_id.number = "677957"
2727

2828
[dev-dependencies]
2929
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.30.0" }
30-
assert_macros = "2.8.0"
30+
assert_macros = "2.8.2"

src/oracle.cairo

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ use starknet::{ContractAddress};
88

99
#[starknet::interface]
1010
pub trait IOracle<TContractState> {
11+
// Returns the timestamp of the earliest observation for a given pair, or Option::None if the
12+
// pair has no observations
13+
fn get_earliest_observation_time(
14+
self: @TContractState, token_a: ContractAddress, token_b: ContractAddress
15+
) -> Option<u64>;
16+
1117
// Returns the time weighted average tick between the given start and end time
1218
fn get_average_tick_over_period(
1319
self: @TContractState,
@@ -102,6 +108,7 @@ pub trait IOracle<TContractState> {
102108

103109
#[starknet::contract]
104110
pub mod Oracle {
111+
use core::cmp::{max};
105112
use core::num::traits::{Zero, Sqrt, WideMul};
106113
use core::traits::{Into};
107114
use ekubo::components::owned::{Owned as owned_component};
@@ -291,6 +298,40 @@ pub mod Oracle {
291298

292299
#[abi(embed_v0)]
293300
impl OracleImpl of IOracle<ContractState> {
301+
fn get_earliest_observation_time(
302+
self: @ContractState, token_a: ContractAddress, token_b: ContractAddress
303+
) -> Option<u64> {
304+
let oracle_token = self.oracle_token.read();
305+
306+
if token_a == oracle_token || token_b == oracle_token {
307+
let (token0, token1) = if token_a < token_b {
308+
(token_a, token_b)
309+
} else {
310+
(token_b, token_a)
311+
};
312+
let entry = self.pool_state.entry((token0, token1));
313+
let count = entry.count.read();
314+
if count.is_zero() {
315+
Option::None
316+
} else {
317+
let first = entry.snapshots.entry(0).read();
318+
Option::Some(first.block_timestamp)
319+
}
320+
} else {
321+
if let Option::Some(time_a) = self
322+
.get_earliest_observation_time(oracle_token, token_a) {
323+
if let Option::Some(time_b) = self
324+
.get_earliest_observation_time(oracle_token, token_b) {
325+
Option::Some(max(time_a, time_b))
326+
} else {
327+
Option::None
328+
}
329+
} else {
330+
Option::None
331+
}
332+
}
333+
}
334+
294335
fn get_average_tick_over_period(
295336
self: @ContractState,
296337
base_token: ContractAddress,

src/oracle_test.cairo

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,35 @@ fn test_get_tick_cumulative_at_future() {
220220
oracle.get_average_tick_over_period(pool_key.token0, pool_key.token1, start, start + 1);
221221
}
222222

223+
#[test]
224+
#[fork("mainnet")]
225+
fn test_get_earliest_observation_time() {
226+
let (pool_key_0, pool_key_1) = setup();
227+
let oracle = IOracleDispatcher { contract_address: pool_key_0.extension };
228+
229+
let start = get_block_timestamp() + 10;
230+
cheat_block_timestamp(oracle.contract_address, start, CheatSpan::Indefinite);
231+
ekubo_core().initialize_pool(pool_key_0, Zero::zero());
232+
cheat_block_timestamp(oracle.contract_address, start + 15, CheatSpan::Indefinite);
233+
ekubo_core().initialize_pool(pool_key_1, Zero::zero());
234+
235+
assert_eq!(
236+
oracle.get_earliest_observation_time(pool_key_0.token0, pool_key_0.token1).unwrap(), start
237+
);
238+
assert_eq!(
239+
oracle.get_earliest_observation_time(pool_key_1.token0, pool_key_1.token1).unwrap(),
240+
start + 15
241+
);
242+
assert_eq!(
243+
oracle.get_earliest_observation_time(pool_key_0.token0, pool_key_0.token1).unwrap(), start
244+
);
245+
// token0, token2
246+
assert_eq!(
247+
oracle.get_earliest_observation_time(pool_key_0.token0, pool_key_1.token1).unwrap(),
248+
start + 15
249+
);
250+
}
251+
223252
// assumes there is 0 liquidity so swaps are free
224253
fn move_price_to_tick(pool_key: PoolKey, tick: i129) {
225254
let tick_current = ekubo_core().get_pool_price(pool_key).tick;

0 commit comments

Comments
 (0)