Skip to content

feat: [contract] define TTL policy and move per-user state to persistent storage - #1704

Open
CathyZaks wants to merge 2 commits into
Junirezz:mainfrom
CathyZaks:fix/issue-1636-contract-define-a-ttl-policy-and-move-pe
Open

CathyZaks wants to merge 2 commits into
Junirezz:mainfrom
CathyZaks:fix/issue-1636-contract-define-a-ttl-policy-and-move-pe

Conversation

@CathyZaks

Copy link
Copy Markdown
Contributor

Header

Problem

In the YieldVault smart contract, no storage TTL was extended anywhere in the vault lifecycle, and all per-user state entries were stored in instance storage. Because instance storage entries share a single lifetime threshold and bump window across the entire contract, storing per-user keys (ShareBalance, UserDeposit, LastDepositTime, PendingWithdrawal, WithdrawalQueueEntry, CheckpointTotals, UserCheckpoint, and UserBalanceAt) in instance storage introduces severe scalability and availability risks:

  1. As the number of depositors grows, instance storage size expands indefinitely, exceeding Soroban instance storage size limits and inflating gas fees.
  2. Inactive users or low-frequency users risk losing access to ledger entries if TTL expires, or causing entire contract instance failure if instance rent is exhausted.
  3. Without automated read/write TTL extension routines, vault entries could expire without deterministic lifecycle guarantees.

Solution

  1. Written TTL Policy:
    • Authored docs/storage-ttl-policy.md defining standard Soroban storage tiers, lifetime thresholds, bump amounts, and rationale.
    • Updated docs/storage-layout-reference.md aligning contract storage documentation with the new classification.
    • Defined parameters:
      • Instance Storage: INSTANCE_LIFETIME_THRESHOLD = 17_280 ledgers (~1 day), INSTANCE_BUMP_AMOUNT = 518_400 ledgers (~30 days). Used strictly for core contract singleton state.
      • Persistent Storage: PERSISTENT_LIFETIME_THRESHOLD = 120_960 ledgers (~7 days), PERSISTENT_BUMP_AMOUNT = 518_400 ledgers (~30 days). Used for unbounded per-user and historical checkpoint data.
  2. Contract Storage Refactoring (contracts/vault/src/lib.rs):
    • Reclassified 8 storage keys to persistent storage: ShareBalance(Address), UserDeposit(Address), LastDepositTime(Address), PendingWithdrawal(Address), WithdrawalQueueEntry(u64), CheckpointTotals(u32), UserCheckpoint(Address), and UserBalanceAt(UserBalanceKey).
    • Introduced dedicated internal helper routines with automatic TTL extensions on read and write:
      • get_share_balance / set_share_balance
      • get_user_deposit / set_user_deposit
      • get_last_deposit_time / set_last_deposit_time
      • get_pending_withdrawal / set_pending_withdrawal / remove_pending_withdrawal
      • get_withdrawal_queue_entry / set_withdrawal_queue_entry / remove_withdrawal_queue_entry
      • get_checkpoint_totals / set_checkpoint_totals
      • get_user_checkpoint / set_user_checkpoint
      • get_user_balance_at / set_user_balance_at
      • bump_instance_ttl (called during state-modifying operations)
    • Updated all vault operations (deposit, gasless_deposit, batch_deposit, withdraw, execute_withdrawal, do_withdraw, enqueue_withdrawal_for_liquidity, process_withdrawal_queue, create_checkpoint, snapshot_user_balance) to use the persistent helpers and bump instance TTL.
  3. Storage Version 4 Migration (migrate_storage):
    • Bumped STORAGE_VERSION from 3 to 4.
    • Added v4 migration block to run_storage_migration migrating queue entries head..tail, checkpoint totals 1..=nonce, and staged migration users (mig_usr) from instance to persistent storage with TTL extension.
    • Provided public administrative entry points stage_migration_users and migrate_user_storage.
  4. Testing (contracts/vault/src/proxy_tests.rs):
    • Updated storage version checks to expect version 4.
    • Added test_ttl_policy_and_entries_survive_past_default_ttl: advances ledger sequence by 10,000 (well past default 4,096 TTL) and verifies user entries survive and read/write operations succeed with TTL renewed.
    • Added test_migrate_storage_moves_instance_held_user_keys: seeds instance storage with legacy user keys, stages users, runs migrate_storage(&4), and verifies all keys are migrated to persistent storage and deleted from instance storage.

Changes by File

docs/storage-ttl-policy.md

  • Created comprehensive storage TTL policy document specifying instance vs persistent storage tiers, ledger threshold and bump constants, key classification, and migration guidelines.

docs/storage-layout-reference.md

  • Updated storage layout documentation reflecting the reclassification of per-user keys from instance to persistent storage, noting the 518,400 ledger bump amount and 120,960 threshold.

contracts/vault/src/lib.rs

  • Bumped STORAGE_VERSION constant from 3 to 4.
  • Defined TTL constants INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT, PERSISTENT_LIFETIME_THRESHOLD, PERSISTENT_BUMP_AMOUNT.
  • Added internal persistent storage accessors and mutators with automatic extend_persistent_ttl calls.
  • Added public getters: pending_withdrawal, user_checkpoint, withdrawal_queue_entry, last_deposit_time.
  • Added administrative migration functions: stage_migration_users, migrate_user_storage.
  • Updated all deposit, withdrawal, queue, and checkpoint execution paths to use persistent accessors and call bump_instance_ttl.
  • Updated run_storage_migration to execute v4 migration of queue entries, checkpoint totals, and staged users from instance to persistent storage.

contracts/vault/src/proxy_tests.rs

  • Updated version assertion in test_storage_migration_version_guard, test_upgrade_storage_version_checkpoint, test_upgrade_storage_version_remains_monotonic_after_migration, test_migrate_storage_version_checkpoint, and test_migrate_storage_downgrade_rejected to storage version 4.
  • Added test_ttl_policy_and_entries_survive_past_default_ttl testing ledger advance past default TTL and persistence survival.
  • Added test_migrate_storage_moves_instance_held_user_keys testing that migrate_storage successfully transfers legacy instance-held user keys to persistent storage and deletes them from instance storage.

Regression Tests

Test Name File Description Status
test_proxy_initialization_guard contracts/vault/src/proxy_tests.rs Verifies double initialization guard remains active Passing
test_storage_migration_version_guard contracts/vault/src/proxy_tests.rs Verifies downgrade rejection and version 4 migration guard Passing
test_upgrade_storage_version_checkpoint contracts/vault/src/proxy_tests.rs Verifies upgrade preserves storage version 4 Passing
test_upgrade_storage_version_remains_monotonic_after_migration contracts/vault/src/proxy_tests.rs Verifies idempotent migration to version 4 Passing
test_migrate_storage_version_checkpoint contracts/vault/src/proxy_tests.rs Verifies idempotent migration checkpoint at version 4 Passing
test_migrate_storage_downgrade_rejected contracts/vault/src/proxy_tests.rs Verifies version downgrade below 4 is rejected Passing
test_ttl_policy_and_entries_survive_past_default_ttl contracts/vault/src/proxy_tests.rs Advances ledger sequence past default TTL and verifies persistent per-user entries survive New / Passing
test_migrate_storage_moves_instance_held_user_keys contracts/vault/src/proxy_tests.rs Migrates seeded legacy instance user keys to persistent storage via migrate_storage(&4) New / Passing

Testing

Verification output from git diff --stat:

 contracts/vault/src/lib.rs         | 551 +++++++++++++++++++++++++++++--------
 contracts/vault/src/proxy_tests.rs | 246 ++++++++++++++++-
 docs/storage-layout-reference.md   |  17 +-
 docs/storage-ttl-policy.md         |  91 ++++++
 4 files changed, 782 insertions(+), 123 deletions(-)

Verification of local commit:

commit 72df7c9b60ea826197546da7efba24f0b641ae1e
Author: cathyzaks <zakaricatherine01@gmail.com>
Date:   Sat Oct 17 11:17:05 2026 +0100

    feat: [contract] define TTL policy and move per-user state to persistent storage

Notes for Reviewers

  • All per-user storage entries now use Soroban persistent() storage with 30-day bump amounts (PERSISTENT_BUMP_AMOUNT = 518_400) and 7-day renewal thresholds (PERSISTENT_LIFETIME_THRESHOLD = 120_960).
  • Singleton protocol configuration remains in instance() storage with 30-day bump amount and 1-day threshold (INSTANCE_LIFETIME_THRESHOLD = 17_280), with bump_instance_ttl invoked across all mutating transactions.
  • Pre-existing compilation issues on main (in contracts/share-price-math/src/rounding.rs:8:1, contracts/vault/src/fuzz_math.rs, contracts/vault/src/timelock.rs, contracts/vault/src/strategy_registration.rs, contracts/vault/tests/operational_safety_tests.rs, and contracts/vault/tests/reentrancy_cei_test.rs) have been documented in BLOCKED.md and left untouched in accordance with strict scope discipline (Rule 54).

Closes #1636

@drips-wave

drips-wave Bot commented Oct 20, 2026

Copy link
Copy Markdown

@CathyZaks Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[contract] Define a TTL policy and move per-user state from instance to persistent storage

1 participant