npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

l1-lottery-contracts

v0.7.46

Published

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

Downloads

673

Readme

Mina L1 lottery

This repo contains smart contracts and related scripts for ZkNoid L1 Lottery proposed here

Technical overview

Pre-Round Phase

  • Before a round begins, the only action permitted is committing a value for randomness.

Active Round

  • A round is considered active if the current chain slot falls within the [roundStartBlock, roundEndBlock] range.

During the Round

  • Users are allowed to buyTickets.

Post-Round Actions

  • Once the round concludes, the following steps must be completed before users can claim rewards for their tickets:
    1. Ticket Reduction:

      • ticketReduce must be invoked on the PLottery contract. This function will reduce all tickets from the target round and at least one from the subsequent round.
    2. Randomness Reveal:

      • reveal should be called on the RandomManager for the target round. This will generate the seed required for winning ticket generation.
    3. Result Production:

      • produceResult must be executed on the PLottery contract to determine the winning ticket for the round.

Reward Collection

  • After the above steps are completed, users can call getReward to claim their rewards for the tickets.

Fallback for Result Generation

  • If the result is not produced within the next two rounds, users will be eligible to request a refund for their tickets.

Storage usage

    @state(Field) ticketRoot = State<Field>();
    @state(Field) ticketNullifier = State<Field>();
    @state(Field) bankRoot = State<Field>();
    @state(Field) roundResultRoot = State<Field>();
    @state(UInt32) startBlock = State<UInt32>();
    @state(Field) lastProcessedState = State<Field>();
    @state(Field) lastReduceInRound = State<Field>();
    @state(Field) lastProcessedTicketId = State<Field>();

We are using all 8 avaliable slots:

  1. ticketRoot - to store merkle tree root for ticket
  2. ticketNullifier - to store merkle tree root for nullifer, so one ticket could be redeemed only once
  3. bankRoot - to store bank merkle tree root for each round
  4. roundResultRoot - to store winning combination for each round
  5. startBlock - stores slot of deployment
  6. lastProcessedState - stores last processed actions state
  7. lastReduceInRound - stores round in wich last actions reduce was called. We can garantee, that in this case all tickets from previous rounds was processed by reducer
  8. lastProcessedTicketId - id of last processed ticket by reducer

Ticket purchase

For ticket purchase buyTicket method is used

@method async buyTicket(ticket: Ticket, round: Field) {
  ...
}

It do not update ticket merkle tree, but add action to actionList.

this.reducer.dispatch(
  new LotteryAction({
    ticket,
    round,
  })
);

Also it fires event:

this.emitEvent(
  'buy-ticket',
  new BuyTicketEvent({
    ticket,
    round: round,
  })
);

Ticket reduce

As mentioned earlier buyTicket do not update ticket merkle tree, but add action to actionList. We can't use it directly, so we need to convert actions list to merkle tree. We do it using ZkProgramm:

export const TicketReduceProgram = ZkProgram({
  name: 'ticket-reduce-program',
  publicInput: TicketReduceProofPublicInput,
  publicOutput: TicketReduceProofPublicOutput,
  methods: {
    init: {
      ...
    },
    addTicket: {
      ...
    },
    cutActions: {
      ...
    },
  },
});

Winning number generation

For random generation we have separate contract. It utilize ZKOn zk oracle and commit-reveal technique.

First we commit our hidden value:

    @method async commit(
      commitValue: CommitValue,
      commitWitness: MerkleMapWitness
    ) {
      ...
    }

Then send request for ZkOn oracle, with request that lies on IPFS(cid can be found here). It sends request on quantum-random.com to get random number.

@method async callZkon() {
  ...
  const requestId = await coordinator.sendRequest(
    this.address,
    hashPart1,
    hashPart2
  );
  ...
}

After we receive random number from ZKOn, we mix it with out hidden number, and store result on merkle tree.

    @method async reveal(
      commitValue: CommitValue,
      commitWitness: MerkleMapWitness,
      resultWitness: MerkleMapWitness
    ) {
      ...
      const resultValue = Poseidon.hash([commitValue.value, curRandomValue]);

      // Update result
      const [newResultRoot] = resultWitness.computeRootAndKey(resultValue);
      this.resultRoot.set(newResultRoot);
      ...
    }

Later we will use this number to generate winning combination

    @method async produceResult(
      resultWiness: MerkleMap20Witness,
      result: Field,
      bankValue: Field,
      bankWitness: MerkleMap20Witness,
      rmWitness: MerkleMapWitness,
      rmValue: Field
    ) {
      ...
      this.checkRandomResultValue(rmWitness, rmValue, round);

      let winningNumbers = generateNumbersSeed(rmValue);
      ...
    }


    public checkRandomResultValue(
      roundResultWitness: MerkleMapWitness,
      roundResulValue: Field,
      round: Field
    ) {
      ...
      const rm = new RandomManager(randomManagerAddress);
      const resultRoot = rm.resultRoot.getAndRequireEquals();
      ...
    }

Bank distribution

Bank is distrubuted among all players fairly, according to amount of rightly guessed number. To do so, after winning numbers generation we match score for it ticket:

  • 0 numbers guessed - 0
  • 1 number guessed - 90
  • 2 numbers guessed - 324
  • 3 numbers guessed - 2187
  • 4 numbers guessed - 26244
  • 5 numbers guessed - 590490
  • 6 numbers guessed - 31886460

Then we compute total score for round in a provable way using proof.

Each ticket can get roundBank * ticketScore / totalScore tokens.

Ticket redemption

To get winning for ticket getReward function exist. It will compute score for ticket, portion of bank, which it owns, transfer to to user, and update nullifier merkle map, so this ticket can't be used in future.

    @method async getReward(
      ticket: Ticket,
      roundWitness: MerkleMap20Witness,
      roundTicketWitness: MerkleMap20Witness,
      dp: DistributionProof,
      winningNumbers: Field,
      resutWitness: MerkleMap20Witness,
      bankValue: Field,
      bankWitness: MerkleMap20Witness,
      nullifierWitness: MerkleMapWitness
    ) {
    }

Preparation

Install npm modules:

npm install

Prepare mina-fungible-token module:

npm run token_prepare
npm run build

How to run tests

npm run test

How to run coverage

npm run coverage

How to deploy

To deploy you first need to set evironments variables:

DEPLOYER_KEY = ""
RANDOM_MANAGER_OWNER_ADDRESS = ""

Then you can deploy it using

npm run deploy

It will generate private and public keys for RandomManager and Lottery. Deploy them on corresponding addresses and will store addresses on deploy/addresses and store keys on keys/auto

License

Apache-2.0