diff --git a/README.md b/README.md index 340ca21..22735d8 100644 --- a/README.md +++ b/README.md @@ -363,10 +363,11 @@ stepwise withdrawal, partial withdrawal and its over-request and non-positive guards, cliff gating, cancellation splits, the `locked` and `progress` views across a stream's life, the cliff and no-cliff schedules documented above, authorization requirements, invalid input, past and -boundary time-window rejection, backdated-start acceptance, id-counter -exhaustion at the `u64::MAX` boundary, rejection of the contract's own address -in each participant role, self-streams, the documented precedence between -validation groups, and double-withdraw and unknown-id guards. +boundary time-window rejection, backdated-start acceptance, multiple +recipients funded by one sender, id-counter exhaustion at the `u64::MAX` +boundary, rejection of the contract's own address in each participant role, +self-streams, the documented precedence between validation groups, and +double-withdraw and unknown-id guards. It also covers the storage and event behaviour described above: the order in which each entry point moves tokens and publishes its event, the silence of a diff --git a/contracts/stream/src/test.rs b/contracts/stream/src/test.rs index 58854a8..76ea6f1 100644 --- a/contracts/stream/src/test.rs +++ b/contracts/stream/src/test.rs @@ -232,6 +232,62 @@ fn create_stream_locks_funds_and_assigns_id() { assert!(!stream.cancelled); } +#[test] +fn one_sender_can_stream_to_multiple_recipients() { + let t = StreamTest::setup(1_500); + let second_recipient = Address::generate(&t.env); + t.set_time(100); + + let first_id = t.contract.create_stream( + &t.sender, + &t.recipient, + &t.token_address, + &500, + &100, + &1_100, + &100, + ); + let second_id = t.contract.create_stream( + &t.sender, + &second_recipient, + &t.token_address, + &700, + &100, + &1_100, + &100, + ); + + assert_eq!(first_id, 0); + assert_eq!(second_id, 1); + assert_eq!(t.contract.stream_count(), 2); + assert_eq!(t.token.balance(&t.sender), 300); + assert_eq!(t.token.balance(&t.contract.address), 1_200); + assert_eq!(t.token.balance(&t.recipient), 0); + assert_eq!(t.token.balance(&second_recipient), 0); + + let first = t.contract.get_stream(&first_id); + assert_eq!(first.sender, t.sender); + assert_eq!(first.recipient, t.recipient); + assert_eq!(first.total_amount, 500); + assert_eq!(first.withdrawn, 0); + + let second = t.contract.get_stream(&second_id); + assert_eq!(second.sender, t.sender); + assert_eq!(second.recipient, second_recipient); + assert_eq!(second.total_amount, 700); + assert_eq!(second.withdrawn, 0); + + t.set_time(600); + assert_eq!(t.contract.withdraw(&first_id), 250); + assert_eq!(t.contract.withdraw(&second_id), 350); + assert_eq!(t.token.balance(&t.recipient), 250); + assert_eq!(t.token.balance(&second_recipient), 350); + assert_eq!(t.token.balance(&t.contract.address), 600); + + assert_eq!(t.contract.get_stream(&first_id).withdrawn, 250); + assert_eq!(t.contract.get_stream(&second_id).withdrawn, 350); +} + #[test] fn withdraw_releases_vested_in_steps() { let t = StreamTest::setup(1_000);