Labels: Official Campaign | FWC26 GrantFox OSS Maybe Rewarded contract soroban receipts performance bug
This is a smart-contract issue for the GrantFox FWC26 campaign. Bound per-payer receipt counts so a single account cannot bloat storage and slow the TTL sweep.
Requirements and Context
contracts/finchippay-contract/src/lib.rs — mint_receipt (≈ line 2110):
let count: u32 = env
.storage()
.persistent()
.get(&DataKey::ReceiptCount(from.clone()))
.unwrap_or(0);
There is no MAX_USER_RECEIPTS cap (unlike MAX_USER_ESCROWS/MAX_USER_STREAMS). A single payer can mint an unbounded number of receipts; each mints two persistent entries (ReceiptRecord(from, count) + ReceiptByIndex(global)). Consequences:
- Storage bloat: one account can drive the contract's storage footprint (and ledger fees) far beyond any other user.
- TTL sweep slowdown:
bump_all_ttls walks every receipt via TotalReceiptCount; unbounded receipts make each sweep pass progressively more expensive and eventually exceed a single transaction's budget, so the sweep can no longer complete a class.
ReceiptCount is u32 — overflow at 4.29B mints (remote, but the pattern is already bounded elsewhere).
Objectives
- Add
MAX_USER_RECEIPTS (e.g. 1_000, consistent with the escrow/stream caps) and reject ReceiptCount(from) >= MAX_USER_RECEIPTS with a descriptive panic before minting.
- Document the cap in rustdoc and the README.
- Add a test: minting past the cap reverts; boundary value passes.
Suggested Execution
- Fork and branch:
git checkout -b fix/receipt-cap.
- Patch
mint_receipt in src/lib.rs.
- Add boundary tests; run
cargo fmt --check && cargo clippy -- -D warnings && cargo test.
Acceptance Criteria
Guidelines
- Pick the cap to be generous but bounded; document it as a contract-level constant.
Timeframe: 12 hours
Labels:
Official Campaign | FWC26GrantFox OSSMaybe RewardedcontractsorobanreceiptsperformancebugRequirements and Context
contracts/finchippay-contract/src/lib.rs—mint_receipt(≈ line 2110):There is no
MAX_USER_RECEIPTScap (unlikeMAX_USER_ESCROWS/MAX_USER_STREAMS). A single payer can mint an unbounded number of receipts; each mints two persistent entries (ReceiptRecord(from, count)+ReceiptByIndex(global)). Consequences:bump_all_ttlswalks every receipt viaTotalReceiptCount; unbounded receipts make each sweep pass progressively more expensive and eventually exceed a single transaction's budget, so the sweep can no longer complete a class.ReceiptCountisu32— overflow at 4.29B mints (remote, but the pattern is already bounded elsewhere).Objectives
MAX_USER_RECEIPTS(e.g. 1_000, consistent with the escrow/stream caps) and rejectReceiptCount(from) >= MAX_USER_RECEIPTSwith a descriptive panic before minting.Suggested Execution
git checkout -b fix/receipt-cap.mint_receiptinsrc/lib.rs.cargo fmt --check && cargo clippy -- -D warnings && cargo test.Acceptance Criteria
cargo test+wasm32v1-nonebuild pass.Guidelines
Timeframe: 12 hours