rfc: simplified community vouchers (#6498)

* rfc: simplified community vouchers

* update
This commit is contained in:
Evgeny
2025-12-29 20:47:13 +00:00
committed by GitHub
parent fe4ff8993d
commit c9137cb015
+98
View File
@@ -0,0 +1,98 @@
# Community Vouchers contract
This document simplifies [the previous RFC](./2025-10-23-vouchers.md) in two ways:
- only one type of credits (previous design had conversion from community to operator credits).
- vouchers can support any amount and change.
- using a single fixed-size Merkle tree for vouchers.
- proposal for balancing privacy and the size of the tree that the client has to load.
## Objectives
- voucher expiration - fixed period per contract.
- make assignment of voucher to redeemer (a community) private, not allowing further transactions/re-assignments.
- vouchers support any amount.
- allow assigning and redeeming part of the voucher, with change.
## Design proposal
### General ideas
- Voucher is issued by the smart contract in exchange for stable-coin deposit, and recorded as blinded commitment added to Merkle tree.
- Voucher is nominated in infrastructure credits with 18 decimals, as all ETH tokens.
- Voucher assignments and redemptions (partial or full) are done via zero-knowledge proof and recorded as nullifier to prevent double spends, with the new commitment for the remaining amount and transaction count (can be 0).
- Commitment includes:
- the amount.
- the whether the voucher is assigned.
- the expiration time.
- Merkle tree of commitments has a fixed depth of say 20-40 levels (for approx 10^6-10^12 voucher capacity).
- Assignments and redemptions should prove consistency between the old and new commitments, without revealing them, and include the nullifier to prevent "double spends".
- Redemptions also include the blockchain address and ID of the operator.
- Release of funds with revenue sharing can be done via call to another contract.
### Data storage
Smart contract:
- total deposit amounts bucketed by time ranges (to allow the release of funds to network after expiration).
- redemption amounts bucketed by time ranges with homomorphic encryption (to prevent reduction of anonymity set).
- nullifiers bucketed by creation time (to allow removing old nullifiers).
- the path in the Merkle tree on "the front" of the filled part of the tree.
- multiple last Merkle tree roots:
- to accept the proof after the root changes.
- to frustrate timing correlation by computing proofs in advance (for better usability).
Transaction event log:
- Merkle tree of commitments are recorded in event log
### Voucher lifecycle
1. Issuance: blinded commitment recorded as described above in exchange for stablecoin deposit.
The contract should be able to verify that:
- commitment amount is the same as deposit amount.
- expiration time is in 12 months from now (possibly rounded up to 1-3 months).
- not assigned to redeemer.
Initially, the deposit UX could be dApp generating some token to be used in the app to assign voucher to the community via app (to preserve privacy).
2. Computing zero-knowledge proof for assignment or redemption.
To compute the proof the client needs to have a path from commitment to tree root.
As the path to commitment changes when the tree gets filled, we need to find a balance between privacy and usability - to request as little as possible and have as large anonymity set as possible.
3. Assignment.
Includes 2 new commitments (to destination and a "change") and nullifier are submitted.
ZK proof should prove that:
- the old commitment expiration time is greater than transaction submission time (possibly has to be included in parameters to be part of the proof).
- the total amount of 2 new commitments is the same as the amount of nullified old commitment.
- the new commitments expiration time is the same as the old.
- the old commitment is not assigned to redeemer.
- the new commitments is assigned to redeemer.
Questions:
1) how would the redeemer know that it received a voucher? Probably, community owners would be notified by chat relays.
2) do we want to conceal from the relays when and to which group donation was made? If yes, community owners can monitor blockchain themselves.
3) can we have view keys to delegate the detection of incoming transactions to relays?
4) should we round expiration time to a month or even 3 months? (to avoid exposing expiration time to the assignment recipient, as it also leaks purchase time) If so, we should also have overlapping rounding ranges to avoid leaking purchase time in case it is assigned straight after purchase, and straight after range change.
4. Redemption.
Includes one new commitment (with the change) and public record of funds released to operator and network.
The revenues received by the operators are publicly visible.
ZK proof should prove that:
- the old commitment expiration time is greater than transaction submission time.
- the total amount of the new commitment and of released funds is the same as the amount of nullified commitment.
- the new commitment expiration time is the same as the old.
- the old commitment is assigned to the redeemer that redeems the voucher.
- the new commitment has the same assignment.
5. Releasing deposits for expired vouchers to the network.
That would require tracking purchases in buckets (in the clear) and redemptions in homomorphicly encrypted structure, so an observer cannot correlate redemptions to purchases (as the same structure will change, and it won't be possible to establish which bucket).