Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions contracts/stream_contract/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,15 +329,21 @@ impl StreamContract {
let now = env.ledger().timestamp();
let accrued_amount = Self::calculate_claimable(&stream, now);

// Refund only the unspent balance minus accrued tokens (accrued tokens stay for recipient)
let token_client = token::Client::new(&env, &stream.token_address);
let contract_address = env.current_contract_address();

// Settle recipient immediately with all final claimable amount at cancellation.
if accrued_amount > 0 {
token_client.transfer(&contract_address, &stream.recipient, &accrued_amount);
stream.withdrawn_amount = stream.withdrawn_amount.saturating_add(accrued_amount);
}

// Refund remaining unspent balance after recipient settlement.
let refunded_amount = stream
.deposited_amount
.saturating_sub(stream.withdrawn_amount)
.saturating_sub(accrued_amount);
.saturating_sub(stream.withdrawn_amount);

if refunded_amount > 0 {
let token_client = token::Client::new(&env, &stream.token_address);
let contract_address = env.current_contract_address();
token_client.transfer(&contract_address, &sender, &refunded_amount);
}

Expand Down
20 changes: 13 additions & 7 deletions contracts/stream_contract/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -872,20 +872,23 @@ fn test_cancel_stream_refunds_sender() {
l.timestamp += 300;
});

// Cancel stream: should refund 700 tokens to sender (1000 - 300 accrued)
// Cancel stream: should pay 300 to recipient and refund 700 to sender
client.cancel_stream(&sender, &stream_id);

let sender_balance_after = token_client.balance(&sender);
let contract_balance_after = token_client.balance(&contract_id);
let recipient_balance_after = token_client.balance(&recipient);

// Sender should receive 700 tokens back
assert_eq!(sender_balance_after - sender_balance_before, 700);
// Contract should have 300 tokens remaining (for recipient to withdraw)
assert_eq!(contract_balance_after, 300);
// Recipient should receive final claimable 300 immediately
assert_eq!(recipient_balance_after, 300);
// Contract should be fully drained
assert_eq!(contract_balance_after, 0);

let stream = client.get_stream(&stream_id).unwrap();
assert!(!stream.is_active);
assert_eq!(stream.withdrawn_amount, 0); // Recipient hasn't withdrawn yet
assert_eq!(stream.withdrawn_amount, 300);
}

#[test]
Expand Down Expand Up @@ -921,14 +924,17 @@ fn test_cancel_stream_after_partial_withdrawal() {
l.timestamp += 100;
});

// Cancel stream: should refund 700 tokens to sender (1000 - 200 withdrawn - 100 accrued)
// Cancel stream: should pay final 100 to recipient and refund 700 to sender
client.cancel_stream(&sender, &stream_id);

let sender_balance_after = token_client.balance(&sender);
let contract_balance_after = token_client.balance(&contract_id);
let recipient_balance_after = token_client.balance(&recipient);

// Sender should receive 700 tokens back
assert_eq!(sender_balance_after - sender_balance_before, 700);
// Contract should have 100 tokens remaining (for recipient to withdraw)
assert_eq!(contract_balance_after, 100);
// Recipient should now hold total 300 (200 withdrawn earlier + 100 settled at cancel)
assert_eq!(recipient_balance_after, 300);
// Contract should be fully drained
assert_eq!(contract_balance_after, 0);
}
Loading