From 72ce25475e91dcc7e05255cfe72f60e5640c169b Mon Sep 17 00:00:00 2001 From: Sobilo34 Date: Sun, 12 Apr 2026 17:24:25 +0100 Subject: [PATCH] fix(stream-manager): reject create-stream when rate-per-block would be zero --- contracts/stream-manager.clar | 3 +++ tests/stream-manager.test.ts | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/contracts/stream-manager.clar b/contracts/stream-manager.clar index a70adcb..b392553 100644 --- a/contracts/stream-manager.clar +++ b/contracts/stream-manager.clar @@ -212,6 +212,9 @@ (asserts! (not (var-get emergency-paused)) ERR-NOT-AUTHORIZED) (asserts! (> deposit-amount u0) ERR-INVALID-AMOUNT) (asserts! (> duration-blocks u0) ERR-INVALID-DURATION) + ;; Integer rate = (deposit * PRECISION) / duration must be >= 1, otherwise + ;; rate-per-block is 0 (no accrual) and top-up-stream divides by zero. + (asserts! (>= (* deposit-amount PRECISION) duration-blocks) ERR-INVALID-DURATION) (asserts! (>= start-block stacks-block-height) ERR-INVALID-START-TIME) (asserts! (not (is-eq recipient contract-caller)) ERR-INVALID-RECIPIENT) (asserts! (not (is-eq recipient (as-contract tx-sender))) ERR-INVALID-RECIPIENT) diff --git a/tests/stream-manager.test.ts b/tests/stream-manager.test.ts index 147689f..0f5d8ab 100644 --- a/tests/stream-manager.test.ts +++ b/tests/stream-manager.test.ts @@ -127,6 +127,21 @@ describe("StackStream - Stream Manager Contract", () => { expect(result.result).toBeErr(Cl.uint(301)); // ERR-INVALID-DURATION }); + it("should fail when duration exceeds deposit * PRECISION (zero rate-per-block)", () => { + const startBlock = getCurrentBlock() + 1; + // 1 * PRECISION / (PRECISION + 1) rounds down to 0 — must be rejected + const precision = 1_000_000_000_000n; + const result = createStream( + wallet1, + wallet2, + 1, + startBlock, + Number(precision + 1n) + ); + + expect(result.result).toBeErr(Cl.uint(301)); // ERR-INVALID-DURATION + }); + it("should fail with start block in the past", () => { // Mine some blocks first so we have room for a past block simnet.mineEmptyBlocks(5);