Repository navigation
test: add contract unit tests for all stream state transitions (#594) - #660
Conversation
…4ever#594) Add comprehensive contract unit tests covering: - Full lifecycle: create -> claim -> complete - Full lifecycle: create -> cancel with refund verification - Full lifecycle: create -> pause -> resume -> claim -> complete - Edge case: cancel after full claim (zero refund path) - Edge case: pause/resume with wrong sender (auth checks) - Edge case: pause on canceled stream - Edge case: resume on non-paused stream - Edge case: over-claim after partial claim - Edge case: clawback with zero amount - Edge case: multiple pause/resume cycles - Edge case: stream with past start time - Edge case: zero duration after cancel at start (vested_amount zero-duration branch) Also includes: - Rust toolchain pinning for reproducible builds - Dependency update (ethnum 1.5.2 -> 1.5.3) for Rust 1.97 compatibility Branch coverage: 91.10% (target: >=85%) All 95 tests passing (6 new + 89 existing) Closes ritik4ever#594
|
@ciscokwiz is attempting to deploy a commit to the ritik4ever's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@ciscokwiz 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! 🚀 |
📝 WalkthroughWalkthroughThe PR pins the contract Rust toolchain, adds comprehensive stream lifecycle and edge-case tests, and updates snapshots for ledger state, diagnostics, events, initialization storage, token flows, pause/resume behavior, cancellation, clawback, and split streams. ChangesStream lifecycle coverage
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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/rust-toolchain.toml`:
- Around line 1-3: Update the contract CI setup before the cargo steps so it
installs and uses the toolchain pinned by contracts/rust-toolchain.toml
(nightly-2024-12-01), rather than stable. Ensure this applies with the
workflow’s contracts working directory before cargo fmt, clippy, audit, test,
and build commands.
🪄 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: 67d0d6c6-7673-457e-a664-a42b617c367e
⛔ Files ignored due to path filters (9)
contracts/Cargo.lockis excluded by!**/*.lockcontracts/src/snapshots/stellar_stream__test__clawback_executed_event.snapis excluded by!**/*.snapcontracts/src/snapshots/stellar_stream__test__create_split_stream_success.snapis excluded by!**/*.snapcontracts/src/snapshots/stellar_stream__test__pause_resume_snapshot_lifecycle-2.snapis excluded by!**/*.snapcontracts/src/snapshots/stellar_stream__test__pause_resume_snapshot_lifecycle-3.snapis excluded by!**/*.snapcontracts/src/snapshots/stellar_stream__test__pause_resume_snapshot_lifecycle.snapis excluded by!**/*.snapcontracts/src/snapshots/stellar_stream__test__stream_cancel_after_partial_claim.snapis excluded by!**/*.snapcontracts/src/snapshots/stellar_stream__test__stream_created_no_metadata.snapis excluded by!**/*.snapcontracts/src/snapshots/stellar_stream__test__stream_created_with_metadata.snapis excluded by!**/*.snap
📒 Files selected for processing (86)
contracts/rust-toolchain.tomlcontracts/src/test.rscontracts/test_snapshots/run_all_benchmarks.1.jsoncontracts/test_snapshots/test/test_cancel_after_full_claim_zero_refund.1.jsoncontracts/test_snapshots/test/test_cancel_after_partial_claim_full_lifecycle.1.jsoncontracts/test_snapshots/test/test_cancel_after_partial_claim_refunds_correct_amount_and_preserves_token_conservation.1.jsoncontracts/test_snapshots/test/test_cancel_before_start_claim_attempt_panics.1.jsoncontracts/test_snapshots/test/test_cancel_before_start_recipient_claimable_is_zero.1.jsoncontracts/test_snapshots/test/test_cancel_before_start_refunds_full_amount_to_sender.1.jsoncontracts/test_snapshots/test/test_cancel_fails_with_wrong_sender.1.jsoncontracts/test_snapshots/test/test_cancel_idempotent_double_cancel_does_not_panic.1.jsoncontracts/test_snapshots/test/test_cancel_marks_stream_as_canceled.1.jsoncontracts/test_snapshots/test/test_cancel_recipient_cannot_claim_beyond_vested_at_cancel_time.1.jsoncontracts/test_snapshots/test/test_cancel_refunds_unclaimed_to_sender.1.jsoncontracts/test_snapshots/test/test_claim_after_stream_fully_completed.1.jsoncontracts/test_snapshots/test/test_claim_before_stream_start_panics.1.jsoncontracts/test_snapshots/test/test_claim_cannot_double_claim.1.jsoncontracts/test_snapshots/test/test_claim_cannot_exceed_vested_amount.1.jsoncontracts/test_snapshots/test/test_claim_fails_with_wrong_recipient.1.jsoncontracts/test_snapshots/test/test_claim_on_canceled_stream.1.jsoncontracts/test_snapshots/test/test_claim_partial_then_full.1.jsoncontracts/test_snapshots/test/test_claim_rapid_succession_prevents_double_pay.1.jsoncontracts/test_snapshots/test/test_claim_transfers_tokens_to_recipient.1.jsoncontracts/test_snapshots/test/test_claim_zero_amount_panics.1.jsoncontracts/test_snapshots/test/test_claimable_accounts_for_already_claimed.1.jsoncontracts/test_snapshots/test/test_claimable_after_end_time.1.jsoncontracts/test_snapshots/test/test_claimable_after_stream_end_caps_at_total.1.jsoncontracts/test_snapshots/test/test_claimable_at_end_time.1.jsoncontracts/test_snapshots/test/test_claimable_at_start_time.1.jsoncontracts/test_snapshots/test/test_claimable_before_stream_start_returns_zero.1.jsoncontracts/test_snapshots/test/test_claimable_during_stream_is_linear.1.jsoncontracts/test_snapshots/test/test_claimable_while_paused_clamped.1.jsoncontracts/test_snapshots/test/test_clawback_after_canceled_stream_transfers_to_admin.1.jsoncontracts/test_snapshots/test/test_clawback_before_initialize_panics.1.jsoncontracts/test_snapshots/test/test_clawback_caps_at_unclaimed_vested.1.jsoncontracts/test_snapshots/test/test_clawback_emits_event.1.jsoncontracts/test_snapshots/test/test_clawback_non_admin_panics.1.jsoncontracts/test_snapshots/test/test_clawback_reduces_recipient_claimable.1.jsoncontracts/test_snapshots/test/test_clawback_token_conservation.1.jsoncontracts/test_snapshots/test/test_clawback_transfers_to_admin.1.jsoncontracts/test_snapshots/test/test_clawback_zero_amount_panics.1.jsoncontracts/test_snapshots/test/test_cliff_vesting_blocks_claim_before_cliff.1.jsoncontracts/test_snapshots/test/test_create_split_stream_creates_child_streams_and_links.1.jsoncontracts/test_snapshots/test/test_create_split_stream_success.1.jsoncontracts/test_snapshots/test/test_create_stream_fails_with_invalid_token_address.1.jsoncontracts/test_snapshots/test/test_create_with_past_start_time.1.jsoncontracts/test_snapshots/test/test_event_emissions.1.jsoncontracts/test_snapshots/test/test_full_lifecycle_create_cancel.1.jsoncontracts/test_snapshots/test/test_full_lifecycle_create_claim_complete.1.jsoncontracts/test_snapshots/test/test_full_lifecycle_pause_resume_claim.1.jsoncontracts/test_snapshots/test/test_get_claimable_batch_single_and_multi.1.jsoncontracts/test_snapshots/test/test_get_next_stream_id.1.jsoncontracts/test_snapshots/test/test_get_split_children_on_nonexistent_stream_returns_empty.1.jsoncontracts/test_snapshots/test/test_get_split_children_on_parent_stream_returns_child_ids_and_child_to_parent_mapping.1.jsoncontracts/test_snapshots/test/test_get_split_children_on_regular_stream_returns_empty.1.jsoncontracts/test_snapshots/test/test_initialize_cannot_be_called_twice.1.jsoncontracts/test_snapshots/test/test_initialize_guard_clawback_rejected_before_init.1.jsoncontracts/test_snapshots/test/test_initialize_guard_different_admin_cannot_replace.1.jsoncontracts/test_snapshots/test/test_initialize_guard_double_init_panics.1.jsoncontracts/test_snapshots/test/test_initialize_guard_stores_admin_on_first_call.1.jsoncontracts/test_snapshots/test/test_initialize_stores_admin.1.jsoncontracts/test_snapshots/test/test_metadata_multiple_labels_round_trip.1.jsoncontracts/test_snapshots/test/test_multiple_pause_resume_cycles.1.jsoncontracts/test_snapshots/test/test_native_xlm_streaming.1.jsoncontracts/test_snapshots/test/test_no_id_collisions_across_mixed_stream_creations.1.jsoncontracts/test_snapshots/test/test_over_claim_after_partial_claim.1.jsoncontracts/test_snapshots/test/test_pause_already_paused_stream_panics.1.jsoncontracts/test_snapshots/test/test_pause_at_start_time_vested_is_zero.1.jsoncontracts/test_snapshots/test/test_pause_canceled_stream_panics.1.jsoncontracts/test_snapshots/test/test_pause_resume_freezes_vesting_and_extends_end_time.1.jsoncontracts/test_snapshots/test/test_pause_resume_normal_flow.1.jsoncontracts/test_snapshots/test/test_pause_resume_snapshot_lifecycle.1.jsoncontracts/test_snapshots/test/test_pause_wrong_sender_panics.1.jsoncontracts/test_snapshots/test/test_resume_non_paused_stream_panics.1.jsoncontracts/test_snapshots/test/test_resume_stream_panic_on_missing_timestamp.1.jsoncontracts/test_snapshots/test/test_resume_wrong_sender_panics.1.jsoncontracts/test_snapshots/test/test_split_stream_child_ids_are_contiguous_and_match_mapping.1.jsoncontracts/test_snapshots/test/test_split_stream_claim_and_cancel_work_per_substream.1.jsoncontracts/test_snapshots/test/test_stream_created_large_metadata_no_budget_panic.1.jsoncontracts/test_snapshots/test/test_stream_created_with_metadata_snapshot.1.jsoncontracts/test_snapshots/test/test_stream_id_auto_increment_across_split_stream.1.jsoncontracts/test_snapshots/test/test_transfer_stream_claim_by_new_recipient.1.jsoncontracts/test_snapshots/test/test_transfer_stream_updates_recipient.1.jsoncontracts/test_snapshots/test/test_vested_constant_while_paused.1.jsoncontracts/test_snapshots/test/test_vesting_resumes_after_resume.1.jsoncontracts/test_snapshots/test/test_zero_duration_after_cancel_at_start.1.json
💤 Files with no reviewable changes (42)
- contracts/test_snapshots/test/test_claimable_at_start_time.1.json
- contracts/test_snapshots/test/test_cancel_before_start_recipient_claimable_is_zero.1.json
- contracts/test_snapshots/test/test_claimable_accounts_for_already_claimed.1.json
- contracts/test_snapshots/test/test_cancel_before_start_refunds_full_amount_to_sender.1.json
- contracts/test_snapshots/test/test_claimable_after_end_time.1.json
- contracts/test_snapshots/test/test_cancel_recipient_cannot_claim_beyond_vested_at_cancel_time.1.json
- contracts/test_snapshots/test/test_claim_cannot_exceed_vested_amount.1.json
- contracts/test_snapshots/test/test_cancel_fails_with_wrong_sender.1.json
- contracts/test_snapshots/test/test_claim_cannot_double_claim.1.json
- contracts/test_snapshots/test/test_claimable_before_stream_start_returns_zero.1.json
- contracts/test_snapshots/test/test_cancel_marks_stream_as_canceled.1.json
- contracts/test_snapshots/test/test_get_next_stream_id.1.json
- contracts/test_snapshots/test/test_claim_rapid_succession_prevents_double_pay.1.json
- contracts/test_snapshots/test/test_event_emissions.1.json
- contracts/test_snapshots/test/test_claimable_at_end_time.1.json
- contracts/test_snapshots/test/test_claimable_after_stream_end_caps_at_total.1.json
- contracts/test_snapshots/test/test_claim_before_stream_start_panics.1.json
- contracts/test_snapshots/test/test_get_claimable_batch_single_and_multi.1.json
- contracts/test_snapshots/test/test_cancel_before_start_claim_attempt_panics.1.json
- contracts/test_snapshots/test/test_initialize_guard_clawback_rejected_before_init.1.json
- contracts/test_snapshots/test/test_claim_after_stream_fully_completed.1.json
- contracts/test_snapshots/test/test_claim_fails_with_wrong_recipient.1.json
- contracts/test_snapshots/test/test_stream_created_large_metadata_no_budget_panic.1.json
- contracts/test_snapshots/test/test_clawback_before_initialize_panics.1.json
- contracts/test_snapshots/test/test_claim_on_canceled_stream.1.json
- contracts/test_snapshots/test/test_claimable_during_stream_is_linear.1.json
- contracts/test_snapshots/test/test_no_id_collisions_across_mixed_stream_creations.1.json
- contracts/test_snapshots/test/test_cancel_refunds_unclaimed_to_sender.1.json
- contracts/test_snapshots/test/test_cliff_vesting_blocks_claim_before_cliff.1.json
- contracts/test_snapshots/test/test_transfer_stream_updates_recipient.1.json
- contracts/test_snapshots/test/test_claim_zero_amount_panics.1.json
- contracts/test_snapshots/test/test_create_split_stream_creates_child_streams_and_links.1.json
- contracts/test_snapshots/test/test_claim_partial_then_full.1.json
- contracts/test_snapshots/test/test_cancel_idempotent_double_cancel_does_not_panic.1.json
- contracts/test_snapshots/test/test_transfer_stream_claim_by_new_recipient.1.json
- contracts/test_snapshots/test/test_split_stream_claim_and_cancel_work_per_substream.1.json
- contracts/test_snapshots/test/test_metadata_multiple_labels_round_trip.1.json
- contracts/test_snapshots/test/test_stream_created_with_metadata_snapshot.1.json
- contracts/test_snapshots/test/test_create_split_stream_success.1.json
- contracts/test_snapshots/test/test_split_stream_child_ids_are_contiguous_and_match_mapping.1.json
- contracts/test_snapshots/test/test_stream_id_auto_increment_across_split_stream.1.json
- contracts/test_snapshots/test/test_claim_transfers_tokens_to_recipient.1.json
| [toolchain] | ||
| channel = "nightly-2024-12-01" | ||
| targets = ["wasm32-unknown-unknown"] |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Root toolchain:"
rustup show active-toolchain
echo "Contract toolchain:"
(
cd contracts
rustup show active-toolchain
)
echo "Workflow cargo working directories:"
rg -n -C2 'cargo (test|build|clippy)|working-directory:' .github/workflows/contract-ci.ymlRepository: ritik4ever/stellar-stream
Length of output: 206
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Files:"
git ls-files | sed -n '1,120p'
echo
echo "Contract toolchain:"
if [ -f contracts/rust-toolchain.toml ]; then cat -n contracts/rust-toolchain.toml; fi
echo
echo "Workflow excerpt:"
if [ -f .github/workflows/contract-ci.yml ]; then cat -n .github/workflows/contract-ci.yml | sed -n '1,220p'; else echo "missing"; fi
echo
echo "Search for rust-toolchain / working-directory / cargo commands in workflows and contracts:"
rg -n 'rust-toolchain|working-directory:|cargo (test|build|clippy|doc|check)|rustup|nightly|stable|toolchain' .github contracts -S || trueRepository: ritik4ever/stellar-stream
Length of output: 9552
🌐 Web query:
cargo doc rust-toolchain configuration TOML nightly features -Z build-std warning rustdoc
💡 Result:
Using -Z build-std with cargo doc is an experimental feature primarily used to rebuild the standard library from source [1][2]. To use it, you must have the rust-src component installed via rustup [1][3]. Key points regarding your query: 1. Configuration: build-std is a nightly-only feature [1]. While there are ongoing RFC proposals to introduce stable configuration options like build-std.when = "always" in rust-toolchain.toml [4][5], these are currently part of future development efforts [2][5]. Presently, -Z build-std and -Z build-std-features must be passed as command-line flags to cargo invocations [1][6]. 2. rustdoc Warnings: When using -Z build-std, cargo doc compiles the standard library as part of your crate graph [1]. Consequently, rustdoc may surface warnings originating from the standard library or its dependencies, which can be disruptive if you use deny(warnings) [7]. There is no specialized flag to suppress only rustdoc warnings from the standard library; these are treated as part of your project's compilation process [1]. 3. Documentation Links: A known limitation of using -Z build-std with cargo doc is that it may fail to generate correct cross-links to the standard library documentation [8]. Because the standard library is being treated as a local dependency rather than an external crate, it may not automatically resolve to the standard online documentation (e.g., doc.rust-lang.org) [8]. To mitigate warning-related issues in documentation builds, ensure your project is clean of its own warnings, as rustdoc will process the standard library crates similarly to other local dependencies [7]. If you are strictly using nightly for this feature, monitor the wg-cargo-std-aware repository for updates regarding build-std maturity and stability [1][2].
Citations:
- 1: https://doc.rust-lang.org/cargo/reference/unstable.html
- 2: https://rust-lang.github.io/rust-project-goals/2025h1/build-std.html
- 3: https://rust-lang.github.io/rustup/concepts/components.html
- 4: https://rust-lang.github.io/rfcs/3874-build-std-always.html
- 5: build-std: always rust-lang/rfcs#3874
- 6: https://rust-lang.github.io/rfcs/3873-build-std-context.html
- 7: cargo doc --no-deps shows rustdoc warnings in dependencies rust-lang/rust#59367
- 8:
cargo doc -Zbuild-stddoesn't generate links to the standard library rust-lang/wg-cargo-std-aware#88
🌐 Web query:
actions dtolnay rust-toolchain action stable toolchain-file .toolchain-version
💡 Result:
The dtolnay/rust-toolchain GitHub Action is designed for concise, manual specification of a Rust toolchain [1][2]. It does not natively parse or automatically detect rust-toolchain or rust-toolchain.toml files to configure its installation behavior [1][2][3]. If you wish to use a rust-toolchain or rust-toolchain.toml file in your repository, you have two primary approaches: 1. Use standard rustup commands: Since GitHub Actions runners have rustup pre-installed, you can simply run the command rustup toolchain install in your workflow [3]. This will automatically detect and install the toolchain (including components and targets) specified in a local rust-toolchain or rust-toolchain.toml file [4][3]. 2. Use a different action: If you require a GitHub Action that specifically supports automatic discovery and installation of toolchain files, consider using the actions-rust-lang/setup-rust-toolchain action [5]. This action is explicitly designed to detect rust-toolchain or rust-toolchain.toml files in the root of the repository and install the environment specified within them [5]. The dtolnay/rust-toolchain action requires the toolchain to be specified via its toolchain input or the action revision (@rev) [1][2]. If you provide an explicit toolchain input, it will override any other default behavior [1][2].
Citations:
- 1: https://github.com/dtolnay/rust-toolchain
- 2: https://github.com/dtolnay/rust-toolchain/blob/master/README.md
- 3: rust-toolchain.toml support dtolnay/rust-toolchain#133
- 4: https://rust-lang.github.io/rustup/overrides.html?highlight=rust-toolchain.toml
- 5: https://github.com/actions-rust-lang/setup-rust-toolchain
Install the pinned contract nightly toolchain before running contract steps.
.github/workflows/contract-ci.yml runs all cargo commands from contracts, but the Rust action still installs stable, so contracts/rust-toolchain.toml’s nightly-2024-12-01 pin is ignored by CI. Install the toolchain from the local file or pass it explicitly, matching the workflow’s working-directory: contracts before cargo fmt/clippy/audit/test/build.
🤖 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/rust-toolchain.toml` around lines 1 - 3, Update the contract CI
setup before the cargo steps so it installs and uses the toolchain pinned by
contracts/rust-toolchain.toml (nightly-2024-12-01), rather than stable. Ensure
this applies with the workflow’s contracts working directory before cargo fmt,
clippy, audit, test, and build commands.
|
@ritik4ever Please review and merge |
|
@ritik4ever please merge |
Summary
Adds comprehensive contract unit tests covering all stream state transitions and edge cases, achieving ≥85% branch coverage as required.
Test Cases
Lifecycle Tests
test_full_lifecycle_create_claim_complete): Full stream lifecycle from creation through partial claim, time advance to completion, and final claim verificationtest_full_lifecycle_create_cancel): Create stream, advance to partial vesting, cancel, verify sender refund and recipient claimabletest_full_lifecycle_pause_resume_claim): Full pause/resume cycle with claim and completion verificationEdge Cases
test_zero_duration_after_cancel_at_start): Cancel exactly at start_time causingtotal_duration = 0invested_amounttest_create_with_past_start_time): Stream created withstart_timebefore current ledger timetest_over_claim_after_partial_claim): Claiming more than available after partial claimBranch Coverage Gaps Filled
cancel: Sender refund == 0 path (cancel after full claim)pause_stream: Sender mismatch, canceled streamresume_stream: Sender mismatch, non-paused streamclawback: Zero amount validationCoverage Report
Branch coverage: 91.10% (target: ≥85%)
Additional Changes
rust-toolchain.toml: Pins nightly-2024-12-01 for reproducible buildsCargo.lock: Update ethnum 1.5.2 → 1.5.3 for Rust 1.97 compatibilityVerification
cargo test✓cargo llvm-cov --lib --html✓Closes #594
Summary by CodeRabbit
New Features
Bug Fixes
Tests