Skip to content

fix: add missing extend_ttl for persistent storage TTL management - #162

Merged
DioChuks merged 3 commits into
BuidlZone-Labs:mainfrom
Myart352:fix/142-storage-ttl-extension
Aug 4, 2026
Merged

fix: add missing extend_ttl for persistent storage TTL management#162
DioChuks merged 3 commits into
BuidlZone-Labs:mainfrom
Myart352:fix/142-storage-ttl-extension

Conversation

@Myart352

@Myart352 Myart352 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Closes #142

Summary

Contracts across the codebase write data to Soroban persistent storage but several critical storage operations were missing extend_ttl calls. Without periodic TTL extension, persistent entries become archived/expired, bricking contract reads and user payouts over time.

Changes

Ticket Contract (contracts/ticket/src/storage.rs)

  • Added extend_ttl to get_ticket, update_ticket, get_tickets_by_owner, get_tickets_by_event, get_recovery_key, set_recovery_key, and get_payments_contract

Ticket Contract (contracts/ticket/src/lib.rs)

  • Added extend_ttl to all persistent storage writes in mint_ticket (Ticket, OwnerTickets, EventTickets keys)
  • Added extend_ttl to write_next_ticket_id
  • Added extend_ttl to transfer_ticket, use_ticket, recover_ticket, and admin_transfer_ticket owner ticket storage updates

Event Contract (contracts/event/src/storage.rs)

  • Added extend_ttl to set_ticket_contract and set_payments_contract
  • Added extend_ttl on reads for get_ticket_contract and get_payments_contract

TTL Configuration

  • Threshold: 60×60×24×30 seconds (~30 days)
  • Extension: 60×60×24×30×2 seconds (~60 days)

Consistent with existing TTL constants (TTL_THRESHOLD, TTL_BUMP) already defined across all contracts.

Summary by CodeRabbit

  • Reliability

    • Improved persistence for event, ticket, contract, payment, reservation, recovery, and configuration records.
    • Frequently accessed information now remains available longer during normal use.
    • Event listings, ownership records, and ticket data are better retained when accessed.
    • Replay-protection records use dedicated retention settings.
  • Bug Fixes

    • Improved consistency when retrieving stored records and indexed lists.
    • Existing handling for missing optional values and unavailable records remains unchanged.
    • Improved cleanup of indexed ticket records in edge cases.

@drips-wave

drips-wave Bot commented Jul 29, 2026

Copy link
Copy Markdown

@Myart352 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

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Persistent storage accessors and writes now refresh TTLs across the event, factory, payments, and ticket contracts. Named ledger-based TTL constants replace inline durations. Existing missing-value errors, defaults, and optional-value behavior remain unchanged.

Changes

Persistent storage TTL management

Layer / File(s) Summary
Event storage TTL handling
contracts/event/src/storage.rs
Event records, administrators, contract links, reservations, privacy settings, and postponements now refresh TTLs. Shared constants replace inline durations.
Factory storage TTL handling
contracts/factory/src/storage.rs
Factory accessors refresh TTLs for administrators, event hashes, contract addresses, deployed events, and non-empty event lists.
Payments storage TTL handling
contracts/payments/src/storage.rs
Payments accessors refresh TTLs for statuses, configurations, contracts, administrators, tokens, payments, tickets, and the platform wallet. Dedicated TTL schedules apply to nonces and nullifiers.
Ticket storage and counter TTL handling
contracts/ticket/src/storage.rs, contracts/ticket/src/lib.rs
Ticket operations and storage accessors refresh TTLs for tickets, indexes, recovery keys, contract addresses, administrators, and the next-ticket-id entry. Owner-ticket removal also handles missing count entries.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: diochuks, unclebaffa

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers the issue and main code changes but omits most required sections, including storage impact, tests, acceptance sign-off, and checklist. Complete the template sections and document storage impact, test coverage, acceptance criteria, scope boundaries, security impact, and verification status.
Linked Issues check ⚠️ Warning The PR adds TTL handling across the listed contracts, but [#142] also requires expiration tests and documentation, and reported test failures prevent a no-regressions assessment. Add Soroban expiration simulation tests, update documentation, and resolve the reported formatting and test failures before merge.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: adding missing extend_ttl calls for persistent storage TTL management.
Out of Scope Changes check ✅ Passed All summarized changes support [#142] by extending TTLs for persistent keys across the event, payments, ticket, and factory contracts.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@contracts/ticket/src/storage.rs`:
- Around line 29-31: Replace the seconds-based TTL values used by
storage::extend_ttl with ledger-count constants, and route every ticket TTL
extension through those constants. Update contracts/ticket/src/storage.rs at
lines 29-31 and contracts/ticket/src/lib.rs at lines 42-46, including the inline
literals in lib.rs, while preserving the existing threshold and bump semantics.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8a60147c-6a87-4fe9-bdd6-94be9fafa73f

📥 Commits

Reviewing files that changed from the base of the PR and between 9225914 and b288e25.

📒 Files selected for processing (3)
  • contracts/event/src/storage.rs
  • contracts/ticket/src/lib.rs
  • contracts/ticket/src/storage.rs

Comment thread contracts/ticket/src/storage.rs Outdated
@Myart352
Myart352 force-pushed the fix/142-storage-ttl-extension branch from b288e25 to e008796 Compare July 30, 2026 09:17
@DioChuks

DioChuks commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

@Myart352 pls ensure to run cargo fmt --all to fix the failing CI checklist & also pls check your tests as they also failed to pass

@DioChuks

DioChuks commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
contracts/ticket/src/storage.rs (1)

93-105: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Refresh count entries before relying on stored index bounds.

get_event_tickets_count and get_owner_tickets_count read the count as Option<u64>, while non-zero entries are extended with storage().persistent().extend(&key, env.storage().get_ttl(&DataKey::TicketCount)...). If the count entry is deleted or unavailable, the index array bound no longer reflects existing data. remove_owner_ticket also deletes the membership before this read and can return with a zero count, potentially leaving stale index entries that later adds can overwrite. Read the count as Option<u64>, extend only existing counts, and handle missing counts with a fallback or corrective rebuild before using the indexes. Also applies to: 181-189, 193-205, 211-223

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@contracts/ticket/src/storage.rs` around lines 93 - 105, Update
get_event_tickets_count, get_owner_tickets_count, and the related removal paths
to read count entries as Option<u64>, refresh TTL only when a count exists, and
recover missing counts by rebuilding or otherwise correcting the index metadata
before using bounds. In remove_owner_ticket, avoid returning solely because the
count is missing or zero after deleting membership; ensure stale index entries
are removed and subsequent additions cannot overwrite them.

Source: MCP tools

🧹 Nitpick comments (1)
contracts/ticket/src/storage.rs (1)

193-223: 🚀 Performance & Scalability | 🔵 Trivial

Bound per-entry TTL refreshes in ticket-list queries.

Each returned index entry can trigger an extend_ttl call. The loop has no page or batch limit. Large owner or event lists can therefore consume significant ledger-write resources and refundable fees. Soroban transactions can fail when TTL extensions exceed resource or fee limits. (developers.stellar.org)

Add pagination or bounded batches, or validate the maximum list size with Soroban simulation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@contracts/ticket/src/storage.rs` around lines 193 - 223, Bound the number of
entries processed and TTL-refreshed in get_tickets_by_owner and
get_tickets_by_event by adding pagination or a fixed maximum batch size. Ensure
each query returns only the bounded page and does not call extend_ttl for
unbounded lists; use the existing count/index storage behavior for offsets and
preserve returned ticket ordering.

Source: MCP tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@contracts/event/src/storage.rs`:
- Around line 52-54: Replace the time-based TTL values passed to
Persistent::extend_ttl in contracts/event/src/storage.rs lines 52-54 and
234-236, contracts/factory/src/storage.rs lines 35-37, and
contracts/payments/src/storage.rs lines 120-122 with shared, tested ledger-based
TTL constants; define or reuse those constants consistently across all affected
storage accessors while preserving the existing threshold and bump behavior.
- Around line 275-283: Update get_event_privacy so it only calls
persistent().extend_ttl for the EventPrivacy key when persistent().get(&key)
returns Some; preserve PrivacyLevel::Standard as the fallback for missing
entries and return the retrieved or default privacy level.

In `@contracts/ticket/src/lib.rs`:
- Around line 377-384: Update the NextTicketId handling in mint_ticket to read
the persistent value as Option<u64>, call extend_ttl only when the key exists,
and use 1 as the fallback when it is absent. Preserve the existing counter
behavior for present values while preventing extend_ttl from running on a
missing key.

In `@contracts/ticket/src/storage.rs`:
- Around line 6-7: Update the TTL_THRESHOLD and TTL_BUMP constants in the
storage configuration to use ledger counts rather than seconds, after verifying
the repository’s target network and its maximum supported TTL. Ensure both
values remain within that network maximum, with TTL_BUMP not exceeding the
documented 3,110,400-ledger limit.

---

Outside diff comments:
In `@contracts/ticket/src/storage.rs`:
- Around line 93-105: Update get_event_tickets_count, get_owner_tickets_count,
and the related removal paths to read count entries as Option<u64>, refresh TTL
only when a count exists, and recover missing counts by rebuilding or otherwise
correcting the index metadata before using bounds. In remove_owner_ticket, avoid
returning solely because the count is missing or zero after deleting membership;
ensure stale index entries are removed and subsequent additions cannot overwrite
them.

---

Nitpick comments:
In `@contracts/ticket/src/storage.rs`:
- Around line 193-223: Bound the number of entries processed and TTL-refreshed
in get_tickets_by_owner and get_tickets_by_event by adding pagination or a fixed
maximum batch size. Ensure each query returns only the bounded page and does not
call extend_ttl for unbounded lists; use the existing count/index storage
behavior for offsets and preserve returned ticket ordering.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: aff8ef78-52a0-45ca-bace-c5bb79e2a4c3

📥 Commits

Reviewing files that changed from the base of the PR and between b288e25 and e008796.

📒 Files selected for processing (5)
  • contracts/event/src/storage.rs
  • contracts/factory/src/storage.rs
  • contracts/payments/src/storage.rs
  • contracts/ticket/src/lib.rs
  • contracts/ticket/src/storage.rs

Comment thread contracts/event/src/storage.rs
Comment thread contracts/event/src/storage.rs Outdated
Comment thread contracts/ticket/src/lib.rs Outdated
Comment thread contracts/ticket/src/storage.rs Outdated
- Replace seconds-style TTL constants with ledger counts (518,400 threshold /
  1,036,800 bump) that stay within the 3,110,400-ledger network maximum;
  previously TTL_BUMP (5,184,000) exceeded the max and would panic on mainnet.
- Route all inline extend_ttl literals through the shared constants in event,
  factory, payments, and ticket storage.
- get_event_privacy / read_next_ticket_id only extend TTL when the key exists
  (extend_ttl on a missing key panics with Error(Storage, MissingValue)).
- get_event_tickets_count / get_owner_tickets_count read Option<u64> and
  refresh TTL only when a count exists.
- remove_owner_ticket defensively cleans up its index slot when the count
  entry is missing so later adds cannot collide with stale entries.
…ocol max

- mint_ticket, transfer_ticket, use_ticket now extend the Ticket key TTL
  immediately after writing it, so a fresh ticket is not left at the default
  low TTL until its first read (matches the PR's write-path intent).
- Route ProcessedNonce/ProcessedNonceHash entries through 7/14-day ledger
  constants (120,960/241,920) instead of seconds-style literals.
- mark_nullifier_spent previously used 365-day seconds-style literals
  (31,536,000/63,072,000) that exceed the 3,110,400-ledger network maximum and
  would panic on mainnet; cap it at 60-day threshold / protocol-maximum bump.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@contracts/payments/src/storage.rs`:
- Around line 7-19: Add Soroban simulation test cases that verify ledger-TTL
behavior for the replay-protection storage constants now defined in the file.
Create test scenarios that advance the simulated ledger before and after each
threshold value (TTL_THRESHOLD, TTL_BUMP, NONCE_TTL_THRESHOLD, NONCE_TTL_BUMP,
NULLIFIER_TTL_THRESHOLD, NULLIFIER_TTL_BUMP). For each constant, include test
paths that verify existing entries remain valid, entries can be renewed before
expiry, and entries correctly fail verification after expiry to enforce replay
protection. Ensure the simulation ledger advancement covers the full lifecycle
of each TTL constant.

In `@contracts/ticket/src/storage.rs`:
- Around line 191-209: Update get_tickets_by_owner so each OwnerTicket(owner,
ticket_id) membership entry has its persistent TTL extended while reading the
owner’s tickets, alongside the existing count and index refreshes. Use the same
TTL_THRESHOLD and TTL_BUMP values and ensure the membership key remains
available for later cleanup in remove_owner_ticket.
- Around line 6-10: Add TTL expiry simulations in the ticket storage tests
around the existing ledger_sequence and storage-key test helpers. Advance
ledger_sequence() beyond TTL_THRESHOLD, verify each key type—Ticket,
OwnerTicket, OwnerTicketIndex, OwnerTicketsCount, and RecoveryKey—expires as
expected, then perform reads/writes to confirm the access refreshes its TTL and
prevents expiry; cover all listed key types before completion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a1fe660d-f419-400a-b1b3-be28bd7ee9c3

📥 Commits

Reviewing files that changed from the base of the PR and between e008796 and c957639.

📒 Files selected for processing (5)
  • contracts/event/src/storage.rs
  • contracts/factory/src/storage.rs
  • contracts/payments/src/storage.rs
  • contracts/ticket/src/lib.rs
  • contracts/ticket/src/storage.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • contracts/factory/src/storage.rs
  • contracts/event/src/storage.rs

Comment on lines +7 to +19
/// TTL refresh threshold in ledgers (~30 days at 5s/ledger).
const TTL_THRESHOLD: u32 = 518_400;
/// TTL extension target in ledgers (~60 days at 5s/ledger), well within the
/// network maximum of 3,110,400 ledgers.
const TTL_BUMP: u32 = 1_036_800;
const CURRENT_VERSION: u32 = 1;
/// Processed-nonce replay-protection entries: ~7-day/14-day ledger schedule.
const NONCE_TTL_THRESHOLD: u32 = 120_960; // ~7 days at 5s/ledger
const NONCE_TTL_BUMP: u32 = 241_920; // ~14 days at 5s/ledger
/// Spent-nullifier replay-protection entries: extend to the protocol maximum
/// (3,110,400 ledgers, ~180 days) since a replayed nullifier must never pass.
const NULLIFIER_TTL_THRESHOLD: u32 = 1_036_800; // ~60 days
const NULLIFIER_TTL_BUMP: u32 = 3_110_400; // protocol maximum TTL

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate TTL-focused Rust tests and their ledger-advance logic.
fd -t f -e rs . | rg '(^|/)(tests?|.*_test)\.rs$' || true
rg -n -C 5 'extend_ttl|TTL_THRESHOLD|TTL_BUMP|NONCE_TTL|NULLIFIER_TTL|ledger.*sequence|jump' --glob '*.rs' .

Repository: BuidlZone-Labs/zicket-contract

Length of output: 50387


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== payments storage outline =="
ast-grep outline contracts/payments/src/storage.rs || true

echo "== payments storage relevant constants/functions =="
sed -n '1,260p' contracts/payments/src/storage.rs

echo "== tests mentioning replay/nullifier/ttl in payments =="
rg -n -C 6 'mark_nullifier_spent|has_nullifier|nonce|replay|TTL_|ledger.*sequence|simulate|simulation' contracts/payments/src --glob '*.rs' || true

Repository: BuidlZone-Labs/zicket-contract

Length of output: 50387


Add ledger-TTL simulation coverage for replay-protection storage.

The current ledger advances cover dispute timeouts, not the storage TTLs. Add Soroban simulation cases that advance ledgers before and after TTL_THRESHOLD, TTL_BUMP, NONCE_TTL_THRESHOLD, NONCE_TTL_BUMP, NULLIFIER_TTL_THRESHOLD, and NULLIFIER_TTL_BUMP. Include existing entries, renewal before expiry, and replay after expiry.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@contracts/payments/src/storage.rs` around lines 7 - 19, Add Soroban
simulation test cases that verify ledger-TTL behavior for the replay-protection
storage constants now defined in the file. Create test scenarios that advance
the simulated ledger before and after each threshold value (TTL_THRESHOLD,
TTL_BUMP, NONCE_TTL_THRESHOLD, NONCE_TTL_BUMP, NULLIFIER_TTL_THRESHOLD,
NULLIFIER_TTL_BUMP). For each constant, include test paths that verify existing
entries remain valid, entries can be renewed before expiry, and entries
correctly fail verification after expiry to enforce replay protection. Ensure
the simulation ledger advancement covers the full lifecycle of each TTL
constant.

Comment on lines +6 to +10
/// TTL refresh threshold in ledgers (~30 days at 5s/ledger).
pub const TTL_THRESHOLD: u32 = 518_400;
/// TTL extension target in ledgers (~60 days at 5s/ledger), well within the
/// network maximum of 3,110,400 ledgers.
pub const TTL_BUMP: u32 = 1_036_800;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

fd -t f -e rs . | rg '(^|/)(tests?|.*_test)\.rs$' || true
rg -n -C 5 'TTL_THRESHOLD|TTL_BUMP|extend_ttl|NextTicketId|OwnerTicketIndex|RecoveryKey' --glob '*.rs' .

Repository: BuidlZone-Labs/zicket-contract

Length of output: 50387


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "## ticket test files"
fd -t f -e rs . contracts/ticket | sed -n '1,120p'

echo
echo "## ticket test references to TTL/expiry/expire"
rg -n -C 4 'TTL_THRESHOLD|TTL_BUMP|TTL|expire|expiration|ledger_sequence|sequence\(|extend_ttl|recovery' contracts/ticket -g '*.rs' | sed -n '1,240p'

echo
echo "## storage renewal call sites in contracts/ticket"
python3 - <<'PY'
from pathlib import Path
import re
for p in Path('contracts/ticket/src').glob('*.rs'):
    txt=p.read_text()
    if 'extend_ttl' in txt:
        print(f"\n# {p}")
        lines=txt.splitlines()
        for i,l in enumerate(lines,1):
            if 'extend_ttl' in l:
                start=max(1,i-3); end=min(len(lines),i+3)
                print(f"\n--- around {p}:{i} ---")
                for j in range(start,end+1):
                    print(f"{j}: {lines[j-1]}")
PY

Repository: BuidlZone-Labs/zicket-contract

Length of output: 25235


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "## contracts/ticket/src/test.rs outline/context"
wc -l contracts/ticket/src/test.rs
sed -n '1,260p' contracts/ticket/src/test.rs

echo
echo "## contracts/ticket/src/test.rs TTL/expiry/sequence references only"
rg -n -C 3 'TTL_THRESHOLD|TTL_BUMP|TTL|expire|expiration|ledger_sequence|sequence\(|extend_ttl|RecoveryKey|transfer|remove_owner_ticket|get_owner_ticket|get_tickets_by_owner|get_recovery_key' contracts/ticket/src/test.rs || true

echo
echo "## contracts/ticket/src/lib.rs relevant sections"
sed -n '360,420p' contracts/ticket/src/lib.rs
sed -n '480,560p' contracts/ticket/src/lib.rs
sed -n '680,770p' contracts/ticket/src/lib.rs

Repository: BuidlZone-Labs/zicket-contract

Length of output: 14163


Add TTL expiry simulations for ticket storage keys.

contracts/ticket/src/test.rs does not advance ledger_sequence() past TTL_THRESHOLD. Add coverage that reads/writes refresh Ticket, OwnerTicket, OwnerTicketIndex, OwnerTicketsCount, and RecoveryKey so the expiry objective is satisfied before merge.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@contracts/ticket/src/storage.rs` around lines 6 - 10, Add TTL expiry
simulations in the ticket storage tests around the existing ledger_sequence and
storage-key test helpers. Advance ledger_sequence() beyond TTL_THRESHOLD, verify
each key type—Ticket, OwnerTicket, OwnerTicketIndex, OwnerTicketsCount, and
RecoveryKey—expires as expected, then perform reads/writes to confirm the access
refreshes its TTL and prevents expiry; cover all listed key types before
completion.

Comment on lines +191 to +209
let count: Option<u64> = env.storage().persistent().get(&key);
if count.is_some() {
env.storage()
.persistent()
.extend_ttl(&key, TTL_THRESHOLD, TTL_BUMP);
}
count.unwrap_or(0)
}

/// Get the count of tickets owned by an address
pub fn get_owner_tickets_count(env: &Env, owner: &Address) -> u64 {
let key = DataKey::OwnerTicketsCount(owner.clone());
env.storage().persistent().get(&key).unwrap_or(0)
let count: Option<u64> = env.storage().persistent().get(&key);
if count.is_some() {
env.storage()
.persistent()
.extend_ttl(&key, TTL_THRESHOLD, TTL_BUMP);
}
count.unwrap_or(0)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the full owner-list and removal paths.
ast-grep outline contracts/ticket/src/storage.rs --items all --type function --match 'get_tickets_by_owner|remove_owner_ticket'
sed -n '95,269p' contracts/ticket/src/storage.rs
rg -n -C 8 'OwnerTicketIndex|OwnerTicketsCount|OwnerTicket\(' contracts/ticket/src/storage.rs

Repository: BuidlZone-Labs/zicket-contract

Length of output: 12958


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect where get_tickets_by_owner and remove_owner_ticket are called from.
rg -n -C 12 'get_tickets_by_owner|remove_owner_ticket|transfer|Transfer|transfer_contract' contracts/ticket/src -g '*.rs'

# Read the surrounding contract API section if not included above.
sed -n '260,460p' contracts/ticket/src/storage.rs 2>/dev/null || true
rg -n 'pub fn|fn ' contracts/ticket/src/storage.rs

Repository: BuidlZone-Labs/zicket-contract

Length of output: 50386


Extend the owner-list read TTL to OwnerTicket(owner, ticket_id).

get_tickets_by_owner refreshes the list count and index before reading each ticket_id, but not the membership entry that remove_owner_ticket later looks up in transfer_ticket, recovery, and admin transfers. If OwnerTicket(owner, ticket_id) expires, the index and count can stay alive and cleanup will skip removing OwnerTicketIndex(owner, idx), leaving the old owner with stale ownership metadata.

Also applies to: 220-222

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@contracts/ticket/src/storage.rs` around lines 191 - 209, Update
get_tickets_by_owner so each OwnerTicket(owner, ticket_id) membership entry has
its persistent TTL extended while reading the owner’s tickets, alongside the
existing count and index refreshes. Use the same TTL_THRESHOLD and TTL_BUMP
values and ensure the membership key remains available for later cleanup in
remove_owner_ticket.

@DioChuks
DioChuks merged commit 0dca806 into BuidlZone-Labs:main Aug 4, 2026
5 checks passed
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.

Missing Soroban Persistent Storage TTL Extension Management

2 participants