Skip to content

Commit

Permalink
Increased coverage, fixed bug with refund
Browse files Browse the repository at this point in the history
  • Loading branch information
aii23 committed Jul 28, 2024
1 parent 29f1149 commit 05b1a96
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 51 deletions.
9 changes: 9 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,15 @@
"feepayerAlias": "deployer",
"fee": "0.1",
"smartContract": "PLottery"
},
"plottery_6": {
"networkId": "testnet",
"url": "https://api.minascan.io/node/devnet/v1/graphql",
"keyPath": "keys/plottery_6.json",
"feepayerKeyPath": "/home/alex/.cache/zkapp-cli/keys/deployer.json",
"feepayerAlias": "deployer",
"fee": "0.1",
"smartContract": "PLottery"
}
}
}
145 changes: 144 additions & 1 deletion src/PLottery.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,153 @@ describe('Add', () => {
checkConsistancy();
});

it('Refund check', async () => {
await localDeploy();

let curRound = 0;

const balanceBefore = Mina.getBalance(senderAccount);

// Buy ticket
const ticket = Ticket.from(mockWinningCombination, senderAccount, 1);

let tx = await Mina.transaction(senderAccount, async () => {
await lottery.buyTicket(ticket, Field.from(curRound));
});

await tx.prove();
await tx.sign([senderKey]).send();

const balanceAfter = Mina.getBalance(senderAccount);

expect(balanceBefore.sub(balanceAfter)).toEqual(TICKET_PRICE);

checkConsistancy();

// Buy second ticket
let tx1_1 = await Mina.transaction(senderAccount, async () => {
await lottery.buyTicket(ticket, Field.from(curRound));
});

await tx1_1.prove();
await tx1_1.sign([senderKey]).send();

// Wait 3 more rounds
mineNBlocks(3 * BLOCK_PER_ROUND + 1);

// Buy dummy ticket in next round, so reudcer works as expected
state.syncWithCurBlock(
+Mina.activeInstance.getNetworkState().globalSlotSinceGenesis
);

// Reduce tickets

// Buy dummy ticket
let dummy_ticket = Ticket.random(senderAccount);
dummy_ticket.amount = UInt64.zero;
let tx_1 = await Mina.transaction(senderAccount, async () => {
await lottery.buyTicket(dummy_ticket, Field.from(3));
});
await tx_1.prove();
await tx_1.sign([senderKey]).send();

let reduceProof = await state.reduceTickets();

let tx2_1 = await Mina.transaction(senderAccount, async () => {
await lottery.reduceTickets(reduceProof);
});

await tx2_1.prove();
await tx2_1.sign([senderKey]).send();
checkConsistancy();

// Get refund

let {
roundWitness,
roundTicketWitness,
resultWitness: resultWitness1,
// bankValue,
// bankWitness,
nullifierWitness,
} = await state.getRefund(0, ticket);

const balanceBefore2 = Mina.getBalance(senderAccount);

let tx3 = await Mina.transaction(senderAccount, async () => {
await lottery.refund(
ticket,
roundWitness,
roundTicketWitness,
resultWitness1,
// bankValue,
// bankWitness,
nullifierWitness
);
});

await tx3.prove();
await tx3.sign([senderKey]).send();
checkConsistancy();

const balanceAfter2 = Mina.getBalance(senderAccount);

expect(balanceAfter2.sub(balanceBefore2)).toEqual(
TICKET_PRICE.mul(97).div(100)
);

// Produce result
let { resultWitness, bankValue, bankWitness } =
state.updateResult(curRound);
let tx4 = await Mina.transaction(senderAccount, async () => {
await lottery.produceResult(
resultWitness,
mockResult,
bankValue,
bankWitness
);
});

await tx4.prove();
await tx4.sign([senderKey]).send();
checkConsistancy();

const balanceBefore3 = Mina.getBalance(senderAccount);

// Get reward for second transaction
const rp = await state.getReward(curRound, ticket, undefined, 2);
let tx5 = await Mina.transaction(senderAccount, async () => {
await lottery.getReward(
ticket,
rp.roundWitness,
rp.roundTicketWitness,
rp.dp,
rp.winningNumbers,
rp.resultWitness,
rp.bankValue,
rp.bankWitness,
rp.nullifierWitness
);
});

await tx5.prove();
await tx5.sign([senderKey]).send();
checkConsistancy();

const balanceAfter3 = Mina.getBalance(senderAccount);

console.log(`Bank: ${state.bankMap.get(Field(0)).toString()}`);
console.log();

expect(balanceAfter3.sub(balanceBefore3)).toEqual(
TICKET_PRICE.mul(97).div(100)
);
});

it('Multiple round test', async () => {
await localDeploy();

const amountOfRounds = 10;
const amountOfRounds = 5;
const amountOfTickets = 10;

for (let round = 0; round < amountOfRounds; round++) {
Expand Down
71 changes: 36 additions & 35 deletions src/PLottery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,8 +289,6 @@ export class PLottery extends SmartContract {
roundWitness: MerkleMap20Witness,
roundTicketWitness: MerkleMap20Witness,
resultWitness: MerkleMap20Witness,
bankValue: Field,
bankWitness: MerkleMap20Witness,
nullifierWitness: MerkleMapWitness
) {
// Check taht owner trying to claim
Expand All @@ -312,8 +310,11 @@ export class PLottery extends SmartContract {

// Check and update bank witness
const totalTicketPrice = ticket.amount.mul(TICKET_PRICE);
const newBankValue = bankValue.sub(totalTicketPrice.value);
this.checkAndUpdateBank(bankWitness, round, bankValue, newBankValue);
const priceWithoutCommision = totalTicketPrice
.mul(PRESICION - COMMISION)
.div(PRESICION);
// const newBankValue = bankValue.sub(totalTicketPrice.value);
// this.checkAndUpdateBank(bankWitness, round, bankValue, newBankValue);

// Check and update nullifier
this.checkAndUpdateNullifier(
Expand All @@ -326,7 +327,7 @@ export class PLottery extends SmartContract {
// Send ticket price back to user
this.send({
to: ticket.owner,
amount: totalTicketPrice,
amount: priceWithoutCommision,
});

this.emitEvent(
Expand Down Expand Up @@ -500,20 +501,20 @@ export class PLottery extends SmartContract {
return this.checkMap(this.roundResultRoot, witness, round, curValue);
}

private checkAndUpdateResult(
witness: MerkleMap20Witness,
round: Field,
curValue: Field,
newValue: Field
): MerkleCheckResult {
return this.checkAndUpdateMap(
this.roundResultRoot,
witness,
round,
curValue,
newValue
);
}
// private checkAndUpdateResult(
// witness: MerkleMap20Witness,
// round: Field,
// curValue: Field,
// newValue: Field
// ): MerkleCheckResult {
// return this.checkAndUpdateMap(
// this.roundResultRoot,
// witness,
// round,
// curValue,
// newValue
// );
// }

private checkBank(
witness: MerkleMap20Witness,
Expand Down Expand Up @@ -587,22 +588,22 @@ export class PLottery extends SmartContract {
};
}

private checkAndUpdateTicketMap(
firstWitness: MerkleMap20Witness | MerkleMapWitness,
key1: Field | null,
secondWitness: MerkleMap20Witness | MerkleMapWitness,
// key2: Field, For know second level key is not checked as later it would transform to merkle map
prevValue: Field,
newValue: Field
): { ticketId: Field; round: Field } {
const res = this.checkTicket(firstWitness, key1, secondWitness, prevValue);

const [newRoot2] = secondWitness.computeRootAndKey(newValue);
const [newRoot1] = firstWitness.computeRootAndKey(newRoot2);
this.ticketRoot.set(newRoot1);

return res;
}
// private checkAndUpdateTicketMap(
// firstWitness: MerkleMap20Witness | MerkleMapWitness,
// key1: Field | null,
// secondWitness: MerkleMap20Witness | MerkleMapWitness,
// // key2: Field, For know second level key is not checked as later it would transform to merkle map
// prevValue: Field,
// newValue: Field
// ): { ticketId: Field; round: Field } {
// const res = this.checkTicket(firstWitness, key1, secondWitness, prevValue);

// const [newRoot2] = secondWitness.computeRootAndKey(newValue);
// const [newRoot1] = firstWitness.computeRootAndKey(newRoot2);
// this.ticketRoot.set(newRoot1);

// return res;
// }

private checkTicket(
firstWitness: MerkleMap20Witness | MerkleMapWitness,
Expand Down
34 changes: 19 additions & 15 deletions src/StateManager/BaseStateManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,8 @@ export class BaseStateManager {
async getReward(
round: number,
ticket: Ticket,
roundDP: JsonProof | undefined = undefined
roundDP: JsonProof | undefined = undefined,
ticketIndex: number = 1 // If two or more same tickets presented
): Promise<{
roundWitness: MerkleMap20Witness;
roundTicketWitness: MerkleMap20Witness;
Expand All @@ -234,10 +235,13 @@ export class BaseStateManager {
.equals(ticketHash)
.toBoolean()
) {
roundTicketWitness = this.roundTicketMap[round].getWitness(
Field.from(ticketId)
);
break;
ticketIndex--;
if (ticketIndex == 0) {
roundTicketWitness = this.roundTicketMap[round].getWitness(
Field.from(ticketId)
);
break;
}
}
}
if (!roundTicketWitness) {
Expand Down Expand Up @@ -286,8 +290,8 @@ export class BaseStateManager {
roundWitness: MerkleMap20Witness;
roundTicketWitness: MerkleMap20Witness;
resultWitness: MerkleMap20Witness;
bankValue: Field;
bankWitness: MerkleMap20Witness;
// bankValue: Field;
// bankWitness: MerkleMap20Witness;
nullifierWitness: MerkleMapWitness;
}> {
const roundWitness = this.ticketMap.getWitness(Field.from(round));
Expand Down Expand Up @@ -315,8 +319,8 @@ export class BaseStateManager {

const resultWitness = this.roundResultMap.getWitness(Field.from(round));

const bankValue = this.bankMap.get(Field.from(round));
const bankWitness = this.bankMap.getWitness(Field.from(round));
// const bankValue = this.bankMap.get(Field.from(round));
// const bankWitness = this.bankMap.getWitness(Field.from(round));

const nullifierWitness = this.ticketNullifierMap.getWitness(
getNullifierId(Field.from(round), Field.from(ticketId))
Expand All @@ -328,18 +332,18 @@ export class BaseStateManager {
Field(1)
);

this.bankMap.set(
Field.from(round),
bankValue.sub(ticket.amount.mul(TICKET_PRICE).value)
);
// this.bankMap.set(
// Field.from(round),
// bankValue.sub(ticket.amount.mul(TICKET_PRICE).value)
// );
}

return {
roundWitness,
roundTicketWitness,
resultWitness,
bankValue,
bankWitness,
// bankValue,
// bankWitness,
nullifierWitness,
};
}
Expand Down

0 comments on commit 05b1a96

Please sign in to comment.