Skip to content

Commit

Permalink
Change ticket store
Browse files Browse the repository at this point in the history
  • Loading branch information
aii23 committed May 23, 2024
1 parent 28e61bc commit 4bae48d
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 67 deletions.
12 changes: 0 additions & 12 deletions src/DistributionProof.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
import {
Field,
SmartContract,
state,
State,
method,
Struct,
Provable,
UInt8,
UInt32,
Poseidon,
Bool,
MerkleMapWitness,
AccountUpdate,
UInt64,
Gadgets,
Mina,
ZkProgram,
MerkleMap,
SelfProof,
Expand Down
38 changes: 17 additions & 21 deletions src/Lottery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,15 @@ import {
state,
State,
method,
Struct,
Provable,
UInt8,
UInt32,
Poseidon,
Bool,
MerkleMapWitness,
AccountUpdate,
UInt64,
Gadgets,
Mina,
ZkProgram,
MerkleMap,
SelfProof,
UInt8,
Int64,
PublicKey,
CircuitString,
} from 'o1js';
import { PackedUInt32Factory } from 'o1js-pack';
import { Ticket } from './Ticket';
Expand All @@ -43,6 +38,7 @@ const generateNumbersSeed = (seed: Field): UInt32[] => {
};

// #TODO constrain round to current
// #TODO add events

export class Lottery extends SmartContract {
// Stores merkle map with all tickets, that user have bought. Each leaf of this tree is a root of tree for corresponding round
Expand All @@ -62,21 +58,22 @@ export class Lottery extends SmartContract {

@method async buyTicket(
ticket: Ticket,
amount: UInt64,
curValue: Field,
rountWitness: MerkleMapWitness,
ticketWitness: MerkleMapWitness,
prevBankValue: Field,
bankWitness: MerkleMapWitness
) {
ticket.owner.equals(this.sender.getAndRequireSignature()); // Do we need this check?

// Ticket validity check
ticket.round.assertEquals(this.getCurrentRound());
ticket.check().assertTrue();

// Calculate round ticket root
const [roundTicketRootBefore, key] =
ticketWitness.computeRootAndKey(curValue);
key.assertEquals(ticket.hash(), 'Wrong key for ticket witness');
const [roundTicketRootBefore, key] = ticketWitness.computeRootAndKey(
Field(0) // Because ticket should be empty before buying
);
// Key can be any right now. We can change it to
// key.assertEquals(ticket.hash(), 'Wrong key for ticket witness');

// Calculate round root
const [ticketRootBefore, roundKey] = rountWitness.computeRootAndKey(
Expand All @@ -88,12 +85,10 @@ export class Lottery extends SmartContract {
.getAndRequireEquals()
.assertEquals(ticketRootBefore, 'Round witness check fail');
// Check that key is a ticket round
roundKey.assertEquals(ticket.round.value);
roundKey.assertEquals(this.getCurrentRound().value);

// Recalculate round ticket root with new value
const [newRoundTicketRoot] = ticketWitness.computeRootAndKey(
curValue.add(amount.value)
);
const [newRoundTicketRoot] = ticketWitness.computeRootAndKey(ticket.hash());

// Recalculate ticket root
const [newTicketRoot] = rountWitness.computeRootAndKey(newRoundTicketRoot);
Expand All @@ -104,7 +99,7 @@ export class Lottery extends SmartContract {
let senderUpdate = AccountUpdate.createSigned(
this.sender.getAndRequireSignature()
);
senderUpdate.send({ to: this, amount: TICKET_PRICE.mul(amount) });
senderUpdate.send({ to: this, amount: TICKET_PRICE.mul(ticket.amount) });

// Update bank info
const [prevBankRoot, bankKey] =
Expand All @@ -115,7 +110,7 @@ export class Lottery extends SmartContract {
bankKey.assertEquals(roundKey, 'Wrong bank round');

const [newBankRoot] = bankWitness.computeRootAndKey(
prevBankValue.add(TICKET_PRICE.mul(amount).value)
prevBankValue.add(TICKET_PRICE.mul(ticket.amount).value)
);

this.bankRoot.set(newBankRoot);
Expand Down Expand Up @@ -157,6 +152,7 @@ export class Lottery extends SmartContract {
winningNumbers: Field,
resutWitness: MerkleMapWitness
) {
ticket.owner.assertEquals(this.sender.getAndRequireSignature());
// Verify distibution proof
dp.verify();

Expand Down
64 changes: 30 additions & 34 deletions src/Ticket.ts
Original file line number Diff line number Diff line change
@@ -1,62 +1,55 @@
import {
Field,
SmartContract,
state,
State,
method,
Struct,
Provable,
UInt8,
UInt32,
Poseidon,
Bool,
MerkleMapWitness,
AccountUpdate,
UInt64,
Gadgets,
Mina,
ZkProgram,
MerkleMap,
SelfProof,
PublicKey,
UInt64,
} from 'o1js';
import { NUMBERS_IN_TICKET } from './constants';
import { NUMBERS_IN_TICKET, SCORE_COEFFICIENTS } from './constants';

// #TODO add user address to ticket
// technically we can remove round from ticket
export class Ticket extends Struct({
numbers: Provable.Array(UInt8, NUMBERS_IN_TICKET),
round: UInt32,
owner: PublicKey,
amount: UInt64,
}) {
static from(numbers: number[], round: number): Ticket {
static from(numbers: number[], owner: PublicKey, amount: number): Ticket {
if (numbers.length != NUMBERS_IN_TICKET) {
throw new Error(
`Wrong amount of numbers. Got: ${numbers.length}, expect: ${NUMBERS_IN_TICKET}`
);
}
return new Ticket({
numbers: numbers.map((number) => UInt8.from(number)),
round: UInt32.from(round),
owner,
amount: UInt64.from(amount),
});
}

static generateFromSeed(seed: Field, round: UInt32): Ticket {
const initMask = 0b1111;
const masks = [...Array(NUMBERS_IN_TICKET)].map(
(val, i) => initMask << (i * 4)
);
// static generateFromSeed(seed: Field, round: UInt32): Ticket {
// const initMask = 0b1111;
// const masks = [...Array(NUMBERS_IN_TICKET)].map(
// (val, i) => initMask << (i * 4)
// );

const numbers = masks
.map((mask, i) => {
const masked = Gadgets.and(seed, Field.from(mask), (i + 1) * 4);
return Gadgets.rightShift64(masked, i * 4);
})
.map((val) => UInt8.from(val));
// const numbers = masks
// .map((mask, i) => {
// const masked = Gadgets.and(seed, Field.from(mask), (i + 1) * 4);
// return Gadgets.rightShift64(masked, i * 4);
// })
// .map((val) => UInt8.from(val));

return new Ticket({
numbers,
round,
});
}
// return new Ticket({
// numbers,
// round,
// });
// }

check(): Bool {
return this.numbers.reduce(
Expand All @@ -67,7 +60,10 @@ export class Ticket extends Struct({

hash(): Field {
return Poseidon.hash(
this.numbers.map((number) => number.value).concat(this.round.value)
this.numbers
.map((number) => number.value)
.concat(this.owner.toFields())
.concat(this.amount.value)
);
}

Expand All @@ -88,8 +84,8 @@ export class Ticket extends Struct({
result.equals(index)
);

const values = [0, 10, 100, 1000, 10000, 100000].map((val) =>
Field.from(val)
const values = SCORE_COEFFICIENTS.map((val) =>
Field.from(val).mul(this.amount.value)
);

return Provable.switch(conditions, Field, values);
Expand Down
2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ export const NUMBERS_IN_TICKET = 6;

export const TICKET_PRICE = UInt64.from(10); // #TODO change to field in smartcontract
export const BLOCK_PER_ROUND = 480; // Aproximate blocks per day

export const SCORE_COEFFICIENTS = [1, 10, 100, 1000, 10000, 100000]; // Should be updated with apropriate probaility

0 comments on commit 4bae48d

Please sign in to comment.