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
TypeScript
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 {};