Hey everyone, sharing Trickle, my submission for the hackathon, and looking for feedback from people building on Fiber.
Authorship Sealed on Scryve. You can seal your work too, proving you wrote it and preserving it permanently on-chain.
1. The Problem
Fiber settles in milliseconds, but there’s still no clean way to bill per unit on it. Two things get in the way:
- You can’t open an HTLC hold for every token, every API call, or every second of usage. The hold locks up liquidity and eventually expires, and a stuck HTLC is a force-close waiting to happen.
- You can’t put a confirmation prompt in front of a human for every fraction of a cent, so anything that wants true per-unit billing needs an authorization step that only happens once, not per tick.
This shows up whenever someone wants to charge:
- Per token for AI inference
- Per call for an API
- Per megabyte for bandwidth or a CDN
- Subscriptions and other pay-as-you-go billing
- Agent-to-agent payments where an unattended process needs to spend under a ceiling
Hold-invoice gateways solve escrow for usage you haven’t spent yet. They don’t solve settling usage that already happened, under a budget you can reuse across thousands of ticks. That’s the gap Trickle fills.
2. How Trickle Works
A grant is a signed, off-chain object with no cell and no on-chain footprint: {payee, asset, maxTotal, maxRate, sessionId, nonce, expiry}.
The flow:
- User registers a passkey (or an M-of-N quorum is set up for delegated spending)
- User picks a budget and signs the grant digest once
- The grant is handed to an
AllowanceSession, which callsstream() - Each tick is a keysend
send_paymentcarryingcustom_records - A local cap check refuses anything over
maxTotalormaxRatebefore it ever reaches the node - Keysend on fnn v0.8.1 is spontaneous (random
payment_hash, preimage reveals at the far end), so a tick clears and closes on the spot, nothing stays open - A
SessionMeteron the receiving side watches the channel balance and releases service against value that has actually landed - In a recorded run a tick round-tripped in about 150 to 200ms
- Hit the cap and the stream freezes automatically
- User taps once to top up and the stream picks up exactly where it left off
3. Current Functionality
- Streaming path live against two real fnn v0.8.1 testnet nodes, not a mock
- Cap enforcement (
maxTotal,maxRate) and settled-value metering, both tested - In a recorded run, direct-channel ticks were free; a routed 3-node path measured at 0.1% proportional fee, no base fee, no per-tick floor
- Grant signing and verification for a 2-of-3 quorum, with tampering and expiry both covered by tests
- Passkey signing running for real through Windows Hello in the browser demo, plus a separate unit test against a simulated authenticator
- An escrow sibling for the hold-invoice side:
new_invoice→ payment →Received→ capture (passkey or quorum, bound to the invoice by a token,SHA256(payment_hash || amount || nonce), so a signature can’t be replayed onto a bigger or different capture) orcancel_invoice - Optional on-chain custody: a 2-of-3 account bootstrapped and swept with 300 CKB on Pudge, a 1-of-3 withdraw rejected on-chain, a valid 2-of-3 withdraw pushed through (details and tx hashes in the README’s Stage B section)
- Packaged as four libraries and two adapters, 22 tests passing across the workspace, build and CI green
- Runnable UI: browser stream at
/, streamer dashboard at/studio, escrow at/escrow, plus a terminal run and a device-free smoke test
4. Architecture
- fnn v0.8.1 over JSON-RPC:
send_payment(keysend,target_pubkey,custom_recordsTLV map),get_payment,new_invoice,settle_invoice,cancel_invoice - Two adapters: one wraps a
@fiber-pay/sdk-shaped client structurally, one bridgesfnn-payinvoice webhooks, so Trickle layers under SDKs teams are already using instead of replacing them @ckb-ccc/core(1.12.5) for building and sending Pudge transactions- On-chain custody reuses the
ckb-smart-accountM-of-N / WebAuthn lock (deployed v5), referenced by code hash, nothing new to deploy @noble/curvesfor P-256 WebAuthn signatures,@noble/hashesfor sha256 and blake2b (CKB’s default hash)- pnpm workspace, TypeScript throughout,
tscbuild,tsxruntime, Node’s built-in test runner (node:test); README asks for Node 20 or newer, CI runs Node 22 TRICKLE_DEMO=1swaps in an in-memory Fiber mock for a no-node run;BUYER_RPC/MERCHANT_RPCpoint the web demo at real nodes
5. Initial Use Cases
- Per-token billing for AI inference
- Per-call metering for APIs
- Per-megabyte billing for bandwidth or CDN delivery
- Subscriptions and other recurring pay-as-you-go billing
- Agent-to-agent payments, where a signed grant lets an unattended process spend under a ceiling someone else set
- Dropping in under existing Fiber payment SDKs (
fnn-pay,@fiber-pay/sdk) purely for the per-unit billing layer
We think the delegation angle (a treasury or a human signs a ceiling once, an agent spends under it) is where this gets more interesting than a single-user metering tool.
6. Early Validation Request
A few things we’d love feedback on from people closer to Fiber internals:
- Is there a roadmap for the receiver side to see incoming keysend payments before they settle? Right now metering more than one payer means one channel per payer, and that’s the limitation we’d most like to see close.
- Where does PTLC sit on the Fiber roadmap? Ticks aren’t currently atomic with delivery, we’re trusting the counterparty for one small tick at a time, and PTLC would close that gap.
- Is
custom_recordsthe right place to carry session/tick metadata, or is there an emerging convention we should align with instead? - Any guidance on multi-hop reliability (LSP peering, graph sync, hop hints)? We’ve measured the fee model on a routed path but haven’t stress-tested routing failures.
- Does packaging this as a client-side library (versus a hosted service) match how other teams want to consume metering infrastructure, or is a hosted gateway what people actually want?
- For UDT-funded streams, is there anything Fiber-specific we should account for beyond wiring
udt_type_scriptthrough the tick and RPC layer (which is already there)?
7. How to Test
pnpm installpnpm -r --filter "./packages/*" buildpnpm test- For a no-node run, set
TRICKLE_DEMO=1and start the browser demo - For a real run, point
BUYER_RPCandMERCHANT_RPCat two fnn v0.8.1 testnet nodes - Open
/for the streaming demo,/studiofor the streamer dashboard,/escrowfor the hold-invoice flow - Passkey signing needs Chrome or Edge; WebAuthn treats localhost as secure so no HTTPS is required locally
- The on-chain custody path is optional and needs a funded Pudge testnet key (
CKB_DEPLOYER_KEY_FILE); it reuses an already-deployed lock, so there’s nothing to deploy yourself - Everything above is testnet only, no real funds are at risk
8. Project Links
- GitHub: https://github.com/LusoCryptoLabs/trickle
- Video demo: gone in 60ms hackathlon – Google Drive
- Hosted demo (live for testing): https://trickle.lusocryptolabs.com/
- Screenshots: gone in 60ms hackathlon – Google Drive
- On-chain custody proof: Stage B section of README.md in the repo

