Engineering a Real-Time Token Streaming Protocol on Bitcoin L2.
A decentralized token streaming protocol built on the Stacks blockchain using Clarity 3 smart contracts. Enables continuous, second-by-second crypto payroll and vesting with pause/resume state machines, cancel refunds, and cryptographic ECDSA signature verification.
Replacing Discrete Payouts with Continuous Asset Flows.
Traditional payroll and token vesting rely on discrete lump-sum disbursements — bi-weekly paychecks or monthly cliff unlocks. The Stacks Token Streaming Protocol converts asset transfers into continuous linear streams on Bitcoin Layer 2. Recipients accumulate funds block-by-block and can withdraw withdrawable tokens at any time, while senders retain refund rights over unaccrued capital.
The Vulnerabilities of Legacy Crypto Payroll & Vesting.
Employees and contractors are exposed to market price drops while waiting for monthly vesting cliffs or delayed payroll processing.
If a contractor stops delivering work mid-month, senders have no programmatic way to pause or cancel unaccrued capital without escrow third parties.
Stream modifications (such as changing payment rates or recipient addresses) often lack cryptographic proof of mutual consent.
Clarity 3 Data Model & Tuple Structure.
Every stream is stored in the streams map keyed by an incrementing uint stream ID:
;; Clarity Data Map Definition in contracts/stream.clar
(define-map streams
uint ;; stream-id
{
sender: principal,
recipient: principal,
balance: uint,
withdrawn-balance: uint,
payment-per-block: uint,
timeframe: (tuple (start-block uint) (stop-block uint)),
status: (response uint uint),
pause-block: uint,
total-paused-blocks: uint
}
)Contract Public Interface & Invariant Guardrails.
Initialize a new token payment stream with sender, recipient, amount, and time boundaries.
Allow recipient to withdraw linearly accrued tokens at any point during active stream period.
Halt token accumulation during stream disputes or pauses, recording pause block timestamp.
Re-activate a paused stream, adjusting end time boundaries dynamically.
Cancel stream, disbursing accrued tokens to recipient and returning remaining balance to sender.
Add additional tokens to an active stream to extend its duration or payout rate.
Modify stream parameters subject to dual-party ECDSA signature verification.
Calculate real-time withdrawable balance based on block height progression.
Error Code Mapping
Triggered when a principal attempts an action restricted to sender or recipient.
Raised when ECDSA signature verification fails over parameter update hash.
Prevents sender from executing refund before stop-block expiry.
Raised on lookup of non-existent stream ID key in data map.
Blocks duplicate pause calls on an already paused stream state.
Blocks withdrawal or parameter mutation on a cancelled stream.
Linear Accrual Math & Balance Implementation.
At current block height stacks-block-height, the withdrawable balance for a recipient is calculated deterministically inside the smart contract:
;; Actual Clarity Balance Function from stream.clar
(define-read-only (balance-of (stream-id uint) (user principal))
(let (
(stream (unwrap! (map-get? streams stream-id) u0))
(start-block (get start-block (get timeframe stream)))
(stop-block (get stop-block (get timeframe stream)))
(current-block stacks-block-height)
(payment-per-block (get payment-per-block stream))
)
(if (is-eq user (get recipient stream))
;; Recipient accrued balance calculation
(if (<= current-block start-block)
u0
(if (>= current-block stop-block)
(- (get balance stream) (get withdrawn-balance stream))
(- (* (- current-block start-block) payment-per-block) (get withdrawn-balance stream))
)
)
u0
)
)
)Cryptographic ECDSA Signature Verification.
To modify parameters on an active stream (update-details), the caller must present a 65-byte ECDSA signature over the SHA-256 hash digest of the proposed new parameters:
;; SHA-256 Hash Digest & ECDSA Signature Verification
(define-read-only (hash-stream (stream-id uint) (payment-per-block uint) (timeframe (tuple (start-block uint) (stop-block uint))))
(sha256 (unwrap-panic (to-consensus-buff? {stream-id: stream-id, payment-per-block: payment-per-block, timeframe: timeframe})))
)
(define-read-only (validate-signature (hash (buff 32)) (signature (buff 65)) (signer principal))
(is-eq (principal-of? (unwrap! (secp256k1-recover? hash signature) false)) (ok signer))
)Production Stack & Technical Choices.
| Layer | Technology | Architectural Rationale |
|---|---|---|
| Smart Contracts | Clarity 3 · Stacks Blockchain | Decidable, non-Turing complete smart contract language preventing unexpected reentrancy and runtime panics |
| Frontend UI | React 19 · TypeScript · Tailwind CSS | Modern Web3 dashboard for stream management, live balance tickers, and signature generation |
| Blockchain SDK | @stacks/connect · @stacks/transactions | Seamless wallet connection (Leather & Xverse) and cryptographic message signing |
| Testing Suite | Clarinet · Vitest · TypeScript | Comprehensive unit and integration test suite covering stream creation, pause/resume, and refunds |