Abstract
This document proposes an MVP architecture for incentivizing Waku Store service provision
through a ZK-based ticket payment protocol.
The MVP focuses on core ticket mechanics with a single Service Provider operating six Service Nodes. The architecture implements a ticket-based payment system that prevents trivial fraud,
ensures unlinkability between payment and service provision, and supports batch ticket operations.
This proposal follows a recent Service Incentivisation MVP discussion and builds upon earlier work linked there.
Background
Waku uses request–response protocols like Store to extend its Relay backbone. This enables edge nodes (such as smartphones and browsers) to retrieve missed messages.
Currently, Status runs its own Store Service Nodes. The goal of the MVP is to integrate existing Service Nodes operated by Status as the Service Provider into a new ticket-based service protocol providing unlinkability.
The long-term goal is to extend the protocol to a decentralized marketplace of independent Service Providers. Required developments might include reputation systems, progressive trust mechanisms for Service Provider selection, dynamic pricing, and alternative payment mechanisms.
MVP Requirements and Assumptions
Requirements for the MVP:
- Security: Prevent trivial fraud; no catastrophic loss from a single session.
- Unlinkability: Break the link between payment and service provision.
- Bearer instruments: Possession of a ticket grants service access rights.
- Efficiency: Support for batch operations; no per-request on-chain transactions.
- Simplicity: Minimal protocol and contract surface for rapid iteration.
- Upgradeability: Clear path to improvements.
The MVP makes the following simplifying assumptions:
- Single Service Provider managing six known Service Nodes, therefore:
- no Provider deposits or slashing;
- no Provider discovery and selection mechanism.
- The Service Provider provides state sync with
TicketRegistry
for its Service Nodes. - Sponsor determines the expiry period for ticket commitments it funds.
- When Sponsor and User are separate entities, User must trust Sponsor to include correct expiry in funding transaction.
- Unit-of-service (UoS) defined as a single request-response interaction.
- Fixed pricing per UoS with no negotiation.
- Single gasless L2 chain deployment.
- Single ERC-20 token support.
The MVP focuses on proving the core ticket issuance, spending, and redemption mechanics
without reputation systems. It emphasizes simplicity and feasibility, while establishing an upgrade path to a decentralised marketplace.
Future development will involve a multi-Service Provider marketplace with reputation systems
and progressive trust mechanisms for Service Provider selection.
MVP Architecture
In this section, we describe a ZK-based ticket payment system, which is the central part of the MVP version of the Store incentivization protocol.
Terminology
This section establishes the vocabulary of the protocol actors and their interactions.
The terminology follows privacy literature conventions, avoids direct association with financial instruments, and clearly distinguishes human-managed entities from contracts (using Registry
suffix).
Objects
Ticket:
A random secret value representing one unit of service (UoS). A ticket is a bearer instrument:
it can be transferred off-chain between Users. A ticket is used to generate ticket commitments (for funding) and nullifiers (for spending).
Ticket commitment:
A cryptographic commitment to a ticket: commitment = hash(ticket_secret, blinding_factor)
. A ticket commitment may represent one ticket or a Merkle root of multiple tickets. The commitment is recorded on-chain in the TicketRegistry
contract.
Nullifier:
A unique provider-specific ticket spending identifier: nullifier = hash(ticket_secret, provider_id)
. A nullifier is revealed as part of an eligibility proof. A nullifier can be redeemed for cash in the TicketRegistry
contract exactly once. Redeemed nullifiers are tracked in the TicketRegistry
contract.
Eligibility proof:
A proof package submitted by a User to a Service Node alongside a request. An eligibility proof consists of a nullifier and a ZK proof demonstrating possession of a funded ticket. An eligibility proof is verified by a Service Node before serving a request.
ZK Proof Statement:
Public inputs: nullifier, ticket_commitment, provider_id, registry_merkle_root, block_number
Private inputs: ticket_secret, blinding_factor, merkle_path
Proof:
I possess ticket such that ticket_commitment = hash(ticket_secret, blinding_factor)
nullifier = hash(ticket_secret, provider_id)
ticket_commitment is included in registry_merkle_root via merkle_path
ticket_commitment was unspent as of block_number
Service request:
A request sent by a User to a Service Node that includes an eligibility proof.
Unit of service (UoS):
A response to a service request.
Actors
User:
An entity that consumes Waku Store services. The User generates ticket secrets, creates ticket commitments for funding, and attaches eligibility proofs to requests. Users may interact with any Service Nodes managed by a single Service Provider (MVP version). In future versions, Users select optimal Service Providers based on progressive trust assessment.
Sponsor:
An entity that funds ticket commitments received from Users by sending a funding transaction to TicketRegistry
. A Sponsor determines an expiry period for ticket commitments it funds. Sponsors may or may not be the same entity as the User.
Service Provider:
An entity that manages one or multiple Service Nodes. The Service Provider maintains blockchain connectivity, syncs TicketRegistry
state, and distributes state updates to all its Service Nodes. A Service Provider maintains a unified nullifier set across all its Service Nodes and provides real-time nullifier validation for them. A Service Provider handles batch redemption
of collected nullifiers through TicketRegistry
.
The following actors are out of scope:
network observers (ISPs); blockchain entry points (RPC Service Providers); and blockchain operating entities (block producers, miners, validators).
Infrastructure
Service Node:
A Waku node running the Store service and accepting requests from Users. Service Nodes are operated by a Service Provider that may manage multiple Service Nodes. Service Nodes delegate blockchain communication to their Service Provider. A Service Node verifies an eligibility proof as follows:
- verify ZK proofs against locally cached blockchain state;
- forward nullifiers to their Service Provider for double-spend prevention.
TicketRegistry
:
An on-chain contract that tracks funded ticket commitments, maintains spent nullifier sets to prevent double-spending, and pays Service Providers for valid nullifier redemptions. It also allows Sponsor reclamation of unused tickets after expiry.
ProviderRegistry
(post-MVP):
An on-chain contract that maintains a registry of Service Providers. Service Providers must lock up a deposit to join the protocol. The registry handles provider deposits and withdrawals, enforces withdrawal delays to prevent “scam-and-exit” behavior, implements slashing for systematic service failures, and presents observable on-chain metrics that enable Users to discover and compare Providers.
Protocol Diagrams
Flow Diagram
flowchart LR
User[User]
Sponsor[Sponsor]
TicketRegistry[TicketRegistry]
ServiceProvider[Service Provider]
ServiceNode[Service Node]
User -->|Funding request| Sponsor
Sponsor -->|Fund commitments| TicketRegistry
ServiceProvider <-.->|Sync state| TicketRegistry
ServiceProvider -.->|Distribute state| ServiceNode
User -->|Service request| ServiceNode
ServiceNode <-->|Double-spend nullifier check| ServiceProvider
ServiceNode -->|Service response| User
ServiceProvider <-.->|Redeem batch| TicketRegistry
Sponsor <-.->|Reclaim expired| TicketRegistry
Sequence Diagram
sequenceDiagram
autonumber
participant User
participant Sponsor
participant ServiceProvider
participant ServiceNode
participant TicketRegistry
Note over User: 1. Ticket Creation
User->>User: Generate ticket_secret(s)
User->>User: Compute ticket_commitment(s) (optionally Merkle root for batch funding)
Note over User,Sponsor: 2. Ticket Funding
User-->>Sponsor: Send ticket commitment
Sponsor->>TicketRegistry: fund(commitments, expiry)
TicketRegistry-->>Sponsor: Record commitments funded with expiry
Note over ServiceProvider,ServiceNode: 3. State Synchronization
ServiceProvider->>TicketRegistry: Sync funded commitments
TicketRegistry-->>ServiceProvider: registry_merkle_root
ServiceProvider->>ServiceNode: Distribute registry_merkle_root to all Service Nodes
Note over User,ServiceNode: 4. Service Request
User->>User: Construct eligibility proof (nullifier, ZK proof, registry_merkle_root)
User->>ServiceNode: Service request + eligibility proof
Note over ServiceNode,ServiceProvider: 5. Service Provision
ServiceNode->>ServiceNode: Verify ZK proof including Merkle inclusion and staleness window
ServiceNode->>ServiceProvider: Forward nullifier for double-spend check
ServiceProvider->>ServiceProvider: Check nullifier against unified set
ServiceProvider-->>ServiceNode: Accept or reject
alt Valid proof and nullifier accepted
ServiceNode-->>User: Serve requested data (UoS)
else Rejected
ServiceNode-->>User: Reject request
end
Note over ServiceProvider,TicketRegistry: 6. Redemption
ServiceProvider->>ServiceProvider: Collect accepted nullifiers and proofs
ServiceProvider->>TicketRegistry: redeemBatch(nullifiers, eligibility proofs)
TicketRegistry->>TicketRegistry: Verify proofs, check unspent, mark spent
TicketRegistry-->>ServiceProvider: Transfer payment
Note over Sponsor,TicketRegistry: After expiry, Sponsor may reclaim unused commitments
Sponsor->>TicketRegistry: reclaimExpired(commitments)
Protocol Flow
1. Ticket Creation
- User generates random ticket secrets;
- User computes a ticket commitment from ticket secrets (optionally as a Merkle root for batch funding).
2. Ticket Funding
- User sends a ticket commitment to Sponsor (off-chain);
- Sponsor determines the expiry period for the ticket commitment;
- Sponsor submits a funding transaction with ticket commitments and expiry period to
TicketRegistry
(on-chain); TicketRegistry
records ticket commitments as funded with specified expiry (supports batch operations).
3. State Synchronization
- Service Provider periodically synchronizes with
TicketRegistry
to obtain the latest Merkle root representing funded ticket commitments; - Service Provider distributes the latest Merkle root to all its Service Nodes;
- Service Nodes verify proofs against locally cached state with configurable staleness tolerance, while delegating nullifier double-spend checks to Service Provider for real-time coordination.
4. Service Request
- User generates an eligibility proof consisting of:
- nullifier (derived from ticket secret and Service Provider ID);
- ZK proof showing knowledge of ticket secret
and inclusion of ticket commitment in current Merkle root; - Reference to Merkle root used.
- User sends a service request to any Service Node
operated by trusted Service Provider,
attaching an eligibility proof.
5. Service Provision
- Service Node receives request and eligibility proof;
- Service Node verifies ZK proof, including Merkle inclusion and that referenced Merkle root is within acceptable staleness window;
- Service Node forwards nullifier to Service Provider for double-spend checking;
- Service Provider checks nullifier against unified set of previously seen nullifiers;
- Service Provider responds to Service Node with accept or reject decision;
- If both ZK proof is valid and Service Provider accepts nullifier, Service Node serves requested data to User.
6. Redemption
- Service Provider collects all nullifiers that have been accepted and served by its Service Nodes;
- At intervals, Service Provider submits a batch redemption transaction to
TicketRegistry
, including collected nullifiers and corresponding eligibility proofs; TicketRegistry
verifies eligibility proofs, checks nullifiers are unspent, marks them as spent,
and transfers payment to Service Provider for valid redemptions;- If any ticket commitments remain unused after Sponsor-determined expiry, Sponsor may reclaim them from
TicketRegistry
.
State Synchronization Analysis
State synchronization is required because eligibility proofs reference the current set of funded ticket commitments, which evolves as tickets are funded and redeemed in TicketRegistry
. Without synchronized state, Service Nodes cannot verify ticket validity and Users cannot generate valid proofs.
In the MVP, Service Nodes delegate nullifier management to their Service Provider while independently verifying cryptographic proofs. When Users make requests, they prove their ticket’s inclusion in the current state. Service Nodes accept proofs that reference recent Merkle roots, allowing some staleness while maintaining security.
The Service Provider syncs with the on-chain TicketRegistry
and distributes the latest Merkle root of funded tickets to all its Service Nodes. The Service Provider maintains unified nullifier tracking and handles real-time nullifier checks and batch on-chain settlement.
This approach provides:
- Service Node simplicity and operational efficiency;
- Unified double-spend prevention across all Service Nodes under the same Service Provider in a single-Provider model.
Alternatives Considered:
- Full blockchain sync at every Service Node would increase complexity and resource usage.
- Pure optimistic verification without cryptographic state proofs would provide weaker security.
- Decentralized state distribution would add coordination overhead.
Double Spending Trade-off
The architecture accepts double spending before nullifiers are redeemed on-chain. Strict prevention would require real-time blockchain synchronization, but Users are lightweight edge devices that should not track blockchain state or commit to specific Service Providers ahead of time.
The current design allows ticket commitments to be funded without reference to specific Service Providers.This provides flexibility for Sponsors to fund tickets in batches and for Users to choose Service Providers based on reputation and availability. Ticket nullifier commitment occurs at usage time, not funding time, enabling adaptation to changing Service Provider landscapes.
In a multi-Service Provider environment, a malicious User could use the same funded ticket to generate eligibility proofs for different Service Providers.
Service Providers can balance redemption timisng versus double spending exposure:
- Wait longer to accumulate nullifiers for batch redemption;
- Redeem immediately to minimize double-spend risk.
An alternative architecture would link ticket commitments to specific Service Providers at funding time, eliminating double spending risk but reducing flexibility.
Post-MVP Development
Multi-Provider Support with Reputation and Progressive Trust
The ProviderRegistry
contract maintains an on-chain registry of independent Service Providers.
Each Provider deposits funds demonstrating commitment to honest service provision. The ProviderRegistry
enforces withdrawal delays to prevent “scam-and-exit” behavior.
Providers operate within separate nullifier spaces. The TicketRegistry
provides global double-spend prevention via a global set of redeemed nullifiers. Double-spend attacks across different Providers are possible before the first nullifier redemption since nullifiers are tracked locally until redeemed on-chain.
Provider reputation is based on aggregate Service Node performance metrics. Slashing penalizes Providers for systematic failures.
Service Node Discovery and Progressive Trust
A Progressive Trust protocol allows Users to incrementally evaluate Service Providers based on on-chain reputation and local interaction history. Service Providers advertise their Service Nodes
with cryptographic ownership proofs. Providers sign and publish Service Node endpoints along with performance metrics for User discovery. Users select Service Providers based on their evaluation criteria, verify Service Provider signatures, and connect to the Service Nodes operated by their chosen Service Provider. Users gradually increase exposure based on successful interactions and rotate Service Providers when systematic failures occur.
Stronger Economic Incentives
Future economic improvements might also include:
- Price negotiation between Users and Service Providers;
- Demand-based dynamic pricing;
- Alternative payment mechanisms such as probabilistic micropayments or payment channels;
- Third-party monitoring with challenge-response mechanics.
Call for Feedback
We welcome community feedback on critical design decisions, for instance:
- Double-spend trade-offs between user flexibility and security;
- MVP scope balancing implementation feasibility with decentralization goals;
- Cryptographic model optimizing privacy, proof complexity, and verification efficiency;
- Economic assumptions and their impact on adoption.
We also welcome feedback on any other aspects of the architecture.