Overview
This batch includes three separate, contract-specific findings that persistent storage entries in escrow (Escrow records), stellar_send (Subscription records), and fee_collector (per-token lifetime totals) are never TTL-extended anywhere in this codebase, risking archival for exactly the long-lived data these features depend on. This issue is the umbrella testing-strategy gap underneath all three: no test anywhere in this workspace's four test suites (escrow/src/test.rs, fee_collector/src/test.rs, stellar_send/src/test.rs, token_bridge/src/test.rs) ever exercises persistent-storage TTL/archival behavior at all, despite soroban-sdk's testutils feature (already enabled for every contract in this workspace — Cargo.toml's per-crate [features] testutils = ["soroban-sdk/testutils"], confirmed in escrow/Cargo.toml:16, fee_collector/Cargo.toml:16, stellar_send/Cargo.toml:16, token_bridge/Cargo.toml:16) exposing the primitives needed to simulate it: ledger-state control over minimum persistent-entry TTL, and env.storage().persistent().extend_ttl(...)/.ttl() for inspecting and manipulating an entry's remaining lifetime directly in a test Env.
Every existing test in this workspace that advances time does so exclusively via env.ledger().set_timestamp(...) (e.g. escrow/src/test.rs:71, 131, 146; stellar_send/src/test.rs:682-683, 753) — which advances the ledger's timestamp for the purpose of evaluating time-based business logic like unlock_time/next_execution_time, but says nothing about, and doesn't interact with, the ledger sequence number progression that actually governs persistent-entry TTL expiry in Soroban's storage model. As a result, every test in this codebase that simulates "a long time has passed" for business-logic purposes implicitly assumes the underlying storage entries involved remain live and readable throughout — an assumption that has literally never been tested, and which the three companion TTL issues in this batch argue is false in production for exactly these long-dormancy scenarios.
This isn't a hypothetical process gap: it means that even after each of the three specific TTL bugs identified in this batch are fixed (by adding extend_ttl calls at the right points), there is still no regression test anywhere in this repository's four suites that would catch a future change silently removing or under-sizing one of those extend_ttl calls — nothing currently exercises the TTL dimension at all, so nothing would fail if it regressed.
Requirements
- Add a shared or per-contract test helper pattern for simulating persistent-entry TTL expiry in this test harness (e.g. a helper that advances the ledger sequence number far enough, combined with the relevant TTL testutils, to put a given entry past its live window) that the three specific TTL-bug fixes in this batch can build their own regression tests on top of, rather than each reinventing the pattern independently.
- At minimum, add one test per affected contract (
escrow, stellar_send, fee_collector) proving a specific persistent entry survives (post-fix) or fails (pre-fix, as a documented characterization) an extended dormancy period modeled with actual TTL-aware testutils, not just a timestamp jump.
- Document this pattern in whichever module ends up hosting the shared helper, so future contributors adding new persistent-storage-backed features in this workspace have a ready-made way to add TTL regression coverage rather than needing to rediscover the relevant testutils from scratch.
Acceptance Criteria
Additional Notes
Precise references: repo-wide grep -rn "extend_ttl\|bump\|ttl\|TTL" across escrow/src, fee_collector/src, stellar_send/src, token_bridge/src (non-test files) returns zero matches, and the same grep restricted to the four test.rs files also returns zero matches — confirming the gap exists at the testing infrastructure level, not just in the production code paths the three companion issues describe. escrow/Cargo.toml:16, fee_collector/Cargo.toml:16, stellar_send/Cargo.toml:16, token_bridge/Cargo.toml:16 each confirm the testutils feature (and therefore the relevant SDK TTL simulation APIs) is already available to every crate's test suite — this isn't blocked on adding a new dependency, just on writing the tests.
Relationship to the three specific TTL-bug issues in this batch (escrow Escrow records, stellar_send Subscription records, fee_collector per-token totals): those issues each include their own test/reproduction plan using TTL testutils as part of fixing that specific bug. This issue is the broader, standing observation that the category of test (TTL-expiry simulation) is entirely absent from this codebase's testing culture today, independent of any one bug — worth tracking on its own so the pattern doesn't quietly disappear again after those three specific fixes land, and so any future long-lived persistent record added to this workspace (in token_bridge, or a fifth contract, or a new field on an existing struct) inherits a known, established way to verify its TTL handling rather than each new feature rediscovering the gap from scratch.
Test/reproduction plan: this issue's own deliverable is the test plan described in each of the three companion TTL issues, consolidated: for escrow, extend escrow/src/test.rs per that issue's plan; for stellar_send, extend stellar_send/src/test.rs per that issue's plan; for fee_collector, extend fee_collector/src/test.rs per that issue's plan — landed together (or in close succession) so the shared helper pattern this issue asks for actually gets reused three times rather than written once and only used in whichever fix happens to land first.
Overview
This batch includes three separate, contract-specific findings that persistent storage entries in
escrow(Escrow records),stellar_send(Subscription records), andfee_collector(per-token lifetime totals) are never TTL-extended anywhere in this codebase, risking archival for exactly the long-lived data these features depend on. This issue is the umbrella testing-strategy gap underneath all three: no test anywhere in this workspace's four test suites (escrow/src/test.rs,fee_collector/src/test.rs,stellar_send/src/test.rs,token_bridge/src/test.rs) ever exercises persistent-storage TTL/archival behavior at all, despitesoroban-sdk'stestutilsfeature (already enabled for every contract in this workspace —Cargo.toml's per-crate[features] testutils = ["soroban-sdk/testutils"], confirmed inescrow/Cargo.toml:16,fee_collector/Cargo.toml:16,stellar_send/Cargo.toml:16,token_bridge/Cargo.toml:16) exposing the primitives needed to simulate it: ledger-state control over minimum persistent-entry TTL, andenv.storage().persistent().extend_ttl(...)/.ttl()for inspecting and manipulating an entry's remaining lifetime directly in a testEnv.Every existing test in this workspace that advances time does so exclusively via
env.ledger().set_timestamp(...)(e.g.escrow/src/test.rs:71, 131, 146;stellar_send/src/test.rs:682-683, 753) — which advances the ledger's timestamp for the purpose of evaluating time-based business logic likeunlock_time/next_execution_time, but says nothing about, and doesn't interact with, the ledger sequence number progression that actually governs persistent-entry TTL expiry in Soroban's storage model. As a result, every test in this codebase that simulates "a long time has passed" for business-logic purposes implicitly assumes the underlying storage entries involved remain live and readable throughout — an assumption that has literally never been tested, and which the three companion TTL issues in this batch argue is false in production for exactly these long-dormancy scenarios.This isn't a hypothetical process gap: it means that even after each of the three specific TTL bugs identified in this batch are fixed (by adding
extend_ttlcalls at the right points), there is still no regression test anywhere in this repository's four suites that would catch a future change silently removing or under-sizing one of thoseextend_ttlcalls — nothing currently exercises the TTL dimension at all, so nothing would fail if it regressed.Requirements
escrow,stellar_send,fee_collector) proving a specific persistent entry survives (post-fix) or fails (pre-fix, as a documented characterization) an extended dormancy period modeled with actual TTL-aware testutils, not just a timestamp jump.Acceptance Criteria
escrow,fee_collector,stellar_send) exercises actual TTL/archival simulation viasoroban-sdktestutils, not just a timestamp jump.extend_ttlcall added to fix the three specific issues in this batch would be caught by at least one of these new tests failing.Additional Notes
Precise references: repo-wide
grep -rn "extend_ttl\|bump\|ttl\|TTL"acrossescrow/src,fee_collector/src,stellar_send/src,token_bridge/src(non-test files) returns zero matches, and the same grep restricted to the fourtest.rsfiles also returns zero matches — confirming the gap exists at the testing infrastructure level, not just in the production code paths the three companion issues describe.escrow/Cargo.toml:16,fee_collector/Cargo.toml:16,stellar_send/Cargo.toml:16,token_bridge/Cargo.toml:16each confirm thetestutilsfeature (and therefore the relevant SDK TTL simulation APIs) is already available to every crate's test suite — this isn't blocked on adding a new dependency, just on writing the tests.Relationship to the three specific TTL-bug issues in this batch (
escrowEscrow records,stellar_sendSubscription records,fee_collectorper-token totals): those issues each include their own test/reproduction plan using TTL testutils as part of fixing that specific bug. This issue is the broader, standing observation that the category of test (TTL-expiry simulation) is entirely absent from this codebase's testing culture today, independent of any one bug — worth tracking on its own so the pattern doesn't quietly disappear again after those three specific fixes land, and so any future long-lived persistent record added to this workspace (intoken_bridge, or a fifth contract, or a new field on an existing struct) inherits a known, established way to verify its TTL handling rather than each new feature rediscovering the gap from scratch.Test/reproduction plan: this issue's own deliverable is the test plan described in each of the three companion TTL issues, consolidated: for
escrow, extendescrow/src/test.rsper that issue's plan; forstellar_send, extendstellar_send/src/test.rsper that issue's plan; forfee_collector, extendfee_collector/src/test.rsper that issue's plan — landed together (or in close succession) so the shared helper pattern this issue asks for actually gets reused three times rather than written once and only used in whichever fix happens to land first.