|
| 1 | +--- |
| 2 | +SPDX-License-Identifier: Apache-2.0 |
| 3 | +copyright: This file is part of midnight-docs. Copyright (C) 2026 Midnight Foundation. Licensed under the Apache License, Version 2.0 (the "License"); You may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. |
| 4 | +sidebar_label: "Private Guest List" |
| 5 | +sidebar_position: 2 |
| 6 | +title: Private Guest List Contract |
| 7 | +description: Example contract |
| 8 | +toc_max_heading_level: 2 |
| 9 | +--- |
| 10 | + |
| 11 | +This Compact contract implements a party with a private guest list. It offers demonstration of the following features: |
| 12 | +- Hiding information on the public ledger |
| 13 | +- Verifying hidden ledger information |
| 14 | +- Access control to circuits |
| 15 | +- Operations on a `Set` |
| 16 | +- Introduction to witness functions |
| 17 | + |
| 18 | +```compact |
| 19 | +pragma language_version 0.21; |
| 20 | +import CompactStandardLibrary; |
| 21 | +
|
| 22 | +export enum PartyState { |
| 23 | + NOT_READY, |
| 24 | + READY |
| 25 | +} |
| 26 | +
|
| 27 | +export ledger organizers: Set<ZswapCoinPublicKey>;// organizers are public |
| 28 | +export ledger hashedPartyGoers: Set<Bytes<32>>;// participants are hashed until they arrive |
| 29 | +export ledger checkedInParty: Set<Bytes<32>>; |
| 30 | +export ledger partyState: PartyState; |
| 31 | +export ledger maxListSize: Uint<8>; |
| 32 | +
|
| 33 | +witness localStartParty(): PartyState; |
| 34 | +
|
| 35 | +constructor(){ |
| 36 | + // the publicKey of the caller of this function |
| 37 | + organizers.insert(ownPublicKey()); |
| 38 | + partyState = PartyState.NOT_READY; |
| 39 | + maxListSize = 99; |
| 40 | +} |
| 41 | +
|
| 42 | +export circuit addOrganizer(newOrganizer: ZswapCoinPublicKey): [] { |
| 43 | + assert(organizers.member(ownPublicKey()), "You are not an organizer"); |
| 44 | + assert(!organizers.member(disclose(newOrganizer)), "You are already in the organizer list"); |
| 45 | + assert(partyState == PartyState.NOT_READY, "The party has already started"); |
| 46 | + |
| 47 | + organizers.insert(disclose(newOrganizer)); |
| 48 | +} |
| 49 | +
|
| 50 | +export circuit addParticipant(_participantPk: Bytes<32>, _organizerSk: Bytes<32>): [] { |
| 51 | + // only organizers can add party goers |
| 52 | + assert(organizers.member(ownPublicKey()), "You are not an organizer"); |
| 53 | + assert(partyState == PartyState.NOT_READY, "The party has already started"); |
| 54 | + assert(hashedPartyGoers.size() < maxListSize, "The list is full"); |
| 55 | +
|
| 56 | + const participant = commitWithSk(_participantPk, _organizerSk); |
| 57 | + assert(!hashedPartyGoers.member(disclose(participant)), "You are already in the list"); |
| 58 | + hashedPartyGoers.insert(disclose(participant)); |
| 59 | +
|
| 60 | + if (hashedPartyGoers.size() == maxListSize) { |
| 61 | + const localPartyState = localStartParty(); |
| 62 | + // don't trust, verify |
| 63 | + assert(localPartyState == PartyState.READY, "Please start the party, the list is full"); |
| 64 | + partyState = PartyState.READY; |
| 65 | + } |
| 66 | +} |
| 67 | +
|
| 68 | +export circuit checkIn(participantPk: Bytes<32>, _organizerSk: Bytes<32>): [] { |
| 69 | + assert(organizers.member(ownPublicKey()), "You are not an organizer"); |
| 70 | + assert(partyState == PartyState.READY, "The party has not started yet"); |
| 71 | + assert(checkedInParty.size() < hashedPartyGoers.size(), "All guests have already checked in"); |
| 72 | + assert(hashedPartyGoers.member(commitWithSk(participantPk, _organizerSk)), "You are not on the list"); |
| 73 | +
|
| 74 | + checkedInParty.insert(disclose(participantPk)); |
| 75 | +} |
| 76 | +
|
| 77 | +export circuit chainStartParty(): [] { |
| 78 | + assert(organizers.member(ownPublicKey()), "Only organizers can start the party"); |
| 79 | + assert(partyState == PartyState.NOT_READY, "The party has already started"); |
| 80 | +
|
| 81 | + const localPartyState = disclose(localStartParty()); |
| 82 | + assert(localPartyState == PartyState.READY, "Please start the party locally"); |
| 83 | + partyState = localPartyState; |
| 84 | +} |
| 85 | +
|
| 86 | +circuit commitWithSk(_participantPk: Bytes<32>, _sk: Bytes<32>): Bytes<32> { |
| 87 | + return disclose(persistentHash<Vector<2, Bytes<32>>>([_participantPk, _sk])); |
| 88 | +} |
| 89 | +``` |
0 commit comments