Problem Statement / Feature Objective
Soroban contracts have a storage rent mechanism where persistent entries must periodically pay rent to remain accessible. The tariff oracle contract stores long-lived tariff configurations (rate schedules, tier definitions) that may remain unchanged for months or years. If these entries are not accessed frequently, their storage rent may expire, causing the contract to lose critical configuration data. The contract currently does not monitor or proactively extend the TTL of long-lived storage entries. A user could deliberately avoid accessing a tariff for a prolonged period, causing the tariff data to be evicted, and then claim that no valid tariff exists (defaulting to a lower rate). The objective is to implement a storage TTL management system that periodically extends TTLs for critical entries.
Technical Invariants & Bounds
Soroban storage TTL: persistent entries have a TTL of ~100 ledgers (~500 seconds) by default, but can be extended via env.storage().persistent().extend_ttl() up to a maximum of LEDGER_MAX = 10,000 ledgers (~50,000 seconds ~ 13.9 hours) or more depending on protocol version. The extension operation costs ~5,000 instructions per entry. Critical TariffOracle entries: DataKey::TariffConfig, DataKey::TierDefinitions, DataKey::OracleConfig — about 5 entries. The TTL extension function should be callable by anyone (permissionless) to prevent liveness issues. The extension target is TARGET_TTL = 5_000_000 (ledgers) — but maximum is protocol-defined; we should extend to the maximum allowed. A permissionless extend_ttl() function must emit an ExtendTTL event. The extension must only extend the TTL, never reduce it. The function must check that the caller pays a nominal fee (1 stroop) to prevent spam extensions.
Codebase Navigation Guide
Tariff configuration storage: contracts/tariff-oracle/src/storage.rs — DataKey variants for tariff configs. TTL management: likely no existing TTL extension functions. Would go in contracts/tariff-oracle/src/ttl_manager.rs. Similar pattern needed in contracts/resource-token/src/ttl_manager.rs for token balances and allowances. Soroban SDK: env.storage().persistent().extend_ttl(&key, ledger_delta) — research the exact API in contracts/common/src/storage_utils.rs.
Implementation Blueprint
Step 1: In contracts/common/src/storage_utils.rs, add pub fn extend_ttl(env: &Env, key: &DataKey, delta: u32) that calls env.storage().persistent().extend_ttl(key, delta). Step 2: In contracts/tariff-oracle/src/ttl_manager.rs, add pub fn refresh_ttl(env: Env) function that iterates over critical TariffOracle keys and extends each by TARGET_TTL_DELTA = 5_000_000 (or the protocol max). Protect with a fee transfer of 1 stroop. Step 3: Expose refresh_ttl() as a public contract function in lib.rs. Step 4: Similarly implement for contracts/resource-token/src/ttl_manager.rs extending TTL for balance entries (which are accessed frequently but may have sparse accounts). Step 5: Add a cron-like mechanism via a keepalive script in scripts/ttl_keeper.js that periodically calls refresh_ttl() on all deployed contracts. Step 6: Add tests: (a) extend_ttl on a stored entry increases its TTL, (b) calling refresh_ttl without paying fee fails, (c) extended entry persists beyond original TTL. Step 7: Run cargo test.
Problem Statement / Feature Objective
Soroban contracts have a storage rent mechanism where persistent entries must periodically pay rent to remain accessible. The tariff oracle contract stores long-lived tariff configurations (rate schedules, tier definitions) that may remain unchanged for months or years. If these entries are not accessed frequently, their storage rent may expire, causing the contract to lose critical configuration data. The contract currently does not monitor or proactively extend the TTL of long-lived storage entries. A user could deliberately avoid accessing a tariff for a prolonged period, causing the tariff data to be evicted, and then claim that no valid tariff exists (defaulting to a lower rate). The objective is to implement a storage TTL management system that periodically extends TTLs for critical entries.
Technical Invariants & Bounds
Soroban storage TTL: persistent entries have a TTL of ~100 ledgers (~500 seconds) by default, but can be extended via env.storage().persistent().extend_ttl() up to a maximum of LEDGER_MAX = 10,000 ledgers (~50,000 seconds ~ 13.9 hours) or more depending on protocol version. The extension operation costs ~5,000 instructions per entry. Critical TariffOracle entries: DataKey::TariffConfig, DataKey::TierDefinitions, DataKey::OracleConfig — about 5 entries. The TTL extension function should be callable by anyone (permissionless) to prevent liveness issues. The extension target is TARGET_TTL = 5_000_000 (ledgers) — but maximum is protocol-defined; we should extend to the maximum allowed. A permissionless extend_ttl() function must emit an ExtendTTL event. The extension must only extend the TTL, never reduce it. The function must check that the caller pays a nominal fee (1 stroop) to prevent spam extensions.
Codebase Navigation Guide
Tariff configuration storage: contracts/tariff-oracle/src/storage.rs — DataKey variants for tariff configs. TTL management: likely no existing TTL extension functions. Would go in contracts/tariff-oracle/src/ttl_manager.rs. Similar pattern needed in contracts/resource-token/src/ttl_manager.rs for token balances and allowances. Soroban SDK: env.storage().persistent().extend_ttl(&key, ledger_delta) — research the exact API in contracts/common/src/storage_utils.rs.
Implementation Blueprint
Step 1: In contracts/common/src/storage_utils.rs, add pub fn extend_ttl(env: &Env, key: &DataKey, delta: u32) that calls env.storage().persistent().extend_ttl(key, delta). Step 2: In contracts/tariff-oracle/src/ttl_manager.rs, add pub fn refresh_ttl(env: Env) function that iterates over critical TariffOracle keys and extends each by TARGET_TTL_DELTA = 5_000_000 (or the protocol max). Protect with a fee transfer of 1 stroop. Step 3: Expose refresh_ttl() as a public contract function in lib.rs. Step 4: Similarly implement for contracts/resource-token/src/ttl_manager.rs extending TTL for balance entries (which are accessed frequently but may have sparse accounts). Step 5: Add a cron-like mechanism via a keepalive script in scripts/ttl_keeper.js that periodically calls refresh_ttl() on all deployed contracts. Step 6: Add tests: (a) extend_ttl on a stored entry increases its TTL, (b) calling refresh_ttl without paying fee fails, (c) extended entry persists beyond original TTL. Step 7: Run cargo test.