Summary
prediction_market/src/lib.rs stores BetEntry records in persistent storage with fixed TTLs (lines ~1200-1240). These TTLs are not extended on the read path — neither get_payout nor get_market_state calls extend_ttl. If a market's resolution or payout window extends beyond the stored TTL, the BetEntry expires and the user's claimable funds are permanently lost.
The same issue affects RefundEntry in cancel_refund and PendingWithdrawal in the fee withdrawal flow.
Impact
- Permanent loss: an expired
BetEntry means the user cannot claim their winnings — the XLM is trapped in the contract with no retrieval path.
- Read-accelerated expiry: every call to
get_payout or get_market_state consumes ledger gas without bumping TTL, so frequent queries accelerate expiry.
- No keeper guarantee: if the automated keeper that calls
refresh_market_keys is offline, all near-expiry entries are lost.
- Market lifecycle mismatch: markets can have resolution windows of 60+ days, but TTLs are set to ~30 days at creation time.
Why it's hard
- The TTL must be set at write time, but the full claim window is not known until
resolve_market is called.
- Extending on read costs gas, which may make querying prohibitively expensive.
- A batch-refresh mechanism requires iterating an unbounded list of entries (gas DoS).
Fix
- Extend TTL in every read path that touches user-claimable state.
- Set TTLs relative to the maximum possible claim window (
resolution_time + 30 days), not the creation time.
- Add a public
bump_ttl(market_id, user) callable by anyone for entries close to expiry.
- Emit a
ClaimWindowExpired event so off-chain indexers can alert users.
Summary
prediction_market/src/lib.rsstoresBetEntryrecords in persistent storage with fixed TTLs (lines ~1200-1240). These TTLs are not extended on the read path — neitherget_payoutnorget_market_statecallsextend_ttl. If a market's resolution or payout window extends beyond the stored TTL, theBetEntryexpires and the user's claimable funds are permanently lost.The same issue affects
RefundEntryincancel_refundandPendingWithdrawalin the fee withdrawal flow.Impact
BetEntrymeans the user cannot claim their winnings — the XLM is trapped in the contract with no retrieval path.get_payoutorget_market_stateconsumes ledger gas without bumping TTL, so frequent queries accelerate expiry.refresh_market_keysis offline, all near-expiry entries are lost.Why it's hard
resolve_marketis called.Fix
resolution_time + 30 days), not the creation time.bump_ttl(market_id, user)callable by anyone for entries close to expiry.ClaimWindowExpiredevent so off-chain indexers can alert users.