Add CurrentTickAccount — an oracle-owned PDA (one per price source) that holds
the latest raw tick written by the price source and a timestamp. The price source
calls UpdateCurrentTick after each price-changing operation; anyone can then call
RecordTick (upcoming) to advance the PriceObservations accumulator without
requiring the price source to be present. PDA is derived from price_source_id
only (no window) since a single current tick serves all time windows.
Add price_to_tick(price: u128) -> i32 to twap_oracle_core: isqrt(price << 128)
-> sqrtPriceX96 -> get_tick_at_sqrt_ratio. The sqrtPriceX96 is clamped to
>= MIN_SQRT_RATIO so a zero/dust price maps to MIN_TICK rather than erroring.
Add a pure-integer integer_sqrt(U256) (bit-by-bit, no floating point): ruint's
root is gated behind its std feature and seeds with f64, neither available in
the guest. Uses wrapping_shr for the digit loop (checked_shr rejects the
intended lossy shifts).
Pull in uniswap_v3_math (for get_tick_at_sqrt_ratio) and alloy-primitives
(U256), with ruint pinned to =1.17.0 — 1.18 raised its MSRV to rustc 1.90,
above the risc0 guest toolchain's 1.88.
Adds the CreatePriceObservations instruction to the TWAP oracle program.
The instruction initialises a PriceObservations PDA for a given price
source account and time window, writing the initial tick and timestamp
as the first entry.
Key design decisions:
- Per-window accounts: each (price_source, window_duration) pair maps to
a distinct PriceObservations PDA. The window duration is baked into the
PDA seed so a single price source can support multiple TWAP windows
(24h, 7d, 30d) at independent sampling rates without sharing a buffer.
- window_duration not stored on struct: it is implicit in the PDA address.
Any reader that located the account already knows the window duration
used to derive it. Storing it would be redundant.
- Authorization is implicit: the PriceObservations PDA is derived from
the price source account ID, so is_authorized = true on the price source
proves the caller controls it without a redundant authority field.
- Impersonation is prevented by the PDA check: passing a controlled price
source with a victim's observations account ID fails immediately because
the computed PDA (from the attacker's source) does not match.
Closes#126