Labels: Official Campaign | FWC26 GrantFox OSS Maybe Rewarded contract soroban api robustness bug
This is a smart-contract issue for the GrantFox FWC26 campaign. Return ContractError::NotFound from the stream/escrow getters so off-chain clients can distinguish "missing" from "contract error".
Requirements and Context
contracts/finchippay-contract/src/streams.rs:
get_stream returns Result<Stream, ContractError> with ContractError::NotFound — good.
get_claimable (≈ line 460) uses .expect("stream not found") — panics.
list_streams_by_payer uses .unwrap() on p_streams.get(i) and .unwrap() on the Stream lookup — panics on a stale index.
contracts/finchippay-contract/src/escrow.rs:
get_escrow returns Result<Escrow, ContractError> — good.
get_user_escrows silently returns an empty Vec for a missing key — acceptable but inconsistent.
The mix of Result, panic!, and silent-empty semantics across the read API forces SDK/indexer authors to special-case each call and makes a genuine NotFound indistinguishable from a contract bug. A stale StreamByPayer index entry (possible with the current silent-index-drop behavior, see batch-3 #62) would permanently panic list_streams_by_payer for that payer.
Objectives
- Convert
get_claimable to return Result<i128, ContractError> (or 0 on missing — pick one and document).
- Make
list_streams_by_payer skip (or return an error for) stale index entries instead of unwrap()-panicking.
- Add tests for missing IDs and stale indexes.
Suggested Execution
- Fork and branch:
git checkout -b fix/view-semantics.
- Patch
streams.rs getters; align escrow getters' semantics.
- Add tests; run
cargo fmt --check && cargo clippy -- -D warnings && cargo test.
Acceptance Criteria
Guidelines
- Keep SDK-facing names stable; document the chosen semantics in rustdoc.
Timeframe: 24 hours
Labels:
Official Campaign | FWC26GrantFox OSSMaybe RewardedcontractsorobanapirobustnessbugRequirements and Context
contracts/finchippay-contract/src/streams.rs:get_streamreturnsResult<Stream, ContractError>withContractError::NotFound— good.get_claimable(≈ line 460) uses.expect("stream not found")— panics.list_streams_by_payeruses.unwrap()onp_streams.get(i)and.unwrap()on theStreamlookup — panics on a stale index.contracts/finchippay-contract/src/escrow.rs:get_escrowreturnsResult<Escrow, ContractError>— good.get_user_escrowssilently returns an emptyVecfor a missing key — acceptable but inconsistent.The mix of
Result,panic!, and silent-empty semantics across the read API forces SDK/indexer authors to special-case each call and makes a genuineNotFoundindistinguishable from a contract bug. A staleStreamByPayerindex entry (possible with the current silent-index-drop behavior, see batch-3 #62) would permanently paniclist_streams_by_payerfor that payer.Objectives
get_claimableto returnResult<i128, ContractError>(or0on missing — pick one and document).list_streams_by_payerskip (or return an error for) stale index entries instead ofunwrap()-panicking.Suggested Execution
git checkout -b fix/view-semantics.streams.rsgetters; align escrow getters' semantics.cargo fmt --check && cargo clippy -- -D warnings && cargo test.Acceptance Criteria
cargo test+wasm32v1-nonebuild pass.Guidelines
Timeframe: 24 hours