Contract d8cae2fd3d848978e016147a6c85909b25ad3eb6550a85ba9ef549a9ae65cf9f

← Back to Index 📥 Download WASM

Meta

cliver 27.0.0#5a7c5fe76530bf4248477ac812fc757146b98cc4
rssdkver 26.1.0#175aa41306f383057a8cdfc84b68d931664fc34e
rsver 1.96.0

Instances

  • CBTTLO5LXNIOLU3UGH27AL3HCTLIZ5LNQBU4IWAOQCFV35ZKVMQNC4D5

Interface

Cumulative compound index since inception (RAY). 1.0 == RAY == no growth.

fn index(env: soroban_sdk::Env, asset: soroban_sdk::Address) -> i128

Replace the contract's wasm (admin-gated). Address and storage are kept.

fn upgrade(env: soroban_sdk::Env, new_wasm_hash: soroban_sdk::BytesN<32>)

Index value (RAY) at an arbitrary past timestamp t.

A pinned t (see [AprOracle::pin_index]) is returned directly and stays available forever; otherwise it is reconstructed from the observation buffer:

  • t newer than the latest observation -> the latest index (flat: the index only moves on updates, so this is the stale-read value);
  • t exactly on an observation -> that observation's index;
  • t between two observations -> geometric interpolation (constant-rate assumption between the surrounding snapshots);
  • t in the future, or older than the oldest retained observation and not pinned, or pool never updated -> panic.
fn index_at(env: soroban_sdk::Env, asset: soroban_sdk::Address, t: u64) -> i128

Register a new pool/asset and start its index at 1.0 (RAY) "from inception", seeding the source baseline in the same call.

obs_capacity sizes the per-pool observation ring buffer (must be >= 1).

Creation-only: an asset that already has state is rejected. Re-configure would reset the index to 1.0 and wipe the accrued history, so a fast-path (the governance deployer) may register a new pool's asset without a timelock but can never disturb a live one.

Seeding here rather than leaving it to the first update_state closes the window between the two: until a baseline exists the index cannot advance, so every bit of yield the source earned in that gap was dropped, and a term starting inside it would settle short. It also means the source is read under the admin's own call — a misconfigured or dead source fails at registration instead of surfacing as a pool that quietly never accrues.

fn configure(
    env: soroban_sdk::Env,
    asset: soroban_sdk::Address,
    obs_capacity: u32,
    source: Source,
)
fn get_admin(env: soroban_sdk::Env) -> soroban_sdk::Address

Full state for a pool (debugging / off-chain reads).

fn get_state(env: soroban_sdk::Env, asset: soroban_sdk::Address) -> AprState

Durably memoize I(asset, t) so it survives eviction from the observation buffer — a pure memoization of the oracle's own index series (nothing pool-specific). Permissionless and idempotent (first write wins); a no-op for a future t or one already pinned. The caller decides which timestamps to pin (e.g. a pool's term boundaries) and when.

Self-refreshing: if t is newer than the newest observation we would be extrapolating, and buffer_index_at would take its flat branch and freeze the last known index — silently dropping everything that accrued between it and t, for the life of the pin. We are the only component that can tell, so we pull the source first and let t land between two real observations. That costs one refresh, once, and only when the pin would otherwise be wrong: an already-pinned t returns above, and a t already bracketed needs nothing (a newer observation cannot change the pair surrounding it).

A t older than the oldest retained observation traps. Its history is gone

fn pin_index(env: soroban_sdk::Env, asset: soroban_sdk::Address, t: u64)

Transfer the admin role to new_admin (current admin only). The deploy hands the oracle to the governance timelock this way once its owner-driven pool configuration is done — the same handover the engine/vamm/lock-yield use.

fn set_admin(env: soroban_sdk::Env, new_admin: soroban_sdk::Address)

Accrued rate since pool inception as a RAY fraction (current_index - 1). e.g. 0.05 * RAY means 5% has accrued since the pool started.

fn accrued_ray(env: soroban_sdk::Env, asset: soroban_sdk::Address) -> i128

Storage/schema version, bumped by a post-upgrade migration when the layout changes.

fn get_version(env: soroban_sdk::Env) -> u32

Advance a Source::GrowthIndex pool by pulling its source index and deriving the rate from the index growth since the previous snapshot.

Deliberately permissionless (mirrors the public updateState in the Solidity implementation): the caller only chooses the moment of the update, the data comes from the configured source and cannot be forged.

fn update_state(env: soroban_sdk::Env, asset: soroban_sdk::Address)
fn __constructor(env: soroban_sdk::Env, admin: soroban_sdk::Address)

Accrued rate over [from, to] as a RAY fraction: index(to) / index(from) - 1.

fn accrued_between(
    env: soroban_sdk::Env,
    asset: soroban_sdk::Address,
    from: u64,
    to: u64,
) -> i128

Read one observation slot (debugging / off-chain reads).

fn get_observation(
    env: soroban_sdk::Env,
    asset: soroban_sdk::Address,
    slot: u32,
) -> Observation

Index growth I(to) / I(from) - 1 as a [Wad] (1e18): pool-agnostic, it only knows two timestamps. Returns (growth, valid) and never traps — valid == false when either endpoint is unavailable (unconfigured, future, or evicted-and-never-pinned), so the caller surfaces a clean error rather than every future read for the pool tripping once the buffer evicts the requested from. A pinned endpoint stays available indefinitely (see [AprOracle::pin_index]); the caller pins the timestamps it needs to outlive the buffer.

fn get_rate_from_to(
    env: soroban_sdk::Env,
    asset: soroban_sdk::Address,
    from: u64,
    to: u64,
) -> (Wad, bool)

Supply I(asset, t) by hand for a t the observation buffer no longer covers — the recovery path for a [AprOracle::pin_index] that traps, and the only way an index value ever enters this contract from outside its source.

Deliberately narrow, because it is the one place a human number can reach settlement:

  • only an evicted t — while t is still in the buffer, pin_index derives the real value and no judgement is needed, so the admin has no business there;
  • only once — an already-pinned t is rejected, so this can never rewrite a pin the permissionless path produced honestly, and first-write-wins still holds;
  • only within [RAY, I(oldest)] — the index starts at RAY and never decreases, so a t before the oldest retained observation had an index between inception and that observation's. Anything outside that range is provably wrong, whoever signed it.

Those bounds leave real discretion inside the interval, which is why this is admin-gated (the governance timelock) rather th

fn set_pinned_index(
    env: soroban_sdk::Env,
    asset: soroban_sdk::Address,
    t: u64,
    index_ray: i128,
)

Imports

WebAssembly Text (WAT) ▶