feat(contracts): add split_stream to divide an existing stream into two - #939
feat(contracts): add split_stream to divide an existing stream into two#939macsonfleek wants to merge 1 commit into
Conversation
Implements the split_stream function that allows a sender to split an active stream at the current vested point into two new streams. The original stream is closed and two child streams are created with the unvested remainder, inheriting the remaining duration. Key details: - split_ratio_bps must contain exactly 2 entries summing to 10000 bps - Already-claimed amounts are excluded from the split - Paused and already-canceled streams cannot be split - Emits StreamSplit event with original_id and new_ids Adds 16 tests covering basic split, uneven ratios, duration inheritance, claimable verification, token conservation, event emission, and error cases (invalid ratios, wrong sender, canceled/paused stream, etc.). Closes ritik4ever#671 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
|
@macsonfleek is attempting to deploy a commit to the ritik4ever's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@macsonfleek 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! 🚀 |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 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 |
Summary
Adds the
split_streamfunction to the Soroban smart contract, allowing a sender to divide one active stream into two new streams at the current vested point. This implements the feature requested in ritik4ever#671.What changes
contracts/src/lib.rsNew
StreamSplitevent struct — emitted when a stream is split:stream_id— the original stream that was closedactor— the sender who initiated the splittimestamp— ledger close timeoriginal_id— id of the original streamnew_ids— the two newly created stream idssplit_ratios_bps— the two basis-point ratios usedNew
split_stream(stream_id, sender, split_ratio_bps) -> (u64, u64)entry point:sender.require_auth()split_ratio_bpsmust have exactly 2 entriesvestedat current ledger time using the existingvested_amount()helpertotal_amount = vested,end_time = now,canceled = truetotal_amount - vested) is divided between two new streams according to the basis-point ratiomin_claim_interval_secondsnowto the originalend_time(remaining duration)StreamSplitevent under(symbol_short!("Stream"), symbol_short!("Split"))
Test | What it verifies -- | -- test_split_stream_basic | 50/50 split at 50% elapsed; original canceled, two 250-token children test_split_stream_uneven_ratios | 30/70 split → 150 and 350 test_split_stream_inherits_remaining_duration | Children start at split time, end at original end_time test_split_stream_claimable_after_split | Claimable amounts grow linearly in children test_split_stream_already_claimed_excluded | Pre-claim of 300 is excluded; unvested 500 splits correctly test_split_stream_token_conservation | Recipient receives exactly the unvested amount from both children test_split_stream_emits_event | StreamSplit event fields match expectations test_split_stream_ratios_not_10000_panics | 4000+4000=8000 panics with expected message test_split_stream_wrong_sender_panics | Non-sender caller panics test_split_stream_canceled_stream_panics | Cannot split a stream that was already canceled test_split_stream_at_end_of_stream_panics | Fully vested stream has nothing to split test_split_stream_zero_ratio_panics | 0+10000 panics (zero ratio rejected) test_split_stream_acceptance_split_at_50_percent_elapsed | Acceptance criterion from #671: split at 50%, verify both halves vest and claim correctly test_split_stream_at_start_no_vesting | Split at t=0 distributes 100% of total test_split_stream_paused_stream_panics | Paused streams cannot be split test_split_stream_wrong_ratio_count_panics | Only 1 ratio entry panicscontracts/src/test.rs— 16 new testsAcceptance Criteria Verification
How to test locally
How this fits with existing architecture
cancel(): read the stream, validate ownership, adjusttotal_amount/end_time, markcanceled = true, and emit an event.DataKey::Stream(u64)andDataKey::NextStreamIdare reused.TokenClientis reused to resolve native vs. non-native tokens, though no actual token transfers occur during the split (tokens remain in escrow).(topic1, topic2)tuple pattern as all other events in the contract.Closes ritik4ever#671
SummaryAdds the split_stream function to the Soroban smart contract, allowing a sender to divide one active stream into two new streams at the current vested point. This implements the feature requested in #671.
What changes
contracts/src/lib.rs
New StreamSplit event struct — emitted when a stream is split:
New split_stream(stream_id, sender, split_ratio_bps) -> (u64, u64) entry point:
contracts/src/test.rs — 16 new tests
Test What it verifies
test_split_stream_basic 50/50 split at 50% elapsed; original canceled, two 250-token children
test_split_stream_uneven_ratios 30/70 split → 150 and 350
test_split_stream_inherits_remaining_duration Children start at split time, end at original end_time
test_split_stream_claimable_after_split Claimable amounts grow linearly in children
test_split_stream_already_claimed_excluded Pre-claim of 300 is excluded; unvested 500 splits correctly
test_split_stream_token_conservation Recipient receives exactly the unvested amount from both children
test_split_stream_emits_event StreamSplit event fields match expectations
test_split_stream_ratios_not_10000_panics 4000+4000=8000 panics with expected message
test_split_stream_wrong_sender_panics Non-sender caller panics
test_split_stream_canceled_stream_panics Cannot split a stream that was already canceled
test_split_stream_at_end_of_stream_panics Fully vested stream has nothing to split
test_split_stream_zero_ratio_panics 0+10000 panics (zero ratio rejected)
test_split_stream_acceptance_split_at_50_percent_elapsed Acceptance criterion from #671: split at 50%, verify both halves vest and claim correctly
test_split_stream_at_start_no_vesting Split at t=0 distributes 100% of total
test_split_stream_paused_stream_panics Paused streams cannot be split
test_split_stream_wrong_ratio_count_panics Only 1 ratio entry panics
Acceptance Criteria Verification
How to test locally
cd contracts
cargo test
How this fits with existing architecture
Closes #671
Closes #
Checklist