UNPKG

l1-lottery-contracts

Version:

This repo contains smart contracts and related scripts for ZkNoid L1 Lottery proposed [here](https://forums.minaprotocol.com/t/zknoid-l1-lottery/6269)

470 lines (469 loc) 17.9 kB
import { Field, SmartContract, State, UInt32, MerkleMapWitness, PublicKey, Provable, UInt64, VerificationKey, Bool } from 'o1js'; import { Ticket } from './Structs/Ticket.js'; import { MerkleMap20Witness } from './Structs/CustomMerkleMap.js'; import { LotteryAction, TicketReduceProof } from './Proofs/TicketReduceProof.js'; export interface MerkleCheckResult { key: Field; } export declare const mockResult: import("o1js/dist/node/lib/provable/field.js").Field; export declare const generateNumbersSeed: (seed: Field) => UInt32[]; declare const BuyTicketEvent_base: (new (value: { ticket: Ticket; }) => { ticket: Ticket; }) & { _isStruct: true; } & Omit<import("o1js/dist/node/lib/provable/types/provable-intf.js").Provable<{ ticket: Ticket; }, { ticket: { numbers: bigint[]; owner: { x: bigint; isOdd: boolean; }; amount: bigint; }; }>, "fromFields"> & { fromFields: (fields: import("o1js/dist/node/lib/provable/field.js").Field[]) => { ticket: Ticket; }; } & { fromValue: (value: { ticket: Ticket | { numbers: UInt32[] | bigint[]; owner: PublicKey | { x: Field | bigint; isOdd: Bool | boolean; }; amount: bigint | UInt64; }; }) => { ticket: Ticket; }; toInput: (x: { ticket: Ticket; }) => { fields?: Field[] | undefined; packed?: [Field, number][] | undefined; }; toJSON: (x: { ticket: Ticket; }) => { ticket: { numbers: string[]; owner: string; amount: string; }; }; fromJSON: (x: { ticket: { numbers: string[]; owner: string; amount: string; }; }) => { ticket: Ticket; }; empty: () => { ticket: Ticket; }; }; export declare class BuyTicketEvent extends BuyTicketEvent_base { } declare const ProduceResultEvent_base: (new (value: { result: import("o1js/dist/node/lib/provable/field.js").Field; totalScore: UInt64; bank: import("o1js/dist/node/lib/provable/field.js").Field; }) => { result: import("o1js/dist/node/lib/provable/field.js").Field; totalScore: UInt64; bank: import("o1js/dist/node/lib/provable/field.js").Field; }) & { _isStruct: true; } & Omit<import("o1js/dist/node/lib/provable/types/provable-intf.js").Provable<{ result: import("o1js/dist/node/lib/provable/field.js").Field; totalScore: UInt64; bank: import("o1js/dist/node/lib/provable/field.js").Field; }, { result: bigint; totalScore: bigint; bank: bigint; }>, "fromFields"> & { fromFields: (fields: import("o1js/dist/node/lib/provable/field.js").Field[]) => { result: import("o1js/dist/node/lib/provable/field.js").Field; totalScore: UInt64; bank: import("o1js/dist/node/lib/provable/field.js").Field; }; } & { fromValue: (value: { result: string | number | bigint | import("o1js/dist/node/lib/provable/field.js").Field; totalScore: bigint | UInt64; bank: string | number | bigint | import("o1js/dist/node/lib/provable/field.js").Field; }) => { result: import("o1js/dist/node/lib/provable/field.js").Field; totalScore: UInt64; bank: import("o1js/dist/node/lib/provable/field.js").Field; }; toInput: (x: { result: import("o1js/dist/node/lib/provable/field.js").Field; totalScore: UInt64; bank: import("o1js/dist/node/lib/provable/field.js").Field; }) => { fields?: Field[] | undefined; packed?: [Field, number][] | undefined; }; toJSON: (x: { result: import("o1js/dist/node/lib/provable/field.js").Field; totalScore: UInt64; bank: import("o1js/dist/node/lib/provable/field.js").Field; }) => { result: string; totalScore: string; bank: string; }; fromJSON: (x: { result: string; totalScore: string; bank: string; }) => { result: import("o1js/dist/node/lib/provable/field.js").Field; totalScore: UInt64; bank: import("o1js/dist/node/lib/provable/field.js").Field; }; empty: () => { result: import("o1js/dist/node/lib/provable/field.js").Field; totalScore: UInt64; bank: import("o1js/dist/node/lib/provable/field.js").Field; }; }; export declare class ProduceResultEvent extends ProduceResultEvent_base { } declare const GetRewardEvent_base: (new (value: { ticket: Ticket; ticketId: import("o1js/dist/node/lib/provable/field.js").Field; }) => { ticket: Ticket; ticketId: import("o1js/dist/node/lib/provable/field.js").Field; }) & { _isStruct: true; } & Omit<import("o1js/dist/node/lib/provable/types/provable-intf.js").Provable<{ ticket: Ticket; ticketId: import("o1js/dist/node/lib/provable/field.js").Field; }, { ticket: { numbers: bigint[]; owner: { x: bigint; isOdd: boolean; }; amount: bigint; }; ticketId: bigint; }>, "fromFields"> & { fromFields: (fields: import("o1js/dist/node/lib/provable/field.js").Field[]) => { ticket: Ticket; ticketId: import("o1js/dist/node/lib/provable/field.js").Field; }; } & { fromValue: (value: { ticket: Ticket | { numbers: UInt32[] | bigint[]; owner: PublicKey | { x: Field | bigint; isOdd: Bool | boolean; }; amount: bigint | UInt64; }; ticketId: string | number | bigint | import("o1js/dist/node/lib/provable/field.js").Field; }) => { ticket: Ticket; ticketId: import("o1js/dist/node/lib/provable/field.js").Field; }; toInput: (x: { ticket: Ticket; ticketId: import("o1js/dist/node/lib/provable/field.js").Field; }) => { fields?: Field[] | undefined; packed?: [Field, number][] | undefined; }; toJSON: (x: { ticket: Ticket; ticketId: import("o1js/dist/node/lib/provable/field.js").Field; }) => { ticket: { numbers: string[]; owner: string; amount: string; }; ticketId: string; }; fromJSON: (x: { ticket: { numbers: string[]; owner: string; amount: string; }; ticketId: string; }) => { ticket: Ticket; ticketId: import("o1js/dist/node/lib/provable/field.js").Field; }; empty: () => { ticket: Ticket; ticketId: import("o1js/dist/node/lib/provable/field.js").Field; }; }; export declare class GetRewardEvent extends GetRewardEvent_base { } declare const RefundEvent_base: (new (value: { ticketId: import("o1js/dist/node/lib/provable/field.js").Field; ticket: Ticket; }) => { ticketId: import("o1js/dist/node/lib/provable/field.js").Field; ticket: Ticket; }) & { _isStruct: true; } & Omit<import("o1js/dist/node/lib/provable/types/provable-intf.js").Provable<{ ticketId: import("o1js/dist/node/lib/provable/field.js").Field; ticket: Ticket; }, { ticketId: bigint; ticket: { numbers: bigint[]; owner: { x: bigint; isOdd: boolean; }; amount: bigint; }; }>, "fromFields"> & { fromFields: (fields: import("o1js/dist/node/lib/provable/field.js").Field[]) => { ticketId: import("o1js/dist/node/lib/provable/field.js").Field; ticket: Ticket; }; } & { fromValue: (value: { ticketId: string | number | bigint | import("o1js/dist/node/lib/provable/field.js").Field; ticket: Ticket | { numbers: UInt32[] | bigint[]; owner: PublicKey | { x: Field | bigint; isOdd: Bool | boolean; }; amount: bigint | UInt64; }; }) => { ticketId: import("o1js/dist/node/lib/provable/field.js").Field; ticket: Ticket; }; toInput: (x: { ticketId: import("o1js/dist/node/lib/provable/field.js").Field; ticket: Ticket; }) => { fields?: Field[] | undefined; packed?: [Field, number][] | undefined; }; toJSON: (x: { ticketId: import("o1js/dist/node/lib/provable/field.js").Field; ticket: Ticket; }) => { ticketId: string; ticket: { numbers: string[]; owner: string; amount: string; }; }; fromJSON: (x: { ticketId: string; ticket: { numbers: string[]; owner: string; amount: string; }; }) => { ticketId: import("o1js/dist/node/lib/provable/field.js").Field; ticket: Ticket; }; empty: () => { ticketId: import("o1js/dist/node/lib/provable/field.js").Field; ticket: Ticket; }; }; export declare class RefundEvent extends RefundEvent_base { } declare const ReduceEvent_base: (new (value: {}) => {}) & { _isStruct: true; } & Omit<import("o1js/dist/node/lib/provable/types/provable-intf.js").Provable<{}, {}>, "fromFields"> & { fromFields: (fields: import("o1js/dist/node/lib/provable/field.js").Field[]) => {}; } & { fromValue: (value: {}) => {}; toInput: (x: {}) => { fields?: Field[] | undefined; packed?: [Field, number][] | undefined; }; toJSON: (x: {}) => {}; fromJSON: (x: {}) => {}; empty: () => {}; }; export declare class ReduceEvent extends ReduceEvent_base { } export declare class PLottery extends SmartContract { reducer: { dispatch(action: LotteryAction): void; reduce<State>(actions: import("o1js").MerkleList<import("o1js").MerkleList<LotteryAction>>, stateType: Provable<State>, reduce: (state: State, action: LotteryAction) => State, initial: State, options?: { maxUpdatesWithActions?: number; maxActionsPerUpdate?: number; skipActionStatePrecondition?: boolean; }): State; forEach(actions: import("o1js").MerkleList<import("o1js").MerkleList<LotteryAction>>, reduce: (action: LotteryAction) => void, options?: { maxUpdatesWithActions?: number; maxActionsPerUpdate?: number; skipActionStatePrecondition?: boolean; }): void; getActions({ fromActionState, endActionState, }?: { fromActionState?: Field; endActionState?: Field; }): import("o1js").MerkleList<import("o1js").MerkleList<LotteryAction>>; fetchActions({ fromActionState, endActionState, }?: { fromActionState?: Field; endActionState?: Field; }): Promise<LotteryAction[][]>; }; events: { 'buy-ticket': typeof BuyTicketEvent; 'produce-result': typeof ProduceResultEvent; 'get-reward': typeof GetRewardEvent; 'get-refund': typeof RefundEvent; reduce: typeof ReduceEvent; }; randomManager: State<PublicKey>; startSlot: State<UInt32>; ticketRoot: State<import("o1js/dist/node/lib/provable/field.js").Field>; ticketNullifier: State<import("o1js/dist/node/lib/provable/field.js").Field>; bank: State<import("o1js/dist/node/lib/provable/field.js").Field>; result: State<import("o1js/dist/node/lib/provable/field.js").Field>; totalScore: State<UInt64>; init(): void; /** * @notice Set verification key for account * @dev verification key can be updated only if Mina hardfork happen. It allows zkApp to be live after Mina hardfork * @param vk Verification key */ updateVerificationKey(vk: VerificationKey): Promise<void>; /** * @notice Allows a user to buy a lottery ticket for a specific round. * @dev No ticket merkle tree update happens here. Only action is dispatched. * * @param ticket The lottery ticket being purchased. * * @require The ticket must be valid as per the ticket validity check. * @require The specified round must be the current lottery round. * * @event buy-ticket Emitted when a ticket is successfully purchased. */ buyTicket(ticket: Ticket): Promise<void>; /** * @notice Reduce tickets that lies as actions. * @dev This function verifies the proof and ensures that the contract's state matches the state described in the proof. * It then updates the tickets merkle tree, populating it with new tickets. * * @param reduceProof The proof that validates the ticket reduction process and contains the new contract state. * * @require The proof must be valid and successfully verified. * @require The processed action list in the proof must be empty, indicating that all actions have been processed. * @require The contract's last processed state must match the initial state in the proof. * @require The contract's action state must match the final state in the proof. * @require The contract's last processed ticket ID must match the initial ticket ID in the proof. * * @event reduce Emitted when the tickets are successfully reduced and the contract state is updated. */ reduceTicketsAndProduceResult(reduceProof: TicketReduceProof): Promise<void>; emergencyReduceTickets(reduceProof: TicketReduceProof): Promise<void>; checkReduceProof(reduceProof: TicketReduceProof, winningNumbersPacked: Field): void; /** * @notice Processes a refund for a lottery ticket if the result for the round was not generated within 2 days. * @dev This function ensures that the ticket owner is the one requesting the refund, verifies the ticket's validity * in the Merkle maps, checks that the result for the round is zero, and processes the refund after verifying * and updating the necessary states. * * @param ticket The lottery ticket for which the refund is being requested. * @param ticketWitness Witness of the ticket in the ticketMap tree. * * @require The sender must be the owner of the ticket. * @require The ticket must exist in the Merkle map as verified by the round and ticket witnesses. * @require The result for the round must be zero to be eligible for a refund. * @require The refund can only be processed after approximately two days since the round finished. * * @event get-refund Emitted when a refund is successfully processed and the ticket price is returned to the user. */ refund(ticket: Ticket, ticketWitness: MerkleMap20Witness): Promise<void>; /** * @notice Claims the reward for a winning lottery ticket. * @dev This function calculate ticket score, totalScore is obtained from DistributionProof, * and then sends appropriate potion of bank to ticket owner. Finally it nullify the ticket. * * @param ticket The lottery ticket for which the reward is being claimed. * @param ticketWitness Witness of the ticket in the ticketMap tree. * @param nullifierWitness The Merkle proof witness for the nullifier tree. * * @require The sender must be the owner of the ticket. * @require The distribution proof must be valid and match the round's ticket root and winning numbers. * @require The ticket must exist in the Merkle map as verified by the round and ticket witnesses. * @require The actions for the round must be reduced before claiming the reward. * * @event get-reward Emitted when the reward is successfully claimed and transferred to the ticket owner. */ getReward(ticket: Ticket, ticketWitness: MerkleMap20Witness, nullifierWitness: MerkleMap20Witness): Promise<void>; /** * @notice Check that execution is happening within provided round * * * @require globalSlotSinceGenesis to be within range of round */ checkCurrentRound(): void; /** * @notice Check that execution is happening after provided round * * @param amount Amounts of rounds to pass to check * * @require globalSlotSinceGenesis to be greater then last slot of given number */ checkRoundPass(amount: UInt32): void; /** * @notice Check validity of merkle map witness for nullifier tree and then updates tree with new value. * * @param witness Merkle map witness for nullifier tree. * @param key Round number, that will be compared with <witness> key. * @param curValue Value of nullifier to be checked. * @param newValue New value that should be store in tree. * * @returns key of <witness> */ checkAndUpdateNullifier(witness: MerkleMap20Witness, key: Field, curValue: Field, newValue: Field): MerkleCheckResult; /** * @notice General method that allows to check and update onchain merkle trees roots * * @param state On-chain state, that should be updated. * @param witness Merkle map witness. * @param key Key that will be compared with <witness> key. * @param curValue Value to be checked. * @param newValue New value that should be store in tree. * * @returns key of <witness> */ checkAndUpdateMap(state: State<Field>, witness: MerkleMap20Witness | MerkleMapWitness, key: Field, curValue: Field, newValue: Field): MerkleCheckResult; /** * @notice General method that allows to check onchain merkle trees roots * * @param state On-chain state, that should be updated. * @param witness Merkle map witness. * @param key Key that will be compared with <witness> key. * @param curValue Value to be checked. * * @returns key of <witness> */ checkMap(state: State<Field>, witness: MerkleMap20Witness | MerkleMapWitness, key: Field, curValue: Field): MerkleCheckResult; } export {};