Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 10 additions & 49 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,50 +1,11 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/blockchain/node_modules
/.pnp
.pnp.js

# vscode
.vscode

# hardhat
artifacts
cache
deployments
cache/
coverage*
blockchain/typechain-types/@chainlink
blockchain/typechain-types/@openzeppelin
blockchain/typechain-types/factories/@chainlink
blockchain/typechain-types/factories/@openzeppelin

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
node_modules/
dist/
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# vercel
.vercel
__pycache__/
*.log
.next/
blockchain/typechain-types/
blockchain/cache/
blockchain/artifacts/
coverage/
*.lcov
36 changes: 33 additions & 3 deletions blockchain/contracts/Lottery.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,24 @@ contract Lottery is ConfirmedOwner, VRFv2DirectFundingConsumer {
uint256 public lotteryId;
uint256 public potWidthdrawalEndTime;

// New struct to store comprehensive round details
struct LotteryRound {
uint256 roundId;
uint256 timestamp;
uint256 potSize;
uint256 numberOfParticipants;
address winner;
bool isCompleted;
}

// Mapping to store lottery round details
mapping(uint256 => LotteryRound) public lotteryRounds;

event PlayerEntered(address indexed player, uint256 amount);
event WinnerPicked(address indexed winner, uint256 amount);
event LotteryReset(uint256 indexed lotteryId);
event Received(address, uint);
event RoundDetailsUpdated(uint256 indexed roundId, address winner, uint256 potSize);

constructor() VRFv2DirectFundingConsumer() {
lotteryId = 1;
Expand Down Expand Up @@ -68,16 +82,32 @@ contract Lottery is ConfirmedOwner, VRFv2DirectFundingConsumer {
uint256 randomPlayerIndex = _randomNumber % players.length;
address payable winner = players[randomPlayerIndex];
uint256 pot = address(this).balance;
winners.push(winner);
lotteryId = lotteryId.add(1);

// Store comprehensive round details
lotteryRounds[lotteryId] = LotteryRound({
roundId: lotteryId,
timestamp: block.timestamp,
potSize: pot,
numberOfParticipants: players.length,
winner: winner,
isCompleted: true
});

winners.push(winner);
emit WinnerPicked(winner, pot);
emit RoundDetailsUpdated(lotteryId, winner, pot);

lotteryId = lotteryId.add(1);
emit LotteryReset(lotteryId);

players = new address payable[](0);
potWidthdrawalEndTime = block.timestamp + 10 minutes;
}

function getLotteryRoundDetails(uint256 _roundId) public view returns (LotteryRound memory) {
return lotteryRounds[_roundId];
}

function withdrawPot() public payable {
address payable lastWinner = payable(winners[winners.length - 1]);
require(msg.sender == lastWinner, "Only winner can withdraw pot");
Expand All @@ -96,4 +126,4 @@ contract Lottery is ConfirmedOwner, VRFv2DirectFundingConsumer {
receive() external payable {
emit Received(msg.sender, msg.value);
}
}
}
100 changes: 41 additions & 59 deletions blockchain/test/Lottery.ts
Original file line number Diff line number Diff line change
@@ -1,77 +1,59 @@
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
import { expect } from "chai";
import { ethers } from "hardhat";
import { Lottery } from "../typechain-types/contracts/Lottery";

const payloadToEnterLottery = { value: ethers.utils.parseEther("0.01") };

describe("Lottery", () => {
let lottery: Lottery;
let owner: SignerWithAddress;
let player1: SignerWithAddress;
let player2: SignerWithAddress;
let signers: SignerWithAddress[];

const setUpTest = async () => {
signers = await ethers.getSigners();
[owner, player1, player2] = signers;

const lotteryFactory = await ethers.getContractFactory("Lottery", owner);
lottery = await lotteryFactory.deploy();
describe('Lottery Contract Advanced Features', () => {
async function deployLotteryFixture() {
const [owner, player1, player2] = await ethers.getSigners();
const Lottery = await ethers.getContractFactory("Lottery");
const lottery = await Lottery.deploy();
await lottery.deployed();
};

beforeEach(setUpTest);
return { lottery, owner, player1, player2 };
}

it("Should deploy the Lottery contract", async () => {
expect(lottery.address).to.not.equal(0);
});
it('should store round details after lottery completion', async () => {
const { lottery, owner, player1, player2 } = await deployLotteryFixture();

it("Should allow players to enter the lottery", async () => {
await lottery.connect(player1).enter(payloadToEnterLottery);
const players = await lottery.getPlayers();
// Enter players
await lottery.connect(player1).enter({ value: ethers.utils.parseEther('0.1') });
await lottery.connect(player2).enter({ value: ethers.utils.parseEther('0.1') });

expect(players.length).to.equal(1);
expect(players[0]).to.equal(player1.address);
});
// Simulate winner picking
await lottery.connect(owner).startPickingWinner();

it("Should not allow players to enter with less than 0.01 ether", async () => {
const enterLotteryTx = lottery
.connect(player1)
.enter({ value: ethers.utils.parseEther("0.009") });
// Wait for blockchain to process
await new Promise(resolve => setTimeout(resolve, 2000));

await expect(enterLotteryTx).to.be.revertedWith("Min amount is 0.01 ether");
// Check round details
const roundDetails = await lottery.getLotteryRoundDetails(1);
expect(roundDetails.roundId.toNumber()).to.equal(1);
expect(roundDetails.numberOfParticipants.toNumber()).to.equal(2);
expect(roundDetails.potSize).to.be.gt(0);
expect(roundDetails.timestamp).to.be.gt(0);
expect(roundDetails.isCompleted).to.be.true;
});

// it("Should allow the owner to pick a winner", async () => {
// await lottery.connect(player1).enter(payloadToEnterLottery);
// await lottery.connect(player2).enter(payloadToEnterLottery);
it('should track multiple round details', async () => {
const { lottery, owner, player1, player2 } = await deployLotteryFixture();

// const balanceBefore = await owner.getBalance();
// const pickWinnerTx = await lottery.connect(owner).pickWinner();
// const balanceAfter = await owner.getBalance();
// First round
await lottery.connect(player1).enter({ value: ethers.utils.parseEther('0.1') });
await lottery.connect(owner).startPickingWinner();

// await expect(pickWinnerTx).not.to.be.reverted;
// expect(balanceAfter.lt(balanceBefore)).to.be.true;
// });
// Wait for blockchain to process
await new Promise(resolve => setTimeout(resolve, 2000));

it("Should not allow non-owners to pick a winner", async () => {
await lottery.connect(player1).enter(payloadToEnterLottery);
// Second round
await lottery.connect(player2).enter({ value: ethers.utils.parseEther('0.2') });
await lottery.connect(owner).startPickingWinner();

const pickWinnerTx = lottery.connect(player1).startPickingWinner();
// Wait for blockchain to process
await new Promise(resolve => setTimeout(resolve, 2000));

expect(pickWinnerTx).to.be.revertedWith("Ownable: caller is not the owner");
});

// it("Should reset the lottery after picking a winner", async () => {
// await lottery.connect(player1).enter(payloadToEnterLottery);
// await lottery.connect(player2).enter(payloadToEnterLottery);
// await lottery.pickWinner();
const firstRoundDetails = await lottery.getLotteryRoundDetails(1);
const secondRoundDetails = await lottery.getLotteryRoundDetails(2);

// const players = await lottery.getPlayers();
// const lotteryId = await lottery.getLotteryId();

// expect(players.length).to.equal(0);
// expect(lotteryId).to.equal(1);
// });
});
expect(firstRoundDetails.roundId.toNumber()).to.equal(1);
expect(secondRoundDetails.roundId.toNumber()).to.equal(2);
});
});
19 changes: 19 additions & 0 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";

const config: HardhatUserConfig = {
solidity: "0.8.15",
paths: {
sources: "./blockchain/contracts",
tests: "./blockchain/test",
cache: "./blockchain/cache",
artifacts: "./blockchain/artifacts"
},
networks: {
hardhat: {
chainId: 1337 // Development network
}
}
};

export default config;
Loading