From 0e7dfda68a5b2706cc93916979dfb305ca7c6274 Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Thu, 11 Dec 2025 19:27:44 +0100 Subject: [PATCH 01/22] docs: add payment streams raw spec --- vac/raw/payment-streams.md | 296 +++++++++++++++++++++++++++++++++++++ 1 file changed, 296 insertions(+) create mode 100644 vac/raw/payment-streams.md diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md new file mode 100644 index 000000000..2075df6df --- /dev/null +++ b/vac/raw/payment-streams.md @@ -0,0 +1,296 @@ +--- +title: PAYMENT-STREAMS +name: Payment Streams Protocol for Logos Services +status: raw +category: Standards Track +tags: logos, payment, streams +editor: Sergei Tikhomirov +contributors: +--- + +## Abstract + +This document specifies a payment streams protocol for Logos services. +In this protocol, a payer locks up a deposit that is released gradually to a payee who provides services. +Either party may withdraw funds at any time. +The proportion of funds available to each party is determined by the underlying blockchain based on elapsed time. + +This approach provides simplicity: +parties need not store old states or handle dispute closures as required in payment channel protocols. +The unidirectional nature maps well to use cases where payers and payees have distinct roles. + +The protocol is designed to be lightweight, secure, private, and to avoid on-chain communication on every payment. +It targets Nescience, a privacy-focused blockchain with state separation architecture, +as the home for its on-chain component. + +This document provides a functional specification of the first MVP version of the protocol. +It clarifies requirements for the MVP and facilitates discussion with Nescience developers +regarding implementation feasibility, challenges, and integration considerations. + +## Motivation + +Logos is a privacy-focused tech stack that includes Logos Messaging, Logos Blockchain, and Logos Storage. + +Logos Messaging comprises a suite of communication protocols with both P2P and request-response structures. +While the backbone P2P protocols use tit-for-tat mechanisms, +we plan to introduce incentivization for auxiliary request-response protocols where client and server roles are well defined. +One such protocol is Store, +which allows a client to query historical messages from Logos Messaging relay nodes. + +Incentivization requires a payment protocol that is lightweight, secure, private, +and does not require on-chain communication for every payment. +After reviewing prior work on related systems including payment channels, streams, e-cash, and tickets, +we converged on payment streams as the first off-chain payment mechanism. + +Nescience is a privacy-focused blockchain under development, planned as part of the Logos Blockchain stack. +Its core innovation is state separation architecture (NSSA), which enables both transparent and shielded execution. +Targeting Nescience for the on-chain component of the payment protocol is a natural fit. +However, Nescience is still in development, and certain architectural aspects remain in progress. + +This document aims to provide clarity on MVP payment protocol requirements +and facilitate discussion with Nescience developers to determine: +whether the required functionality can be implemented, +which parts are most challenging and whether they can be simplified, +and other considerations for integrating Nescience with off-chain payment streams for privacy and scalability. + + + +## Related Work + +### Sablier Flow + +Sablier Flow implements open-ended streaming debt with a rate per second parameter. +The core formula is: amount owed equals rate per second multiplied by elapsed time. +Streams have no predetermined end time and accrue continuously. +Anyone can trigger settlement to realize accrued debt. +Uses standard ERC-20 tokens. + +### Sablier Lockup + +Sablier Lockup implements a deposit-to-continuous-emission-to-refund-remainder pattern. +Streams have fixed duration determined at creation. +The total deposit amount is locked upfront. +Tokens are released according to a predetermined schedule. +Settlement happens automatically based on time. +Uses singleton stream manager architecture and standard ERC-20 tokens. + +### LlamaPay V2 + +LlamaPay V2 deploys one vault contract per payer. +Each vault can manage multiple outgoing streams to different recipients using multiple tokens. +Streams are open-ended with rate per second accrual. +The protocol tracks debt when streams exceed available vault balance. +Either recipient or payer can trigger settlement. +Includes whitelisting for delegated vault management. +Uses standard ERC-20 tokens. +Licensed under AGPL-3.0. + +### Superfluid + +Superfluid implements real-time finance with continuous money flows. +Streams are open-ended with rate per second accrual. +Uses a host-agreements framework: a central host contract routes operations to pluggable agreement contracts. +Constant Flow Agreement handles streaming, Instant Distribution Agreement handles one-to-many distributions. +Balances update in real-time; settlement is automatic when balances are queried. +Requires wrapping standard tokens into Super Tokens. +Supports one sender streaming to multiple recipients. + +### Comparison + +| Design Dimension | Sablier Flow | Sablier Lockup | LlamaPay V2 | Superfluid | +|----------------|--------------|----------------|-------------|------------| +| Stream duration | Open-ended | Fixed duration | Open-ended | Open-ended | +| Accrual mechanism | Rate per second, debt tracking | Fixed schedule, no debt | Rate per second, debt tracking | Rate per second, real-time balance | +| Architecture | Singleton manager | Singleton manager | Per-payer vault | Host-agreements framework | +| Multi-recipient from one payer | No | No | Yes | Yes | +| Spending controls | None | Total deposit fixed upfront | None | Solvency checks only | +| Settlement trigger | Anyone can settle | Automatic time-based | Recipient or payer | Automatic on balance check | +| Token requirements | Standard ERC-20 | Standard ERC-20 | Standard ERC-20 | Super Tokens only | + +Key trade-offs between architectures: +Singleton managers (Sablier Flow, Sablier Lockup) require separate deposits per stream but provide simpler global state management. +Per-payer vaults (LlamaPay V2) allow deposit sharing across multiple streams but increase per-payer deployment costs. +Host-agreements framework (Superfluid) provides extensibility and composability at the cost of complexity and non-standard token requirements. + +## Theory and Semantics + +### Terminology + +| Term | Description | +|------|-------------| +| User | The party paying for services (payer) | +| Provider | The party delivering services and receiving payment (payee) | +| Vault | User's deposit holding funds that can back multiple streams | +| Stream | Individual payment flow from vault to one provider, with allocated funds and accrual rate | +| Allocation | Portion of vault funds committed to back a specific stream | +| Rate | Amount of tokens per second that accrue to provider while stream is active | +| Accrual | Process of calculating provider's earned balance based on elapsed time and rate | +| Claim | Provider retrieving accrued funds from a stream, available at any time from any stream state | +| Withdraw | User retrieving unallocated funds from vault or unaccrued funds from closed stream | +| Top-up | User adding funds to a stream's allocation | + +### High-level protocol semantics + +The overall goal of the protocol is to enable payments for services. + +This specification is written with Nescience blockchain as the target platform. +Nescience provides state separation architecture that enables both transparent and shielded execution. +The protocol design leverages these privacy capabilities while remaining functionally defined. + +We aim for the following high-level requirements: + +- Performance: Payments must be efficient in latency and fees. +- Security: The protocol must limit loss exposure through spending controls. +- Privacy: The protocol must break links between payments and service provision across providers. +- Extendability: The protocol must allow simple initial versions that can be enhanced later. + + +### Assumptions + +We assume the parties agree on stream parameters before stream creation. +The discovery protocol provides a way for providers to advertise their services and expected payment, +or for users and providers to negotiate stream parameters off-chain. + +We assume users monitor service delivery and take action when providers stop delivering service. +Since users are typically online to receive service, +monitoring service quality and pausing or closing streams when issues arise is not an unreasonable burden. +The user's risk exposure is bounded by the stream allocation size and the time to detect and respond to service degradation. + + +### Roles and responsibilities + +There are two parties: a user (payer) and a service provider (payee). +Funds flow unidirectionally from user to provider. + + +### Architecture Overview + +The protocol uses a two-level architecture: + +Vault - User's deposit of funds that can back multiple payment streams. +A vault holds the total balance available for streaming payments. +Each user has their own vault. + +Stream - Individual payment channel from a vault to one provider. +When creating a stream, the user allocates a portion of vault funds to back that stream. +Each stream specifies a rate per second at which funds accrue to the provider. + +Relationship: +One vault can have multiple streams to different providers. +Each stream belongs to exactly one vault. +Streams are isolated from each other to prevent linking user activity across providers. + +The protocol enforces that total allocated funds across all streams cannot exceed vault balance. + + +### Vault Lifecycle + +A vault is created when a user first deposits funds. +The vault persists as long as the user maintains it. + +Vault operations: + +Deposit - User adds tokens to the vault. +The vault balance increases. + +Withdraw - User removes unallocated tokens from the vault. +Only funds not allocated to streams can be withdrawn. + +Create Stream - User creates a new stream by allocating a portion of vault funds. +Allocated funds are committed to back that stream. + +Top Up Stream - User increases an existing stream's allocation using vault's available balance. +The additional amount is allocated from vault to the stream. + +Vault invariants: + +Sum of all stream allocations must not exceed total deposited balance. +User can only withdraw funds that are not allocated to streams. +Vault must maintain sufficient balance to cover all stream allocations. + + +### Stream Lifecycle + +A stream exists only when on-chain state is created. +Off-chain negotiation of stream parameters is handled by a separate discovery protocol. + +Stream states: + +ACTIVE - Funds accrue to provider at the agreed rate per second. +PAUSED - Accrual is stopped by user action, stream can be resumed by user. +DEPLETED - Stream has run out of allocated funds, accrual is stopped automatically. +CLOSED - Stream is permanently terminated, no further state changes possible. This is the terminal state. + +Stream state transitions: + +Create - User creates stream in ACTIVE state by allocating funds from vault. +Pause - User pauses an ACTIVE stream, stopping accrual. +Resume - User resumes a PAUSED stream, restarting accrual. +Deplete - Automatic transition from ACTIVE when allocated funds are fully accrued. +Top Up - User adds funds to stream from ACTIVE, PAUSED, or DEPLETED states, increasing allocation. +If performed from DEPLETED state, stream transitions to PAUSED. +If performed from ACTIVE or PAUSED state, stream remains in same state. +Close - Either user or provider closes stream from any non-CLOSED state. +Closure is permanent and irreversible. +CLOSED is the terminal state with no outgoing transitions. + +Claim operation: +Provider can claim accrued funds at any time from any stream state. +Accrued amount is determined by rate per second multiplied by time in ACTIVE state. +Claim operation is independent of stream state and does not affect state transitions. + +Withdraw operation: +User can withdraw unaccrued allocated funds only from CLOSED state. +User can withdraw unallocated funds from vault at any time. +User cannot withdraw allocated funds from non-CLOSED streams. + +Top-up operation: +User can add funds to a stream from ACTIVE, PAUSED, or DEPLETED states. +Top-up increases the stream's allocation from vault's available balance. +Vault must have sufficient unallocated balance to cover the top-up amount. +If stream is in DEPLETED state, top-up transitions it to PAUSED. +User must explicitly resume to restart accrual after topping up a depleted stream. +If stream is in ACTIVE or PAUSED state, top-up increases allocation without changing state. + +Stream invariants: + +Stream starts in ACTIVE state upon creation. +Only user can pause, resume, or top up a stream. +Stream automatically transitions to DEPLETED when allocated funds are fully accrued. +Either party can close a stream at any time from any non-CLOSED state. +Provider can only claim funds that have accrued based on elapsed time and rate. +User's allocated funds remain committed to the stream until stream is closed. +User can only withdraw stream funds after closing the stream. + +## Security and Privacy Considerations + +This section will address: +- Economic security assumptions and spending controls +- Attack vectors and mitigations +- Privacy guarantees provided by stream isolation +- Trust assumptions between users and providers +- Considerations specific to Nescience state separation architecture + +## Open Questions + +This section captures unresolved design decisions for discussion with Nescience developers: + +- Implementation of vault and stream isolation in Nescience NSSA +- Enforcement of allocation limits across streams in shielded execution +- Mechanisms for preventing over-commitment without revealing cross-provider activity +- State representation and transition enforcement in shielded execution +- Integration with delivery receipt verification for service quality assurance + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +## References + +### Informative + +- [Sablier Flow](https://github.com/sablier-labs/flow) - Open-ended streaming debt protocol +- [Sablier Lockup](https://github.com/sablier-labs/lockup) - Fixed-duration streaming protocol +- [LlamaPay V2](https://github.com/LlamaPay/llamapay-v2) - Per-payer vault streaming protocol +- [Superfluid Protocol](https://github.com/superfluid-org/protocol-monorepo) - Real-time finance framework + From 12d9ec4c0259a2bb3b78310f4e6dc11fc68dcd58 Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Fri, 12 Dec 2025 18:08:35 +0100 Subject: [PATCH 02/22] edit payment streams raw spec --- vac/raw/payment-streams.md | 446 ++++++++++++++++++------------------- 1 file changed, 212 insertions(+), 234 deletions(-) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index 2075df6df..0ca6eef46 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -4,282 +4,241 @@ name: Payment Streams Protocol for Logos Services status: raw category: Standards Track tags: logos, payment, streams -editor: Sergei Tikhomirov -contributors: +editor: Sergei Tikhomirov +contributors: Akhil Peddireddy --- ## Abstract -This document specifies a payment streams protocol for Logos services. -In this protocol, a payer locks up a deposit that is released gradually to a payee who provides services. -Either party may withdraw funds at any time. -The proportion of funds available to each party is determined by the underlying blockchain based on elapsed time. +This document provides a functional specification +for a payment streams protocol for Logos services. -This approach provides simplicity: -parties need not store old states or handle dispute closures as required in payment channel protocols. -The unidirectional nature maps well to use cases where payers and payees have distinct roles. +A payment stream is an off-chain protocol +where a payer's deposit releases gradually to a payee. +The blockchain determines fund accrual based on elapsed time. -The protocol is designed to be lightweight, secure, private, and to avoid on-chain communication on every payment. -It targets Nescience, a privacy-focused blockchain with state separation architecture, -as the home for its on-chain component. +The protocol targets Nescience, +a privacy-focused blockchain in the Logos stack. +This document clarifies MVP requirements +and facilitates discussion with Nescience developers +on implementation feasibility and challenges. -This document provides a functional specification of the first MVP version of the protocol. -It clarifies requirements for the MVP and facilitates discussion with Nescience developers -regarding implementation feasibility, challenges, and integration considerations. +## Language -## Motivation +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", +"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" +in this document are to be interpreted as described in +[RFC 2119](http://tools.ietf.org/html/rfc2119). -Logos is a privacy-focused tech stack that includes Logos Messaging, Logos Blockchain, and Logos Storage. +## Change Process -Logos Messaging comprises a suite of communication protocols with both P2P and request-response structures. -While the backbone P2P protocols use tit-for-tat mechanisms, -we plan to introduce incentivization for auxiliary request-response protocols where client and server roles are well defined. -One such protocol is Store, -which allows a client to query historical messages from Logos Messaging relay nodes. +This document is governed by the [1/COSS](../1/coss.md) (COSS). -Incentivization requires a payment protocol that is lightweight, secure, private, -and does not require on-chain communication for every payment. -After reviewing prior work on related systems including payment channels, streams, e-cash, and tickets, -we converged on payment streams as the first off-chain payment mechanism. +## Motivation -Nescience is a privacy-focused blockchain under development, planned as part of the Logos Blockchain stack. -Its core innovation is state separation architecture (NSSA), which enables both transparent and shielded execution. -Targeting Nescience for the on-chain component of the payment protocol is a natural fit. -However, Nescience is still in development, and certain architectural aspects remain in progress. +Logos is a privacy-focused tech stack that includes +Logos Messaging, Logos Blockchain, and Logos Storage. -This document aims to provide clarity on MVP payment protocol requirements -and facilitate discussion with Nescience developers to determine: +Logos Messaging comprises a suite of communication protocols +with both P2P and request-response structures. +The backbone P2P protocols use tit-for-tat mechanisms. +We plan to introduce incentivization +for auxiliary request-response protocols +where client and server roles are well defined. +One such protocol is Store, +which allows clients to query historical messages +from Logos Messaging relay nodes. + +We target the following requirements: + +- Performance: Efficient payments with low latency and fees. +- Security: Limited loss exposure through spending controls. +- Privacy: Unlinkable payments across different providers. +- Extendability: Simple initial design with room for enhancements. + +After reviewing prior work on payment channels, streams, +e-cash, and tickets, +we selected payment streams as the most suitable mechanism. + +Payment streams enable unidirectional time-based fund flows +from payer to payee. +Streams are simpler than alternatives +and map well to use cases with distinct roles. +Parties need not store old states or initiate disputes +as required in payment channel protocols. +Streams avoid relying on a centralized mint entity, +typical for e-cash and ticket protocols, +improving resilience and privacy. + +Nescience is a privacy-focused blockchain under development +for the Logos Blockchain stack. +Its core innovation is state separation architecture (NSSA), +which enables both transparent and shielded execution. +Nescience is a natural fit +for the on-chain component of the payment protocol. + +This document provides clarity on MVP requirements +and facilitates discussion with Nescience developers on: whether the required functionality can be implemented, -which parts are most challenging and whether they can be simplified, -and other considerations for integrating Nescience with off-chain payment streams for privacy and scalability. - - - -## Related Work - -### Sablier Flow - -Sablier Flow implements open-ended streaming debt with a rate per second parameter. -The core formula is: amount owed equals rate per second multiplied by elapsed time. -Streams have no predetermined end time and accrue continuously. -Anyone can trigger settlement to realize accrued debt. -Uses standard ERC-20 tokens. - -### Sablier Lockup - -Sablier Lockup implements a deposit-to-continuous-emission-to-refund-remainder pattern. -Streams have fixed duration determined at creation. -The total deposit amount is locked upfront. -Tokens are released according to a predetermined schedule. -Settlement happens automatically based on time. -Uses singleton stream manager architecture and standard ERC-20 tokens. +which parts are most challenging and how to simplify them, +and other implementation considerations. -### LlamaPay V2 - -LlamaPay V2 deploys one vault contract per payer. -Each vault can manage multiple outgoing streams to different recipients using multiple tokens. -Streams are open-ended with rate per second accrual. -The protocol tracks debt when streams exceed available vault balance. -Either recipient or payer can trigger settlement. -Includes whitelisting for delegated vault management. -Uses standard ERC-20 tokens. -Licensed under AGPL-3.0. - -### Superfluid - -Superfluid implements real-time finance with continuous money flows. -Streams are open-ended with rate per second accrual. -Uses a host-agreements framework: a central host contract routes operations to pluggable agreement contracts. -Constant Flow Agreement handles streaming, Instant Distribution Agreement handles one-to-many distributions. -Balances update in real-time; settlement is automatic when balances are queried. -Requires wrapping standard tokens into Super Tokens. -Supports one sender streaming to multiple recipients. +## Theory and Semantics -### Comparison +### Architecture Overview -| Design Dimension | Sablier Flow | Sablier Lockup | LlamaPay V2 | Superfluid | -|----------------|--------------|----------------|-------------|------------| -| Stream duration | Open-ended | Fixed duration | Open-ended | Open-ended | -| Accrual mechanism | Rate per second, debt tracking | Fixed schedule, no debt | Rate per second, debt tracking | Rate per second, real-time balance | -| Architecture | Singleton manager | Singleton manager | Per-payer vault | Host-agreements framework | -| Multi-recipient from one payer | No | No | Yes | Yes | -| Spending controls | None | Total deposit fixed upfront | None | Solvency checks only | -| Settlement trigger | Anyone can settle | Automatic time-based | Recipient or payer | Automatic on balance check | -| Token requirements | Standard ERC-20 | Standard ERC-20 | Standard ERC-20 | Super Tokens only | +The protocol has two roles: -Key trade-offs between architectures: -Singleton managers (Sablier Flow, Sablier Lockup) require separate deposits per stream but provide simpler global state management. -Per-payer vaults (LlamaPay V2) allow deposit sharing across multiple streams but increase per-payer deployment costs. -Host-agreements framework (Superfluid) provides extensibility and composability at the cost of complexity and non-standard token requirements. +- User: the party paying for services (payer). +- Provider: the party delivering services +and receiving payment (payee). -## Theory and Semantics +The protocol uses a two-level architecture +of vaults and streams. -### Terminology +A vault holds a user's deposit and backs multiple streams. +To start using the protocol, +the user MUST deposit funds into a vault. +A vault holds the total balance available for that user's streams. +One vault MAY have multiple streams to different providers. +The user MAY withdraw unallocated funds from the vault at any time. +Vault withdrawals MUST send funds to external addresses. -| Term | Description | -|------|-------------| -| User | The party paying for services (payer) | -| Provider | The party delivering services and receiving payment (payee) | -| Vault | User's deposit holding funds that can back multiple streams | -| Stream | Individual payment flow from vault to one provider, with allocated funds and accrual rate | -| Allocation | Portion of vault funds committed to back a specific stream | -| Rate | Amount of tokens per second that accrue to provider while stream is active | -| Accrual | Process of calculating provider's earned balance based on elapsed time and rate | -| Claim | Provider retrieving accrued funds from a stream, available at any time from any stream state | -| Withdraw | User retrieving unallocated funds from vault or unaccrued funds from closed stream | -| Top-up | User adding funds to a stream's allocation | +A stream is an individual payment flow from a vault to one provider. +When creating a stream, +the user MUST allocate a portion of vault funds to that stream. +Each stream MUST belong to exactly one vault. +Each stream MUST specify an accrual rate (tokens per time unit). +An allocation is the portion of vault funds committed to a stream. +The sum of all stream allocations MUST NOT exceed vault balance. -### High-level protocol semantics +A claim is the operation +where the provider retrieves accrued funds from a stream. +The provider MAY claim accrued funds from a stream in any state. -The overall goal of the protocol is to enable payments for services. +### Stream Lifecycle -This specification is written with Nescience blockchain as the target platform. -Nescience provides state separation architecture that enables both transparent and shielded execution. -The protocol design leverages these privacy capabilities while remaining functionally defined. +Stream states: -We aim for the following high-level requirements: +- ACTIVE: Funds accrue to the provider at the agreed rate. +- PAUSED: Accrual is stopped by user action. +The stream MAY be resumed by the user. +- DEPLETED: Stream has run out of allocated funds. +Accrual is stopped automatically. +- CLOSED: Stream is permanently terminated. +The stream MUST NOT transition to any other state. -- Performance: Payments must be efficient in latency and fees. -- Security: The protocol must limit loss exposure through spending controls. -- Privacy: The protocol must break links between payments and service provision across providers. -- Extendability: The protocol must allow simple initial versions that can be enhanced later. +Stream state transitions: +- Create: User creates a stream in ACTIVE state +by allocating funds from the vault. +- Pause: User pauses an ACTIVE stream, stopping accrual. +- Resume: User resumes a PAUSED stream, restarting accrual. +- Deplete: Automatic transition from ACTIVE +when allocated funds are fully accrued. +- Top-Up: User MAY add funds to stream allocation. +From DEPLETED state, stream MUST transition to PAUSED. +From ACTIVE or PAUSED state, stream MUST remain in same state. +- Close: Either user or provider MAY close the stream +from any non-CLOSED state. +- Withdraw: User MAY withdraw only unaccrued funds +from a CLOSED stream. +A withdraw operation MUST return funds to the vault. +The user MUST NOT withdraw from any non-CLOSED stream. +Accrued funds remain available for provider to claim. +- Claim: Provider MAY claim accrued funds +from a stream in any state. +A claim operation does not change stream state. + +### Stream State Transition Diagram + +```mermaid +graph LR; + ACTIVE --> PAUSED; + PAUSED --> ACTIVE; + ACTIVE --> DEPLETED; + DEPLETED --> PAUSED; + ACTIVE --> CLOSED; + PAUSED --> CLOSED; + DEPLETED --> CLOSED; +``` ### Assumptions -We assume the parties agree on stream parameters before stream creation. -The discovery protocol provides a way for providers to advertise their services and expected payment, -or for users and providers to negotiate stream parameters off-chain. +Parties MUST agree on stream parameters before creation. +A separate discovery protocol SHOULD enable +providers to advertise services and expected payment, +or enable users and providers to negotiate parameters. -We assume users monitor service delivery and take action when providers stop delivering service. +Users SHOULD monitor service delivery +and take action when providers stop delivering service. Since users are typically online to receive service, -monitoring service quality and pausing or closing streams when issues arise is not an unreasonable burden. -The user's risk exposure is bounded by the stream allocation size and the time to detect and respond to service degradation. +monitoring quality and pausing or closing streams +is a reasonable expectation. +## Protocol Extensions -### Roles and responsibilities +This section describes optional modifications +that MAY be applied to the base protocol. +Each extension is independent. -There are two parties: a user (payer) and a service provider (payee). -Funds flow unidirectionally from user to provider. +### Epoch-Based Accrual Caps +The user MAY specify epoch length and epoch cap when creating a stream. +When accrued amount reaches the epoch cap, +the stream MUST automatically transition to PAUSED state. +The user MAY resume the stream, resetting the epoch accrual counter. -### Architecture Overview - -The protocol uses a two-level architecture: +### Delivery Receipts -Vault - User's deposit of funds that can back multiple payment streams. -A vault holds the total balance available for streaming payments. -Each user has their own vault. +The claim operation MAY require delivery receipts as proof of service. +A delivery receipt is a user-signed message that MUST include +stream identifier, service delivery details, and signature. +If a stream has delivery receipts enabled, +the protocol MUST only allow claims with valid receipts. +Receipt granularity (per-message vs batched) affects +proof granularity and interaction overhead. -Stream - Individual payment channel from a vault to one provider. -When creating a stream, the user allocates a portion of vault funds to back that stream. -Each stream specifies a rate per second at which funds accrue to the provider. +### Automatic Settlement on Closure -Relationship: -One vault can have multiple streams to different providers. -Each stream belongs to exactly one vault. -Streams are isolated from each other to prevent linking user activity across providers. +This extension adds two independent boolean stream parameters: -The protocol enforces that total allocated funds across all streams cannot exceed vault balance. +- Auto-claim on close: +When enabled, closing the stream +MUST automatically claim accrued funds for the provider. +- Auto-withdraw on close: +When enabled, closing the stream +MUST automatically return unaccrued funds to the user's vault. +## Implementation Considerations -### Vault Lifecycle +This section captures implementation questions: -A vault is created when a user first deposits funds. -The vault persists as long as the user maintains it. - -Vault operations: - -Deposit - User adds tokens to the vault. -The vault balance increases. - -Withdraw - User removes unallocated tokens from the vault. -Only funds not allocated to streams can be withdrawn. - -Create Stream - User creates a new stream by allocating a portion of vault funds. -Allocated funds are committed to back that stream. - -Top Up Stream - User increases an existing stream's allocation using vault's available balance. -The additional amount is allocated from vault to the stream. - -Vault invariants: - -Sum of all stream allocations must not exceed total deposited balance. -User can only withdraw funds that are not allocated to streams. -Vault must maintain sufficient balance to cover all stream allocations. - - -### Stream Lifecycle - -A stream exists only when on-chain state is created. -Off-chain negotiation of stream parameters is handled by a separate discovery protocol. - -Stream states: - -ACTIVE - Funds accrue to provider at the agreed rate per second. -PAUSED - Accrual is stopped by user action, stream can be resumed by user. -DEPLETED - Stream has run out of allocated funds, accrual is stopped automatically. -CLOSED - Stream is permanently terminated, no further state changes possible. This is the terminal state. - -Stream state transitions: - -Create - User creates stream in ACTIVE state by allocating funds from vault. -Pause - User pauses an ACTIVE stream, stopping accrual. -Resume - User resumes a PAUSED stream, restarting accrual. -Deplete - Automatic transition from ACTIVE when allocated funds are fully accrued. -Top Up - User adds funds to stream from ACTIVE, PAUSED, or DEPLETED states, increasing allocation. -If performed from DEPLETED state, stream transitions to PAUSED. -If performed from ACTIVE or PAUSED state, stream remains in same state. -Close - Either user or provider closes stream from any non-CLOSED state. -Closure is permanent and irreversible. -CLOSED is the terminal state with no outgoing transitions. - -Claim operation: -Provider can claim accrued funds at any time from any stream state. -Accrued amount is determined by rate per second multiplied by time in ACTIVE state. -Claim operation is independent of stream state and does not affect state transitions. - -Withdraw operation: -User can withdraw unaccrued allocated funds only from CLOSED state. -User can withdraw unallocated funds from vault at any time. -User cannot withdraw allocated funds from non-CLOSED streams. - -Top-up operation: -User can add funds to a stream from ACTIVE, PAUSED, or DEPLETED states. -Top-up increases the stream's allocation from vault's available balance. -Vault must have sufficient unallocated balance to cover the top-up amount. -If stream is in DEPLETED state, top-up transitions it to PAUSED. -User must explicitly resume to restart accrual after topping up a depleted stream. -If stream is in ACTIVE or PAUSED state, top-up increases allocation without changing state. - -Stream invariants: - -Stream starts in ACTIVE state upon creation. -Only user can pause, resume, or top up a stream. -Stream automatically transitions to DEPLETED when allocated funds are fully accrued. -Either party can close a stream at any time from any non-CLOSED state. -Provider can only claim funds that have accrued based on elapsed time and rate. -User's allocated funds remain committed to the stream until stream is closed. -User can only withdraw stream funds after closing the stream. +- Mapping streams to NSSA: +How does the stream protocol map onto Nescience architecture? +- Timestamp-based accrual calculation: +Can shielded execution access block timestamps +to calculate accrued amounts based on elapsed time? +- Encoding and enforcing state transitions: +How to encode and enforce state machine transition rules +for the stream lifecycle states? ## Security and Privacy Considerations -This section will address: -- Economic security assumptions and spending controls -- Attack vectors and mitigations -- Privacy guarantees provided by stream isolation -- Trust assumptions between users and providers -- Considerations specific to Nescience state separation architecture - -## Open Questions - -This section captures unresolved design decisions for discussion with Nescience developers: - -- Implementation of vault and stream isolation in Nescience NSSA -- Enforcement of allocation limits across streams in shielded execution -- Mechanisms for preventing over-commitment without revealing cross-provider activity -- State representation and transition enforcement in shielded execution -- Integration with delivery receipt verification for service quality assurance +This section captures security and privacy questions: + +- Can or should all protocol operations be within shielded execution? +- If not, where is the boundary +between transparent and shielded execution? +- Who decides whether to use transparent or shielded execution: +user, provider, both, or fixed by protocol design? +- What data is stored in the user's account +and who can see it in transparent vs shielded execution? +- How to ensure external observers cannot correlate +streams from the same vault across different providers? +- How to ensure providers cannot see +streams from the same user to other providers, +while still being able to verify balance constraints? ## Copyright @@ -289,8 +248,27 @@ Copyright and related rights waived via [CC0](https://creativecommons.org/public ### Informative -- [Sablier Flow](https://github.com/sablier-labs/flow) - Open-ended streaming debt protocol -- [Sablier Lockup](https://github.com/sablier-labs/lockup) - Fixed-duration streaming protocol -- [LlamaPay V2](https://github.com/LlamaPay/llamapay-v2) - Per-payer vault streaming protocol -- [Superfluid Protocol](https://github.com/superfluid-org/protocol-monorepo) - Real-time finance framework - +#### Related Work + +- [Off-Chain Payment Protocols: Classification and Architectural Choice](https://forum.vac.dev/t/off-chain-payment-protocols-classification-and-architectural-choice/596) +- [Nescience: A User-Centric State-Separation Architecture](https://vac.dev/rlog/Nescience-state-separation-architecture) + +#### Payment Streaming Protocols + +Existing payment streaming protocols +(Sablier Flow, Sablier Lockup, LlamaPay V2, Superfluid) +target EVM-like state architectures. +They use time-based accrual with ERC-20 tokens. +Protocols differ in stream duration. +Some support fixed-duration streams (Sablier Lockup), +while others allow open-ended streams (Sablier Flow). +Deposit architecture also varies. +Singleton managers (Sablier Flow, Sablier Lockup) +require separate deposits per stream. +Per-payer vaults (LlamaPay V2) +allow one deposit to back multiple streams. + +- [Sablier Flow](https://github.com/sablier-labs/flow) +- [Sablier Lockup](https://github.com/sablier-labs/lockup) +- [LlamaPay V2](https://github.com/LlamaPay/llamapay-v2) +- [Superfluid Protocol](https://github.com/superfluid-org/protocol-monorepo) From 640a9e914ac3dc8d99ecd80ae5f49bff79fc34f7 Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Mon, 15 Dec 2025 11:54:20 +0100 Subject: [PATCH 03/22] minor edits of payment streams spec --- vac/raw/payment-streams.md | 45 +++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index 0ca6eef46..ebf880fc7 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -3,7 +3,7 @@ title: PAYMENT-STREAMS name: Payment Streams Protocol for Logos Services status: raw category: Standards Track -tags: logos, payment, streams +tags: logos, nescience, payment-streams editor: Sergei Tikhomirov contributors: Akhil Peddireddy --- @@ -97,12 +97,17 @@ The protocol uses a two-level architecture of vaults and streams. A vault holds a user's deposit and backs multiple streams. +A user MAY have multiple vaults. To start using the protocol, the user MUST deposit funds into a vault. -A vault holds the total balance available for that user's streams. +A vault holds the total balance available for that vault's streams. One vault MAY have multiple streams to different providers. The user MAY withdraw unallocated funds from the vault at any time. -Vault withdrawals MUST send funds to external addresses. +Vault withdrawals send funds to addresses, +which MAY be external addresses or other vaults. +Allocating funds from a vault to a stream +is not considered a withdrawal, +as the funds remain within the protocol. A stream is an individual payment flow from a vault to one provider. When creating a stream, @@ -145,6 +150,8 @@ from any non-CLOSED state. from a CLOSED stream. A withdraw operation MUST return funds to the vault. The user MUST NOT withdraw from any non-CLOSED stream. +When a stream is closed, +unaccrued funds MUST automatically return to the user's vault. Accrued funds remain available for provider to claim. - Claim: Provider MAY claim accrued funds from a stream in any state. @@ -196,19 +203,31 @@ A delivery receipt is a user-signed message that MUST include stream identifier, service delivery details, and signature. If a stream has delivery receipts enabled, the protocol MUST only allow claims with valid receipts. -Receipt granularity (per-message vs batched) affects -proof granularity and interaction overhead. -### Automatic Settlement on Closure +Receipt granularity presents a trade-off. +Per-message receipts allow the user to approve each message individually +but require signing each receipt, increasing interaction overhead. +Batched receipts reduce signing overhead +but require the user to approve multiple messages at once. -This extension adds two independent boolean stream parameters: +### Automatic Claim on Closure -- Auto-claim on close: -When enabled, closing the stream -MUST automatically claim accrued funds for the provider. -- Auto-withdraw on close: -When enabled, closing the stream -MUST automatically return unaccrued funds to the user's vault. +This extension adds an optional auto-claim flag. +When auto-claim is enabled, +closing the stream MUST automatically claim accrued funds for the provider. + +Auto-claim simplifies the protocol +by ensuring closed streams hold no funds, +eliminating the need to track balances in closed streams. + +However, auto-claim has potential issues: +prevents provider from batching claims, +may create timing correlations that leak privacy, +requires user to pay for provider's claim operation, +and may cause the entire close operation to fail if claim fails. + +Assessing these trade-offs requires clarity on Nescience architecture, +particularly gas model, batching techniques, and timing privacy. ## Implementation Considerations From 6b0954ff56b8789999d50c0dfbc996c84f840148 Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Tue, 16 Dec 2025 18:37:58 +0100 Subject: [PATCH 04/22] add off-chain protocol section --- vac/raw/payment-streams.md | 75 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index ebf880fc7..69faa807e 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -183,6 +183,81 @@ Since users are typically online to receive service, monitoring quality and pausing or closing streams is a reasonable expectation. +## Off-Chain Protocol + +This section describes off-chain communication +for stream establishment, service delivery, and closure. + +### Design Rationale + +On-chain state is the source of truth for fund allocation and accrual. +Off-chain communication coordinates lifecycle events +and enables service delivery. + +Users MAY pause or close streams without prior notice. +Providers SHOULD track on-chain state for their streams. + +If the provider stops serving the user, +the provider MUST notify the user off-chain +before closing the stream on-chain. + +### Message Types + +#### Stream Establishment + +StreamRequest: +The user sends a StreamRequest to initiate a stream. +This message MUST include: + +- service_type: identifier of the requested service +- stream_rate: proposed accrual rate (tokens per time unit) +- stream_allocation: proposed initial allocation +- public_key: key for signing subsequent service requests + +StreamResponse: +The provider responds with acceptance or rejection. +This message MUST include: + +- status: ACCEPTED or REJECTED +- reason: explanation if rejected (OPTIONAL) + +If accepted, the user creates the stream on-chain. +Acceptance commits the provider to deliver the specified service +while payment accrues at the agreed rate. +The provider MAY later terminate service +but MUST send a ServiceTermination message first. + +#### Service Request + +ServiceRequest: +The user sends service requests during stream operation. +Each request MUST include: + +- request_data: service-specific payload +- signature: signature over request_data using the committed public key + +The signature proves the request originates from the stream owner. +The provider tracks on-chain state to verify the stream remains active. + +This design assumes the underlying blockchain provides funding privacy. +Stream creation MUST NOT reveal which vault funded the stream. +Vault deposits MUST NOT reveal the depositor's identity. + +#### Service Termination + +ServiceTermination: +The provider sends this message when stopping service. +This message MUST include: + +- termination_type: TEMPORARY or PERMANENT +- resume_after: timestamp after which service MAY resume + (REQUIRED for TEMPORARY, empty for PERMANENT) + +For temporary termination, +the user MAY pause the stream until the resume_after time. +For permanent termination, +the user SHOULD close the stream to recover unaccrued funds. + ## Protocol Extensions This section describes optional modifications From 1383e3c42e68dfddf684f86264377696da6712a3 Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Wed, 17 Dec 2025 16:05:47 +0100 Subject: [PATCH 05/22] simplify state machine: merge PAUSED and DEPLETED --- vac/raw/payment-streams.md | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index 69faa807e..45e260e09 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -126,10 +126,10 @@ The provider MAY claim accrued funds from a stream in any state. Stream states: - ACTIVE: Funds accrue to the provider at the agreed rate. -- PAUSED: Accrual is stopped by user action. +- PAUSED: Accrual is stopped. +The stream transitions to PAUSED by user action +or automatically when allocated funds are fully accrued. The stream MAY be resumed by the user. -- DEPLETED: Stream has run out of allocated funds. -Accrual is stopped automatically. - CLOSED: Stream is permanently terminated. The stream MUST NOT transition to any other state. @@ -138,12 +138,12 @@ Stream state transitions: - Create: User creates a stream in ACTIVE state by allocating funds from the vault. - Pause: User pauses an ACTIVE stream, stopping accrual. -- Resume: User resumes a PAUSED stream, restarting accrual. -- Deplete: Automatic transition from ACTIVE +The stream also transitions automatically from ACTIVE to PAUSED when allocated funds are fully accrued. +- Resume: User resumes a PAUSED stream, restarting accrual. +Resume MUST fail if remaining allocation is zero. - Top-Up: User MAY add funds to stream allocation. -From DEPLETED state, stream MUST transition to PAUSED. -From ACTIVE or PAUSED state, stream MUST remain in same state. +Stream MUST remain in same state after top-up. - Close: Either user or provider MAY close the stream from any non-CLOSED state. - Withdraw: User MAY withdraw only unaccrued funds @@ -161,13 +161,10 @@ A claim operation does not change stream state. ```mermaid graph LR; - ACTIVE --> PAUSED; - PAUSED --> ACTIVE; - ACTIVE --> DEPLETED; - DEPLETED --> PAUSED; - ACTIVE --> CLOSED; - PAUSED --> CLOSED; - DEPLETED --> CLOSED; + ACTIVE -->|pause / deplete| PAUSED; + PAUSED -->|resume| ACTIVE; + ACTIVE -->|close| CLOSED; + PAUSED -->|close| CLOSED; ``` ### Assumptions From bc78e303469e9694dcc0c8782f64e35f92747e53 Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Wed, 17 Dec 2025 16:07:57 +0100 Subject: [PATCH 06/22] auto-resume stream on top-up --- vac/raw/payment-streams.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index 45e260e09..54616c3ac 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -143,7 +143,9 @@ when allocated funds are fully accrued. - Resume: User resumes a PAUSED stream, restarting accrual. Resume MUST fail if remaining allocation is zero. - Top-Up: User MAY add funds to stream allocation. -Stream MUST remain in same state after top-up. +Top-up MUST transition the stream to ACTIVE state. +If the user wants to add funds without resuming, +the user MUST pause the stream after top-up. - Close: Either user or provider MAY close the stream from any non-CLOSED state. - Withdraw: User MAY withdraw only unaccrued funds @@ -162,7 +164,7 @@ A claim operation does not change stream state. ```mermaid graph LR; ACTIVE -->|pause / deplete| PAUSED; - PAUSED -->|resume| ACTIVE; + PAUSED -->|resume / top-up| ACTIVE; ACTIVE -->|close| CLOSED; PAUSED -->|close| CLOSED; ``` From 0d7e7d4d172c928d92bcfd2fef1297e05fa4ea04 Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Wed, 17 Dec 2025 16:10:48 +0100 Subject: [PATCH 07/22] auto-pause instead of per-epoch cap --- vac/raw/payment-streams.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index 54616c3ac..1bc5cd39f 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -263,12 +263,16 @@ This section describes optional modifications that MAY be applied to the base protocol. Each extension is independent. -### Epoch-Based Accrual Caps +### Auto-Pause -The user MAY specify epoch length and epoch cap when creating a stream. -When accrued amount reaches the epoch cap, +The user MAY specify an auto-pause duration when creating a stream. +When the specified duration elapses since stream creation or last resume, the stream MUST automatically transition to PAUSED state. -The user MAY resume the stream, resetting the epoch accrual counter. +The user MAY resume the stream, resetting the auto-pause timer. + +Auto-pause limits loss if service stops and the user is offline. +Per-stream allocation already bounds total risk; +auto-pause adds periodic check-ins for long-running streams. ### Delivery Receipts From 13dacc1dd972eaf3e3a2475d81f8b4bf92c86e16 Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Fri, 19 Dec 2025 11:57:21 +0100 Subject: [PATCH 08/22] add activation fee extension; chain tracking comment --- vac/raw/payment-streams.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index 1bc5cd39f..cac109c00 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -182,6 +182,10 @@ Since users are typically online to receive service, monitoring quality and pausing or closing streams is a reasonable expectation. +Providers SHOULD monitor the stream on-chain +and SHOULD stop providing service when a stream +is not ACTIVE. + ## Off-Chain Protocol This section describes off-chain communication @@ -307,6 +311,26 @@ and may cause the entire close operation to fail if claim fails. Assessing these trade-offs requires clarity on Nescience architecture, particularly gas model, batching techniques, and timing privacy. +### Activation Fee + +A user MAY exploit the pause/resume mechanism +by keeping a stream paused and resuming only briefly to query a service. +This results in minimal payment for actual service usage. + +The activation fee extension addresses this attack. +When enabled, the stream MUST accrue a fixed activation fee +immediately upon entering ACTIVE state. +The fee applies to stream creation, resume, and top-up operations. +Note that only user actions transition a stream to ACTIVE state. + +The activation fee SHOULD reflect +the minimum acceptable payment for a service session. +If the fee exceeds the value of a single query, +the attack becomes economically unviable. + +Providers MAY alternatively address this attack via off-chain policy +by refusing service to users who pause and resume excessively. + ## Implementation Considerations This section captures implementation questions: From 65b094b2f2f998a410b6c7d731da8c21b0f86a87 Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Fri, 19 Dec 2025 12:05:35 +0100 Subject: [PATCH 09/22] add comment on streams vs channels applicability --- vac/raw/payment-streams.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index cac109c00..5e865acec 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -70,6 +70,17 @@ Streams avoid relying on a centralized mint entity, typical for e-cash and ticket protocols, improving resilience and privacy. +Different service patterns suit different payment mechanisms. +Ongoing services align well with streams +that provide time-based automatic fund accrual. +One-time or on-demand services are better suited +for payment channels with one-off payments. + +This specification targets streams +for services with steady usage patterns. +Addressing burst services with one-off payments +remains future work. + Nescience is a privacy-focused blockchain under development for the Logos Blockchain stack. Its core innovation is state separation architecture (NSSA), From f398916857e6c1c565a4c3912c3a28e3e78c8c3b Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Fri, 19 Dec 2025 12:17:11 +0100 Subject: [PATCH 10/22] update naming to Logos and LSSA --- vac/raw/payment-streams.md | 110 +++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 59 deletions(-) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index 5e865acec..26805735f 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -3,7 +3,7 @@ title: PAYMENT-STREAMS name: Payment Streams Protocol for Logos Services status: raw category: Standards Track -tags: logos, nescience, payment-streams +tags: logos, lssa, payment-streams editor: Sergei Tikhomirov contributors: Akhil Peddireddy --- @@ -17,10 +17,10 @@ A payment stream is an off-chain protocol where a payer's deposit releases gradually to a payee. The blockchain determines fund accrual based on elapsed time. -The protocol targets Nescience, -a privacy-focused blockchain in the Logos stack. +The protocol targets Logos blockchain, +which uses the Logos State-Separation Architecture (LSSA). This document clarifies MVP requirements -and facilitates discussion with Nescience developers +and facilitates discussion with Logos developers on implementation feasibility and challenges. ## Language @@ -81,15 +81,13 @@ for services with steady usage patterns. Addressing burst services with one-off payments remains future work. -Nescience is a privacy-focused blockchain under development -for the Logos Blockchain stack. -Its core innovation is state separation architecture (NSSA), +Logos blockchain uses the Logos State-Separation Architecture (LSSA), which enables both transparent and shielded execution. -Nescience is a natural fit +LSSA is a natural fit for the on-chain component of the payment protocol. This document provides clarity on MVP requirements -and facilitates discussion with Nescience developers on: +and facilitates discussion with Logos developers on: whether the required functionality can be implemented, which parts are most challenging and how to simplify them, and other implementation considerations. @@ -101,18 +99,16 @@ and other implementation considerations. The protocol has two roles: - User: the party paying for services (payer). -- Provider: the party delivering services -and receiving payment (payee). +- Provider: the party delivering services and receiving payment (payee). The protocol uses a two-level architecture of vaults and streams. A vault holds a user's deposit and backs multiple streams. A user MAY have multiple vaults. +One vault MAY back streams to different providers. To start using the protocol, the user MUST deposit funds into a vault. -A vault holds the total balance available for that vault's streams. -One vault MAY have multiple streams to different providers. The user MAY withdraw unallocated funds from the vault at any time. Vault withdrawals send funds to addresses, which MAY be external addresses or other vaults. @@ -138,37 +134,32 @@ Stream states: - ACTIVE: Funds accrue to the provider at the agreed rate. - PAUSED: Accrual is stopped. -The stream transitions to PAUSED by user action -or automatically when allocated funds are fully accrued. -The stream MAY be resumed by the user. + The stream transitions to PAUSED by user action + or automatically when allocated funds are fully accrued. + The user MAY resume the stream. - CLOSED: Stream is permanently terminated. -The stream MUST NOT transition to any other state. + The stream MUST NOT transition to any other state. Stream state transitions: - Create: User creates a stream in ACTIVE state -by allocating funds from the vault. + by allocating funds from the vault. - Pause: User pauses an ACTIVE stream, stopping accrual. -The stream also transitions automatically from ACTIVE to PAUSED -when allocated funds are fully accrued. + The stream also transitions automatically from ACTIVE to PAUSED + when allocated funds are fully accrued. - Resume: User resumes a PAUSED stream, restarting accrual. -Resume MUST fail if remaining allocation is zero. + Resume MUST fail if remaining allocation is zero. - Top-Up: User MAY add funds to stream allocation. -Top-up MUST transition the stream to ACTIVE state. -If the user wants to add funds without resuming, -the user MUST pause the stream after top-up. + Top-up MUST transition the stream to ACTIVE state. + If the user wants to add funds without resuming, + the user MUST pause the stream after top-up. - Close: Either user or provider MAY close the stream -from any non-CLOSED state. -- Withdraw: User MAY withdraw only unaccrued funds -from a CLOSED stream. -A withdraw operation MUST return funds to the vault. -The user MUST NOT withdraw from any non-CLOSED stream. -When a stream is closed, -unaccrued funds MUST automatically return to the user's vault. -Accrued funds remain available for provider to claim. -- Claim: Provider MAY claim accrued funds -from a stream in any state. -A claim operation does not change stream state. + from any non-CLOSED state. + When a stream is closed, + unaccrued funds MUST automatically return to the user's vault. + Accrued funds remain available for provider to claim. +- Claim: Provider MAY claim accrued funds from a stream in any state. + A claim operation does not change stream state. ### Stream State Transition Diagram @@ -194,8 +185,7 @@ monitoring quality and pausing or closing streams is a reasonable expectation. Providers SHOULD monitor the stream on-chain -and SHOULD stop providing service when a stream -is not ACTIVE. +and SHOULD stop providing service when a stream is not ACTIVE. ## Off-Chain Protocol @@ -314,25 +304,27 @@ by ensuring closed streams hold no funds, eliminating the need to track balances in closed streams. However, auto-claim has potential issues: -prevents provider from batching claims, -may create timing correlations that leak privacy, -requires user to pay for provider's claim operation, -and may cause the entire close operation to fail if claim fails. -Assessing these trade-offs requires clarity on Nescience architecture, +- Prevents provider from batching claims. +- May create timing correlations that leak privacy. +- Requires user to pay for provider's claim operation. +- May cause the entire close operation to fail if claim fails. + +Assessing these trade-offs requires clarity on LSSA, particularly gas model, batching techniques, and timing privacy. ### Activation Fee -A user MAY exploit the pause/resume mechanism -by keeping a stream paused and resuming only briefly to query a service. +A user can exploit the pause/resume mechanism +by keeping a stream paused +and resuming briefly only when querying a service. This results in minimal payment for actual service usage. The activation fee extension addresses this attack. When enabled, the stream MUST accrue a fixed activation fee immediately upon entering ACTIVE state. -The fee applies to stream creation, resume, and top-up operations. -Note that only user actions transition a stream to ACTIVE state. +The fee applies to stream creation, resume, and top-up operations, +as only user actions transition a stream to ACTIVE state. The activation fee SHOULD reflect the minimum acceptable payment for a service session. @@ -346,14 +338,14 @@ by refusing service to users who pause and resume excessively. This section captures implementation questions: -- Mapping streams to NSSA: -How does the stream protocol map onto Nescience architecture? +- Mapping streams to LSSA: + How does the stream protocol map onto LSSA? - Timestamp-based accrual calculation: -Can shielded execution access block timestamps -to calculate accrued amounts based on elapsed time? + Can shielded execution access block timestamps + to calculate accrued amounts based on elapsed time? - Encoding and enforcing state transitions: -How to encode and enforce state machine transition rules -for the stream lifecycle states? + How to encode and enforce state machine transition rules + for the stream lifecycle states? ## Security and Privacy Considerations @@ -361,16 +353,16 @@ This section captures security and privacy questions: - Can or should all protocol operations be within shielded execution? - If not, where is the boundary -between transparent and shielded execution? + between transparent and shielded execution? - Who decides whether to use transparent or shielded execution: -user, provider, both, or fixed by protocol design? + user, provider, both, or fixed by protocol design? - What data is stored in the user's account -and who can see it in transparent vs shielded execution? + and who can see it in transparent vs shielded execution? - How to ensure external observers cannot correlate -streams from the same vault across different providers? + streams from the same vault across different providers? - How to ensure providers cannot see -streams from the same user to other providers, -while still being able to verify balance constraints? + streams from the same user to other providers, + while still being able to verify balance constraints? ## Copyright @@ -383,7 +375,7 @@ Copyright and related rights waived via [CC0](https://creativecommons.org/public #### Related Work - [Off-Chain Payment Protocols: Classification and Architectural Choice](https://forum.vac.dev/t/off-chain-payment-protocols-classification-and-architectural-choice/596) -- [Nescience: A User-Centric State-Separation Architecture](https://vac.dev/rlog/Nescience-state-separation-architecture) +- [LSSA](https://github.com/logos-blockchain/lssa) #### Payment Streaming Protocols From 4b22b2f8398d129b62bef8480eb23c3669305ed0 Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Fri, 19 Dec 2025 12:49:51 +0100 Subject: [PATCH 11/22] add appendix on illustrative EVM implementation --- vac/raw/payment-streams.md | 90 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index 26805735f..ad5c8083e 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -396,3 +396,93 @@ allow one deposit to back multiple streams. - [Sablier Lockup](https://github.com/sablier-labs/lockup) - [LlamaPay V2](https://github.com/LlamaPay/llamapay-v2) - [Superfluid Protocol](https://github.com/superfluid-org/protocol-monorepo) + +## Appendix A: Illustrative EVM Implementation + +This appendix provides an illustrative EVM-based implementation outline. +The actual implementation will target Logos with LSSA. + +### A.1 Contract Structure + +```solidity +contract PaymentVault { + enum StreamState { ACTIVE, PAUSED, CLOSED } + + struct Stream { + address token; + address provider; + uint128 ratePerSecond; + uint128 allocation; + uint64 lastUpdatedAt; + uint128 accruedBalance; + StreamState state; + } + + address public user; + mapping(address token => uint256) public vaultBalance; + uint256 public nextStreamId; + mapping(uint256 => Stream) public streams; +} +``` + +### A.2 Vault Operations + +```solidity +event Deposited(address indexed token, uint256 amount); +event Withdrawn(address indexed token, uint256 amount, address indexed to); + +function deposit(address token, uint256 amount) external; +function withdraw(address token, uint256 amount, address to) external; +``` + +### A.3 Stream Lifecycle + +```solidity +event StreamCreated( + uint256 indexed streamId, + address indexed provider, + address indexed token, + uint128 ratePerSecond, + uint128 allocation +); +event StreamPaused(uint256 indexed streamId); +event StreamResumed(uint256 indexed streamId); +event StreamToppedUp(uint256 indexed streamId, uint128 additionalAllocation); +event StreamClosed(uint256 indexed streamId, uint128 refundedToVault); +event Claimed(uint256 indexed streamId, address indexed provider, uint128 amount); + +/// @notice Create a new stream in ACTIVE state (user only) +function createStream( + address provider, + address token, + uint128 ratePerSecond, + uint128 allocation +) external returns (uint256 streamId); + +/// @notice Pause an ACTIVE stream (user only) +function pauseStream(uint256 streamId) external; + +/// @notice Resume a PAUSED stream (user only) +function resumeStream(uint256 streamId) external; + +/// @notice Add funds to stream allocation; transitions to ACTIVE (user only) +function topUpStream(uint256 streamId, uint128 additionalAllocation) external; + +/// @notice Close stream permanently; refunds unaccrued funds to vault +/// @dev Callable by user or provider +function closeStream(uint256 streamId) external; + +/// @notice Provider claims accrued funds from a stream +function claim(uint256 streamId) external; +``` + +### A.4 Internal Accrual + +```solidity +/// @notice Update accruedBalance based on elapsed time since lastUpdatedAt +/// @dev Called by pauseStream, topUpStream, closeStream, and claim +/// before modifying stream state. Caps accrual at allocation and +/// transitions to PAUSED when fully accrued (lazy evaluation: +/// state updates on next interaction, not at exact depletion time). +function _accrue(uint256 streamId) internal; +``` From af477499c58768b87b25cf8b46878b6f15602f01 Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Tue, 23 Dec 2025 13:06:11 +0100 Subject: [PATCH 12/22] add stream load cap --- vac/raw/payment-streams.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index ad5c8083e..60f986bae 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -224,6 +224,7 @@ This message MUST include: - status: ACCEPTED or REJECTED - reason: explanation if rejected (OPTIONAL) +- load_cap: maximum load the provider will serve (REQUIRED if ACCEPTED) If accepted, the user creates the stream on-chain. Acceptance commits the provider to deliver the specified service @@ -334,6 +335,26 @@ the attack becomes economically unviable. Providers MAY alternatively address this attack via off-chain policy by refusing service to users who pause and resume excessively. +### Load Cap + +The provider MAY advertise a load cap +(requests per unit time or another service-dependent metric) +representing the maximum load the provider is willing to serve. +A separate discovery protocol SHOULD enable providers +to advertise their load caps (out of scope for this spec). + +When responding to StreamRequest with ACCEPTED status, +the provider MUST include the load cap in StreamResponse. +The user MUST NOT exceed the load cap. + +If the user exceeds the load cap during stream operation, +the provider SHOULD terminate service. +The provider MUST send a ServiceTermination message +before closing the stream on-chain. + +A user who requires a higher load cap +SHOULD open multiple streams to the same provider. + ## Implementation Considerations This section captures implementation questions: From 0323cd9c7fa36793fbdd09bb9c72992470cdaf62 Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Mon, 2 Feb 2026 14:52:15 +0100 Subject: [PATCH 13/22] Apply suggestion from @jm-clius Co-authored-by: Hanno Cornelius <68783915+jm-clius@users.noreply.github.com> --- vac/raw/payment-streams.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index 60f986bae..800ebf279 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -3,7 +3,7 @@ title: PAYMENT-STREAMS name: Payment Streams Protocol for Logos Services status: raw category: Standards Track -tags: logos, lssa, payment-streams +tags: logos, lee, payment-streams editor: Sergei Tikhomirov contributors: Akhil Peddireddy --- From e8c91dd96f17f908040b6cd0cc6e28bf0a5f11de Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Mon, 2 Feb 2026 15:41:58 +0100 Subject: [PATCH 14/22] Apply suggestions from code review --- vac/raw/payment-streams.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index 800ebf279..607175457 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -53,7 +53,7 @@ We target the following requirements: - Performance: Efficient payments with low latency and fees. - Security: Limited loss exposure through spending controls. -- Privacy: Unlinkable payments across different providers. +- Privacy: On-chain deposit identity unlinkable to off-chain service requests. - Extendability: Simple initial design with room for enhancements. After reviewing prior work on payment channels, streams, @@ -202,7 +202,7 @@ Users MAY pause or close streams without prior notice. Providers SHOULD track on-chain state for their streams. If the provider stops serving the user, -the provider MUST notify the user off-chain +the provider SHOULD notify the user off-chain before closing the stream on-chain. ### Message Types @@ -213,7 +213,7 @@ StreamRequest: The user sends a StreamRequest to initiate a stream. This message MUST include: -- service_type: identifier of the requested service +- service_id: identifier of the requested service - stream_rate: proposed accrual rate (tokens per time unit) - stream_allocation: proposed initial allocation - public_key: key for signing subsequent service requests From 07be0fcce42dbd96e43446d64a4c13cea29b2735 Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Tue, 3 Feb 2026 20:25:45 +0100 Subject: [PATCH 15/22] edit spec, remove duplication --- vac/raw/payment-streams.md | 56 ++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index 607175457..cfaa6c54d 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -201,10 +201,6 @@ and enables service delivery. Users MAY pause or close streams without prior notice. Providers SHOULD track on-chain state for their streams. -If the provider stops serving the user, -the provider SHOULD notify the user off-chain -before closing the stream on-chain. - ### Message Types #### Stream Establishment @@ -229,8 +225,8 @@ This message MUST include: If accepted, the user creates the stream on-chain. Acceptance commits the provider to deliver the specified service while payment accrues at the agreed rate. -The provider MAY later terminate service -but MUST send a ServiceTermination message first. +The provider MAY terminate service prematurely +(see Service Termination). #### Service Request @@ -241,17 +237,13 @@ Each request MUST include: - request_data: service-specific payload - signature: signature over request_data using the committed public key -The signature proves the request originates from the stream owner. -The provider tracks on-chain state to verify the stream remains active. - -This design assumes the underlying blockchain provides funding privacy. -Stream creation MUST NOT reveal which vault funded the stream. -Vault deposits MUST NOT reveal the depositor's identity. +The signature proves the request is paid for by the respective stream. +The provider SHOULD verify on-chain that the stream remains active. #### Service Termination ServiceTermination: -The provider sends this message when stopping service. +The provider SHOULD send this message before stopping service. This message MUST include: - termination_type: TEMPORARY or PERMANENT @@ -321,16 +313,16 @@ by keeping a stream paused and resuming briefly only when querying a service. This results in minimal payment for actual service usage. -The activation fee extension addresses this attack. -When enabled, the stream MUST accrue a fixed activation fee -immediately upon entering ACTIVE state. -The fee applies to stream creation, resume, and top-up operations, -as only user actions transition a stream to ACTIVE state. - +Activation fee addresses this attack. +When activation fee is enabled, +a fixed amount MUST accrue to the provider +immediately upon the stream becoming ACTIVE. The activation fee SHOULD reflect the minimum acceptable payment for a service session. -If the fee exceeds the value of a single query, -the attack becomes economically unviable. +The activation fee applies to stream creation, resume, and top-up operations, +as only user actions transition a stream to ACTIVE state. +If stream allocation is lower than activation fee, +stream activation MUST fail. Providers MAY alternatively address this attack via off-chain policy by refusing service to users who pause and resume excessively. @@ -348,9 +340,7 @@ the provider MUST include the load cap in StreamResponse. The user MUST NOT exceed the load cap. If the user exceeds the load cap during stream operation, -the provider SHOULD terminate service. -The provider MUST send a ServiceTermination message -before closing the stream on-chain. +the provider SHOULD terminate service (see Service Termination). A user who requires a higher load cap SHOULD open multiple streams to the same provider. @@ -368,8 +358,6 @@ This section captures implementation questions: How to encode and enforce state machine transition rules for the stream lifecycle states? -## Security and Privacy Considerations - This section captures security and privacy questions: - Can or should all protocol operations be within shielded execution? @@ -385,6 +373,22 @@ This section captures security and privacy questions: streams from the same user to other providers, while still being able to verify balance constraints? + +## Security and Privacy Considerations + +Our initial privacy goal is unlinkability +between off-chain requests and on-chain funding. +Vault deposits MUST NOT reveal the depositor's identity. +Stream creation SHOULD NOT reveal which vault funded the stream. + +Under LSSA mechanics, +it is the user (stream creator) who decides +whether a stream operates under transparent or shielded execution. +This MAY imply maintaining stream state as part of public state. +In any case, on-chain state of a stream +MUST be verifiable by both parties. + + ## Copyright Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From cb8a539dcf91e9fef5577edc00746c9098274187 Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Tue, 3 Feb 2026 20:53:44 +0100 Subject: [PATCH 16/22] expand implementation considerations; LEZ --- vac/raw/payment-streams.md | 82 +++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 46 deletions(-) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index cfaa6c54d..51ffcf349 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -3,7 +3,7 @@ title: PAYMENT-STREAMS name: Payment Streams Protocol for Logos Services status: raw category: Standards Track -tags: logos, lee, payment-streams +tags: logos, lez, payment-streams editor: Sergei Tikhomirov contributors: Akhil Peddireddy --- @@ -18,7 +18,7 @@ where a payer's deposit releases gradually to a payee. The blockchain determines fund accrual based on elapsed time. The protocol targets Logos blockchain, -which uses the Logos State-Separation Architecture (LSSA). +which includes the Logos Execution Zone (LEZ). This document clarifies MVP requirements and facilitates discussion with Logos developers on implementation feasibility and challenges. @@ -44,9 +44,9 @@ with both P2P and request-response structures. The backbone P2P protocols use tit-for-tat mechanisms. We plan to introduce incentivization for auxiliary request-response protocols -where client and server roles are well defined. +with well-defined user and provider roles. One such protocol is Store, -which allows clients to query historical messages +which allows users to query historical messages from Logos Messaging relay nodes. We target the following requirements: @@ -73,21 +73,20 @@ improving resilience and privacy. Different service patterns suit different payment mechanisms. Ongoing services align well with streams that provide time-based automatic fund accrual. -One-time or on-demand services are better suited -for payment channels with one-off payments. +One-time or on-demand services suit +payment channels with one-off payments. This specification targets streams for services with steady usage patterns. Addressing burst services with one-off payments remains future work. -Logos blockchain uses the Logos State-Separation Architecture (LSSA), +Logos blockchain uses the Logos Execution Zone (LEZ), which enables both transparent and shielded execution. -LSSA is a natural fit +LEZ is a natural fit for the on-chain component of the payment protocol. -This document provides clarity on MVP requirements -and facilitates discussion with Logos developers on: +This document facilitates discussion with Logos developers on whether the required functionality can be implemented, which parts are most challenging and how to simplify them, and other implementation considerations. @@ -157,7 +156,7 @@ Stream state transitions: from any non-CLOSED state. When a stream is closed, unaccrued funds MUST automatically return to the user's vault. - Accrued funds remain available for provider to claim. + Accrued funds remain available for the provider to claim. - Claim: Provider MAY claim accrued funds from a stream in any state. A claim operation does not change stream state. @@ -237,7 +236,7 @@ Each request MUST include: - request_data: service-specific payload - signature: signature over request_data using the committed public key -The signature proves the request is paid for by the respective stream. +The signature links the request to the paying stream. The provider SHOULD verify on-chain that the stream remains active. #### Service Termination @@ -303,7 +302,7 @@ However, auto-claim has potential issues: - Requires user to pay for provider's claim operation. - May cause the entire close operation to fail if claim fails. -Assessing these trade-offs requires clarity on LSSA, +Assessing these trade-offs requires clarity on LEZ, particularly gas model, batching techniques, and timing privacy. ### Activation Fee @@ -347,32 +346,22 @@ SHOULD open multiple streams to the same provider. ## Implementation Considerations -This section captures implementation questions: - -- Mapping streams to LSSA: - How does the stream protocol map onto LSSA? -- Timestamp-based accrual calculation: - Can shielded execution access block timestamps - to calculate accrued amounts based on elapsed time? -- Encoding and enforcing state transitions: - How to encode and enforce state machine transition rules - for the stream lifecycle states? - -This section captures security and privacy questions: - -- Can or should all protocol operations be within shielded execution? -- If not, where is the boundary - between transparent and shielded execution? -- Who decides whether to use transparent or shielded execution: - user, provider, both, or fixed by protocol design? -- What data is stored in the user's account - and who can see it in transparent vs shielded execution? -- How to ensure external observers cannot correlate - streams from the same vault across different providers? -- How to ensure providers cannot see - streams from the same user to other providers, - while still being able to verify balance constraints? +This section outlines how the protocol maps onto LEZ. +The stream protocol MAY be deployed as an LEZ program +with three account types: + +- StreamDefinition: stream parameters and status. +- VaultDefinition: list of streams backed by a vault, controlled by payer. +- VaultHolding: token account funded by payer, used to pay providers. + +Stream lifecycle rules and balance constraints +are encoded and enforced through program logic. + +Whether shielded execution can access block timestamps +for time-based accrual calculation is an open question. +Given a mechanism for elapsed time in shielded execution, +all protocol operations MAY be performed within shielded execution. ## Security and Privacy Considerations @@ -381,13 +370,14 @@ between off-chain requests and on-chain funding. Vault deposits MUST NOT reveal the depositor's identity. Stream creation SHOULD NOT reveal which vault funded the stream. -Under LSSA mechanics, -it is the user (stream creator) who decides -whether a stream operates under transparent or shielded execution. -This MAY imply maintaining stream state as part of public state. -In any case, on-chain state of a stream -MUST be verifiable by both parties. +Each account MAY be public or private, configured per-account. +The payer decides whether stream operations use +transparent or shielded execution. +The protocol design SHOULD NOT fix this decision. +A provider MAY reject stream requests +that do not match their privacy preferences. +On-chain state of a stream MUST be verifiable by both parties. ## Copyright @@ -400,7 +390,7 @@ Copyright and related rights waived via [CC0](https://creativecommons.org/public #### Related Work - [Off-Chain Payment Protocols: Classification and Architectural Choice](https://forum.vac.dev/t/off-chain-payment-protocols-classification-and-architectural-choice/596) -- [LSSA](https://github.com/logos-blockchain/lssa) +- [LSSA](https://github.com/logos-blockchain/lssa) (now called LEZ) #### Payment Streaming Protocols @@ -425,7 +415,7 @@ allow one deposit to back multiple streams. ## Appendix A: Illustrative EVM Implementation This appendix provides an illustrative EVM-based implementation outline. -The actual implementation will target Logos with LSSA. +The actual implementation will target LEZ. ### A.1 Contract Structure From bba3fc6a1663a609fd13978d6c42bf89aff10c6c Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Tue, 3 Feb 2026 21:10:13 +0100 Subject: [PATCH 17/22] clarify lazy on-chain state transitions --- vac/raw/payment-streams.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index 51ffcf349..83936dbef 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -358,6 +358,12 @@ with three account types: Stream lifecycle rules and balance constraints are encoded and enforced through program logic. +Stream state is evaluated lazily. +On-chain storage holds stream parameters, +but effective state depends on block timestamp at execution time. +State transitions (such as auto-pause) are reflected on-chain +only when an on-chain operation is executed. + Whether shielded execution can access block timestamps for time-based accrual calculation is an open question. Given a mechanism for elapsed time in shielded execution, From cc2f12afaa66deda190ebb2e679649b24c698354 Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Wed, 4 Feb 2026 11:35:11 +0100 Subject: [PATCH 18/22] clarify claim logic --- vac/raw/payment-streams.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index 83936dbef..209d8fd52 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -20,7 +20,7 @@ The blockchain determines fund accrual based on elapsed time. The protocol targets Logos blockchain, which includes the Logos Execution Zone (LEZ). This document clarifies MVP requirements -and facilitates discussion with Logos developers +and facilitates discussion with Logos blockchain and LEZ developers on implementation feasibility and challenges. ## Language @@ -126,6 +126,7 @@ The sum of all stream allocations MUST NOT exceed vault balance. A claim is the operation where the provider retrieves accrued funds from a stream. The provider MAY claim accrued funds from a stream in any state. +A claim MUST transfer the full accrued balance to the provider. ### Stream Lifecycle @@ -158,6 +159,8 @@ Stream state transitions: unaccrued funds MUST automatically return to the user's vault. Accrued funds remain available for the provider to claim. - Claim: Provider MAY claim accrued funds from a stream in any state. + A claim MUST transfer the full accrued balance; + partial claims are not supported. A claim operation does not change stream state. ### Stream State Transition Diagram @@ -473,6 +476,7 @@ event StreamClosed(uint256 indexed streamId, uint128 refundedToVault); event Claimed(uint256 indexed streamId, address indexed provider, uint128 amount); /// @notice Create a new stream in ACTIVE state (user only) +/// @dev MUST revert if allocation exceeds available vault balance function createStream( address provider, address token, @@ -484,16 +488,21 @@ function createStream( function pauseStream(uint256 streamId) external; /// @notice Resume a PAUSED stream (user only) +/// @dev MUST revert if remaining allocation (allocation - accruedBalance) is zero function resumeStream(uint256 streamId) external; /// @notice Add funds to stream allocation; transitions to ACTIVE (user only) +/// @dev MUST revert if additionalAllocation exceeds available vault balance function topUpStream(uint256 streamId, uint128 additionalAllocation) external; -/// @notice Close stream permanently; refunds unaccrued funds to vault -/// @dev Callable by user or provider +/// @notice Close stream permanently +/// @dev Callable by user or provider. Unaccrued funds (allocation - accruedBalance) +/// MUST be returned to vaultBalance. Accrued funds remain claimable by provider. function closeStream(uint256 streamId) external; /// @notice Provider claims accrued funds from a stream +/// @dev Callable in any state (ACTIVE, PAUSED, or CLOSED). +/// Transfers full accruedBalance to provider and resets it to zero. function claim(uint256 streamId) external; ``` @@ -501,7 +510,7 @@ function claim(uint256 streamId) external; ```solidity /// @notice Update accruedBalance based on elapsed time since lastUpdatedAt -/// @dev Called by pauseStream, topUpStream, closeStream, and claim +/// @dev Called by pauseStream, resumeStream, topUpStream, closeStream, and claim /// before modifying stream state. Caps accrual at allocation and /// transitions to PAUSED when fully accrued (lazy evaluation: /// state updates on next interaction, not at exact depletion time). From 30aef3cab3b7d55882eb4157f41d503a6d044d9d Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Fri, 6 Feb 2026 13:11:07 +0100 Subject: [PATCH 19/22] edit spec with better defined eligibility-proof types --- vac/raw/payment-streams.md | 293 ++++++++++++++++++++++++++++++------- 1 file changed, 241 insertions(+), 52 deletions(-) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index 209d8fd52..9cc45ce14 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -17,6 +17,14 @@ A payment stream is an off-chain protocol where a payer's deposit releases gradually to a payee. The blockchain determines fund accrual based on elapsed time. +This specification defines stream-backed eligibility proof types +for the incentivization framework +defined in the incentivization spec +(see [References](#references)). +The incentivization spec is defined +in the context of Logos Messaging request-response protocols. +This spec MAY be extended to non-Messaging services. + The protocol targets Logos blockchain, which includes the Logos Execution Zone (LEZ). This document clarifies MVP requirements @@ -177,8 +185,23 @@ graph LR; Parties MUST agree on stream parameters before creation. A separate discovery protocol SHOULD enable -providers to advertise services and expected payment, -or enable users and providers to negotiate parameters. +providers to advertise services and accepted payment terms. + +The provider SHOULD announce +accepted eligibility proof types and service parameters +via the discovery protocol. + +The following is an informal list of discoverable parameters +(to be formally defined in the context of the discovery spec): + +- accepted eligibility proof types +- accepted tokens +- required rate (tokens per time unit) +- minimum allocation +- required vault buffer percentage (RECOMMENDED default: 5%) +- load cap (cumulative resource limit per stream per time window) +- `VaultProof` response cap + (maximum response size for `VaultProof`-backed requests) Users SHOULD monitor service delivery and take action when providers stop delivering service. @@ -187,12 +210,12 @@ monitoring quality and pausing or closing streams is a reasonable expectation. Providers SHOULD monitor the stream on-chain -and SHOULD stop providing service when a stream is not ACTIVE. +and SHOULD stop providing service when a stream is not `ACTIVE`. ## Off-Chain Protocol This section describes off-chain communication -for stream establishment, service delivery, and closure. +for stream establishment, service delivery, and termination. ### Design Rationale @@ -200,63 +223,212 @@ On-chain state is the source of truth for fund allocation and accrual. Off-chain communication coordinates lifecycle events and enables service delivery. -Users MAY pause or close streams without prior notice. -Providers SHOULD track on-chain state for their streams. +This spec does not re-define the service provision protocol. +The incentivization spec (see [References](#references)) +defines the generic request-response framework +with `EligibilityProof` and `EligibilityStatus`. +This spec extends `EligibilityProof` +with two new types for stream-backed service provision, +defined in the following subsection. + +### Eligibility Proof Types + +The incentivization spec's `EligibilityProof` +is extended with two new optional fields: +`stream_proposal` and `stream_proof`. +These fields are mutually exclusive. +The first `ServiceRequest` MUST use `stream_proposal`; +its semantics: "I want to open a stream to you +with these parameters; +here is proof I have a vault to back it; +here is my first request." +All subsequent requests MUST use `stream_proof`. + +```protobuf +message EligibilityProof { + // existing, from incentivization spec + optional bytes proof_of_payment = 1; + // new, for stream-backed service provision + optional bytes stream_proposal = 2; + optional bytes stream_proof = 3; +} +``` + +#### StreamProposal + +```protobuf +message StreamProposal { + VaultProof vault_proof = 1; + StreamParams stream_params = 2; + bytes public_key = 3; // key for signing subsequent service requests +} +``` + +#### VaultProof + +A `VaultProof` proves that the user controls a vault +with sufficient unallocated funds +to back the proposed stream. + +```protobuf +message VaultProof { + bytes vault_id = 1; // on-chain identifier of the vault + bytes provider_id = 2; // target provider (prevents replay) + uint64 balance_commitment = 3; // asserted unallocated balance + bytes owner_signature = 4; // signature covering all fields above +} +``` + +The provider SHOULD verify on-chain +that the vault's unallocated balance is at least +`stream_allocation * (1 + buffer)`, +where `stream_allocation` is from the accompanying `StreamParams` +and `buffer` is the provider's required vault buffer percentage +(RECOMMENDED default: 5%). + +The user MAY issue `VaultProof`s to different providers +only if the sum of their promised allocations +does not exceed the vault's unallocated balance. + +#### StreamParams + +`StreamParams` contains proposed stream parameters. + +```protobuf +message StreamParams { + bytes service_id = 1; // identifier of the requested service + uint64 stream_rate = 2; // proposed accrual rate (tokens per time unit) + uint64 stream_allocation = 3; // proposed initial allocation + uint32 stream_establishment_timeout = 4; // seconds; RECOMMENDED default: 300 +} +``` + +#### StreamProof + +A `StreamProof` links a request to an active on-chain stream. + +```protobuf +message StreamProof { + bytes stream_id = 1; // on-chain identifier of the stream + bytes signature = 2; // signature over request_data using committed public_key +} +``` + +The provider SHOULD verify on-chain +that the stream is `ACTIVE`, +that the signature matches the committed `public_key`, +and that the stream parameters match +those originally proposed. ### Message Types -#### Stream Establishment +The off-chain protocol uses three message types: +`ServiceRequest`, `ServiceResponse`, and `ServiceTermination`. -StreamRequest: -The user sends a StreamRequest to initiate a stream. -This message MUST include: +#### ServiceRequest -- service_id: identifier of the requested service -- stream_rate: proposed accrual rate (tokens per time unit) -- stream_allocation: proposed initial allocation -- public_key: key for signing subsequent service requests +A `ServiceRequest` has two top-level fields, +consistent with the incentivization spec pattern: -StreamResponse: -The provider responds with acceptance or rejection. -This message MUST include: +- `request_data`: service-specific payload +- `eligibility_proof`: an `EligibilityProof` + containing either a `stream_proposal` or a `stream_proof` + (see [Eligibility Proof Types](#eligibility-proof-types)) -- status: ACCEPTED or REJECTED -- reason: explanation if rejected (OPTIONAL) -- load_cap: maximum load the provider will serve (REQUIRED if ACCEPTED) +#### ServiceResponse -If accepted, the user creates the stream on-chain. -Acceptance commits the provider to deliver the specified service -while payment accrues at the agreed rate. -The provider MAY terminate service prematurely -(see Service Termination). +A `ServiceResponse` MUST include: -#### Service Request +- `eligibility_status`: an `EligibilityStatus` + (from the incentivization spec) with: + - `status_code`: indicating acceptance, + parameter rejection, proof invalidity, etc. + - `status_desc`: human-readable description + (RECOMMENDED to include actionable guidance + on parameter rejection) +- `response_data`: service-specific payload + (included if and only if the request is served) -ServiceRequest: -The user sends service requests during stream operation. -Each request MUST include: +Status codes specific to this spec: -- request_data: service-specific payload -- signature: signature over request_data using the committed public key +- `OK`: request served +- `PARAMS_REJECTED`: stream parameters unacceptable; + `VaultProof` NOT marked as spent; + user MAY retry with adjusted parameters +- `PROOF_INVALID`: `VaultProof` or `StreamProof` verification failed +- `STREAM_NOT_ACTIVE`: referenced stream + is no longer active on-chain -The signature links the request to the paying stream. -The provider SHOULD verify on-chain that the stream remains active. +The provider SHOULD limit parameter-rejection retries +to a RECOMMENDED maximum of 5 per vault +within a RECOMMENDED time window of 600 seconds. -#### Service Termination +#### ServiceTermination + +The provider SHOULD send a `ServiceTermination` message +before stopping service. +A `ServiceTermination` message MAY be sent regardless of whether +a stream has been established on-chain. -ServiceTermination: -The provider SHOULD send this message before stopping service. This message MUST include: -- termination_type: TEMPORARY or PERMANENT -- resume_after: timestamp after which service MAY resume - (REQUIRED for TEMPORARY, empty for PERMANENT) +- `termination_type`: `TEMPORARY` or `PERMANENT` +- `resume_after`: timestamp after which service MAY resume + (REQUIRED for `TEMPORARY`, empty for `PERMANENT`) For temporary termination, -the user MAY pause the stream until the resume_after time. +the user MAY pause the stream until the `resume_after` time. For permanent termination, the user SHOULD close the stream to recover unaccrued funds. +### Protocol Flow + +1. The user discovers a provider via the discovery protocol. + The provider's advertisement includes + accepted eligibility types and service parameters. + +2. The user sends the first `ServiceRequest` + with `eligibility_proof` containing a `StreamProposal` + (`VaultProof` + `StreamParams` + `public_key`) + and `request_data`. + +3. The provider verifies `VaultProof` on-chain + and evaluates `StreamParams`: + + - If parameters are unacceptable: + the provider responds with `PARAMS_REJECTED`. + The `VaultProof` is not marked as spent. + The user MAY retry with adjusted `StreamParams`. + - If the proof is invalid: + the provider responds with `PROOF_INVALID`. + - If accepted: + the provider serves the request immediately, + responding with `OK` and `response_data`. + The provider notes the pending session. + The provider SHOULD limit this response + to the advertised `VaultProof` response cap. + +4. The user creates the stream on-chain + within `stream_establishment_timeout`. + +5. The user sends subsequent `ServiceRequest`s + with `eligibility_proof` containing a `StreamProof`. + +6. If no `StreamProof`-backed request arrives + within `stream_establishment_timeout`, + the provider MAY discard the pending session + and release planned capacity. + +A user MUST NOT have more than one pending +`StreamProposal`-backed session per vault-provider pair at a time. +To open multiple streams to the same provider, +the user MUST complete each stream establishment +before initiating the next. +If the vault is drained between `VaultProof` verification +and stream creation, this constitutes a protocol violation; +the provider SHOULD send a `ServiceTermination` +with `termination_type` `PERMANENT`. + ## Protocol Extensions This section describes optional modifications @@ -318,11 +490,11 @@ This results in minimal payment for actual service usage. Activation fee addresses this attack. When activation fee is enabled, a fixed amount MUST accrue to the provider -immediately upon the stream becoming ACTIVE. +immediately upon the stream becoming `ACTIVE`. The activation fee SHOULD reflect the minimum acceptable payment for a service session. The activation fee applies to stream creation, resume, and top-up operations, -as only user actions transition a stream to ACTIVE state. +as only user actions transition a stream to `ACTIVE` state. If stream allocation is lower than activation fee, stream activation MUST fail. @@ -331,22 +503,35 @@ by refusing service to users who pause and resume excessively. ### Load Cap -The provider MAY advertise a load cap -(requests per unit time or another service-dependent metric) -representing the maximum load the provider is willing to serve. -A separate discovery protocol SHOULD enable providers -to advertise their load caps (out of scope for this spec). +A load cap represents +cumulative resource consumption per stream per time window +(e.g. total bytes or requests per minute). +It applies to the entire stream session, +not to individual responses. +The provider SHOULD advertise the load cap +via the discovery protocol. -When responding to StreamRequest with ACCEPTED status, -the provider MUST include the load cap in StreamResponse. -The user MUST NOT exceed the load cap. +For `VaultProof`-backed requests (the first `ServiceRequest`), +the provider SHOULD advertise a separate `VaultProof` response cap: +the maximum response size for a single `VaultProof`-backed response. +This limits provider exposure +to requests not yet backed by an on-chain stream. -If the user exceeds the load cap during stream operation, -the provider SHOULD terminate service (see Service Termination). +The user MUST NOT exceed the applicable cap. +If the user exceeds it, +the provider SHOULD terminate service. A user who requires a higher load cap SHOULD open multiple streams to the same provider. +### Multi-round Stream Parameter Negotiation + +A future extension MAY allow the provider +to include counter-proposed parameters +in a `PARAMS_REJECTED` response, +enabling iterative negotiation +before the first request is served. + ## Implementation Considerations This section outlines how the protocol maps onto LEZ. @@ -394,6 +579,10 @@ Copyright and related rights waived via [CC0](https://creativecommons.org/public ## References +### Normative + +- [Incentivization for Waku Light Protocols](https://github.com/logos-messaging/specs/blob/master/standards/core/incentivization.md) + ### Informative #### Related Work From 1d4731cb3288689b97268410cf03b35494cbc2ff Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Tue, 24 Feb 2026 15:19:58 +0100 Subject: [PATCH 20/22] clarify stream establishment timeout logic --- vac/raw/payment-streams.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index 9cc45ce14..5309a26b0 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -202,6 +202,9 @@ The following is an informal list of discoverable parameters - load cap (cumulative resource limit per stream per time window) - `VaultProof` response cap (maximum response size for `VaultProof`-backed requests) +- `max_open_stream_window` (RECOMMENDED default: 300 seconds) + (maximum acceptable duration + between receiving a `StreamProposal` and stream establishment) Users SHOULD monitor service delivery and take action when providers stop delivering service. @@ -299,10 +302,15 @@ message StreamParams { bytes service_id = 1; // identifier of the requested service uint64 stream_rate = 2; // proposed accrual rate (tokens per time unit) uint64 stream_allocation = 3; // proposed initial allocation - uint32 stream_establishment_timeout = 4; // seconds; RECOMMENDED default: 300 + uint64 open_stream_by = 4; // stream establishment deadline (absolute timestamp) } ``` +The `open_stream_by` field is an absolute timestamp +by which the user commits to establishing the stream on-chain. +The user MUST set `open_stream_by` to a future timestamp +no later than the current time plus `max_open_stream_window`. + #### StreamProof A `StreamProof` links a request to an active on-chain stream. @@ -409,15 +417,18 @@ the user SHOULD close the stream to recover unaccrued funds. to the advertised `VaultProof` response cap. 4. The user creates the stream on-chain - within `stream_establishment_timeout`. + before `open_stream_by`. 5. The user sends subsequent `ServiceRequest`s with `eligibility_proof` containing a `StreamProof`. -6. If no `StreamProof`-backed request arrives - within `stream_establishment_timeout`, - the provider MAY discard the pending session +6. The provider monitors the chain for a matching stream. + If no matching stream appears by `open_stream_by`, + the provider SHOULD discard the session and release planned capacity. + If the stream is established before `open_stream_by`, + the first `StreamProof`-backed request + MAY arrive after `open_stream_by`. A user MUST NOT have more than one pending `StreamProposal`-backed session per vault-provider pair at a time. From 233c0e4e320f81386e24a49a3e8fcbde39aec2d1 Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Tue, 24 Feb 2026 15:26:32 +0100 Subject: [PATCH 21/22] clarify vaultproof conditions --- vac/raw/payment-streams.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index 5309a26b0..17a43242e 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -289,9 +289,11 @@ where `stream_allocation` is from the accompanying `StreamParams` and `buffer` is the provider's required vault buffer percentage (RECOMMENDED default: 5%). -The user MAY issue `VaultProof`s to different providers -only if the sum of their promised allocations -does not exceed the vault's unallocated balance. +The user MAY issue `VaultProof`s to multiple providers. +The user MUST ensure that issuing a new `VaultProof` +does not cause the total of all promised `VaultProof` allocations +from this vault +to exceed the vault's unallocated balance. #### StreamParams From aab3346a77bc8537790e04c8206f2a40c516fac5 Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Tue, 24 Feb 2026 15:34:31 +0100 Subject: [PATCH 22/22] minor edits --- vac/raw/payment-streams.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vac/raw/payment-streams.md b/vac/raw/payment-streams.md index 17a43242e..a4693c3a5 100644 --- a/vac/raw/payment-streams.md +++ b/vac/raw/payment-streams.md @@ -129,7 +129,7 @@ the user MUST allocate a portion of vault funds to that stream. Each stream MUST belong to exactly one vault. Each stream MUST specify an accrual rate (tokens per time unit). An allocation is the portion of vault funds committed to a stream. -The sum of all stream allocations MUST NOT exceed vault balance. +The sum of all stream allocations MUST NOT exceed the vault balance. A claim is the operation where the provider retrieves accrued funds from a stream. @@ -226,7 +226,7 @@ On-chain state is the source of truth for fund allocation and accrual. Off-chain communication coordinates lifecycle events and enables service delivery. -This spec does not re-define the service provision protocol. +This spec does not redefine the service provision protocol. The incentivization spec (see [References](#references)) defines the generic request-response framework with `EligibilityProof` and `EligibilityStatus`. @@ -500,8 +500,8 @@ by keeping a stream paused and resuming briefly only when querying a service. This results in minimal payment for actual service usage. -Activation fee addresses this attack. -When activation fee is enabled, +The activation fee addresses this attack. +When the activation fee is enabled, a fixed amount MUST accrue to the provider immediately upon the stream becoming `ACTIVE`. The activation fee SHOULD reflect @@ -561,7 +561,7 @@ are encoded and enforced through program logic. Stream state is evaluated lazily. On-chain storage holds stream parameters, -but effective state depends on block timestamp at execution time. +but the effective state depends on the block timestamp at execution time. State transitions (such as auto-pause) are reflected on-chain only when an on-chain operation is executed.