Skip to content

Fix #54: Add storage TTL lifecycle management (read-bumps, keeper refresh, migration) - #127

Merged
Muyideen-js merged 3 commits into
SPulse-Org:mainfrom
funds0033-cmyk:fix/issue-54-storage-ttl-lifecycle
Aug 20, 2026
Merged

Fix #54: Add storage TTL lifecycle management (read-bumps, keeper refresh, migration)#127
Muyideen-js merged 3 commits into
SPulse-Org:mainfrom
funds0033-cmyk:fix/issue-54-storage-ttl-lifecycle

Conversation

@funds0033-cmyk

@funds0033-cmyk funds0033-cmyk commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Closes #54

Summary

This PR introduces a complete TTL lifecycle for every prediction-market storage entry required to recover user funds.

Markets, bettor indexes, bets, payouts, refund records, and related user liabilities are refreshed as one logical lifecycle rather than independently.

The design includes automatic touch-based refresh, permissionless maintenance, expiry visibility, and an upgrade migration path for existing state.

Storage Lifecycle Invariant

For every market that still has a possible user claim or refund, all storage required to execute that claim/refund must remain alive together:

  • Market(market_id)
  • bettor index;
  • Bet(market_id, user)
  • Payout(market_id, user)
  • refundable/cancellation state;
  • claim/refund completion state.

It must never be possible for the market metadata to remain available while the user's financial entitlement silently expires.

Shared TTL Helper

Introduce an internal lifecycle helper that refreshes all keys touched by a market operation using the same TTL policy.

Every write or financially relevant read calls the helper.

Automatic Refresh Paths

TTL is refreshed on:

  • create_market
  • place_bet
  • resolve_market
  • cancel_market
  • claim
  • cancel_refund
  • other functions that read or update outstanding user financial state.

For claim/refund operations, the required keys are refreshed before further processing whenever they are still available.

Permissionless Keeper

refresh_market_ttl(market_id) refreshes the complete market lifecycle, not just the Market key.

Using the bounded bettor index, it refreshes all required per-user entries for that market.

If one transaction cannot safely refresh the entire bounded set, expose paginated maintenance:

refresh_market_ttl(market_id, start, limit)

with deterministic progress.

Anyone may call it and pay the storage-extension cost.

TTL Visibility

Expose lifecycle information sufficient for operators/indexers to know when maintenance is needed:

  • market TTL;
  • minimum TTL across required market entries;
  • whether refresh is complete;
  • next bettor-index cursor if paginated.

A keeper should not have to guess which dependent key is closest to expiry.

Migration

After upgrade, provide a bounded migration/refresh function over all existing known markets:

refresh_markets(start_id, limit)

For each market it also schedules/executes refresh of its associated bettor/bet/payout/refund keys.

Migration progress is persistent and resumable.

Already unavailable state is explicitly detected and reported rather than silently treated as healthy.

Where the platform supports restoration of archived entries, document and provide the required restoration workflow before TTL refresh.

Lifecycle Policy

Document who is responsible for keeping unresolved liabilities alive:

  • normal user interaction automatically refreshes state;
  • permissionless keepers can refresh inactive markets;
  • production operations monitor the minimum TTL;
  • resolved/cancelled markets remain maintained while unclaimed payouts/refunds exist.

Storage may be allowed to expire only after every financial liability for that market has been settled.

Tests

Cover:

  • active bet keys refreshed;
  • claim refreshes required state;
  • cancel_refund refreshes required state;
  • market TTL cannot be healthy while dependent payout TTL is left near expiry after a refresh;
  • permissionless keeper refreshes Market + Bet + Payout + index entries;
  • multiple-user market refresh works;
  • paginated refresh resumes correctly;
  • migration refreshes existing entries;
  • missing/expired dependent key is reported;
  • fully settled market can follow the documented cleanup/expiry policy;
  • unrelated markets are unaffected.

Acceptance Criteria

  • Every key required for claims/refunds has lifecycle management.
  • cancel_refund is covered.
  • Refreshing a market refreshes dependent financial-state keys.
  • Permissionless keeper exists.
  • Refresh can be bounded/paginated.
  • Operators can observe lifecycle/TTL status.
  • Existing entries have a migration path.
  • Already unavailable entries have a documented restoration/error path.
  • State is not intentionally allowed to expire while user liabilities remain.
  • Referral/leaderboard related TTL changes are tested independently where included.
  • Workspace tests pass.

Result

User funds no longer depend on independently expiring storage keys with no maintenance policy. Every outstanding market liability has an explicit, observable, and maintainable storage lifecycle until settlement.

funds0033-cmyk and others added 3 commits August 18, 2026 23:02
… permissionless keeper, and a migration path.

Claim/resolve/cancel now refresh market/bet/payout keys; anyone can call refresh_market_ttl / refresh_markets / get_market_ttl. Referral counters and leaderboard stats get write-time bumps plus matching keeper entrypoints so idle entries cannot silently vanish.

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

[CRITICAL] Persistent storage TTLs can expire before claims/refunds — user funds permanently locked

2 participants