fix(contracts): preserve accrued vest time on stream top-up (closes #786)#961
fix(contracts): preserve accrued vest time on stream top-up (closes #786)#961samjay8 wants to merge 1 commit into
Conversation
|
heads up: main's ci was broken (the Backend CI and Backend Docker Image CI jobs) until the fixes in #969 and #974 just landed, so the red backend/docker checks on this pr are almost certainly stale, they ran against the broken main. please rebase to re-test against the now-green main: |
top_up_stream reset stream.last_update_time to the current ledger timestamp on every call. Since calculate_claimable uses last_update_time as the accrual anchor, this silently zeroed out any vested-but-unwithdrawn balance: a sender could top up a stream right before cancelling it to reclaim tokens the recipient had already earned. Drop the reassignment so prior accrued time carries through top-ups, including while the stream is paused (last_update_time must never be pushed past paused_at). Add regression coverage for the claimable amount surviving a top-up, a cancel-immediately-after-top-up payout, and the paused-stream case.
6057518 to
3839e8c
Compare
Hey boss @ogazboiz , all checks passes. Thank you. |
(closes #786)
Summary
top_up_streamwas unconditionally resettingstream.last_update_timeto thecurrent ledger timestamp on every call. Since
calculate_claimableuseslast_update_timeas the accrual anchor (elapsed = effective_now - last_update_time), this silently discarded any vested-but-unwithdrawnbalance the moment a top-up happened.
Concrete impact: for a 1000-token / 1000s stream (rate 1/s), if the recipient
had 900 unwithdrawn tokens vested at
t=900and the sender calledtop_up_stream(+100),last_update_timejumped to900, zeroingget_claimable_amount. A subsequentcancel_streamatt=901would then paythe recipient only
1token and refund1099to the sender — letting thesender reclaim ~899 tokens the recipient had already earned.
Fix
stream.last_update_time = env.ledger().timestamp()assignmentin
top_up_stream(contracts/stream_contract/src/lib.rs) so prior accruedtime is preserved across top-ups, including while a stream is paused
(
last_update_timeis never pushed pastpaused_at).Tests added
test_top_up_preserves_already_accrued_claimable— aftercreate_stream(1000, 1000s), advancing 900s and topping up by 100 keepsget_claimable_amountat 900 instead of dropping to 0.test_top_up_then_cancel_pays_pre_topup_accrued— topping up andimmediately cancelling pays the recipient exactly the pre-top-up accrued
amount.
test_top_up_while_paused_does_not_advance_last_update_time— topping up apaused stream does not push
last_update_timepastpaused_at, andclaimable amount still reflects only the time accrued before the pause.
Scope
wiring were left untouched.
contracts/stream_contract/src/lib.rs,contracts/stream_contract/src/test.rs.