create: new folder

This commit is contained in:
abiyasa05 2024-12-31 11:46:10 +07:00
parent 9c970bc7b3
commit 17946eb04c
330 changed files with 40952 additions and 1 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1 +0,0 @@
tes

View File

@ -0,0 +1,17 @@
node_modules
.env
# Hardhat files
/cache
/artifacts
# TypeChain files
/typechain
/typechain-types
# solidity-coverage files
/coverage
/coverage.json
# Hardhat Ignition default folder for deployments against a local node
ignition/deployments/chain-31337

View File

@ -0,0 +1,13 @@
# Sample Hardhat Project
This project demonstrates a basic Hardhat use case. It comes with a sample contract, a test for that contract, and a Hardhat Ignition module that deploys that contract.
Try running some of the following tasks:
```shell
npx hardhat help
npx hardhat test
REPORT_GAS=true npx hardhat test
npx hardhat node
npx hardhat ignition deploy ./ignition/modules/Lock.js
```

View File

@ -0,0 +1,419 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.2 <0.9.0;
contract Election {
address payable public owner;
struct Voter {
uint256 id;
string name;
string email;
bool hasVoted;
bytes32 passwordHash;
uint256 lastUpdated; // Timestamp of the last update
bool isActive; // To mark if a voter is active
bytes32 transactionHash;
uint256 blockNumber;
}
struct Candidate {
uint256 id;
string name;
string visi;
string misi;
uint256 voteCount;
uint256 lastUpdated; // Timestamp of the last update
bool isActive; // To mark if a voter is active
bytes32 transactionHash;
uint256 blockNumber;
}
struct VoterHistory {
uint256 id;
string name;
string email;
bool hasVoted;
bytes32 passwordHash;
uint256 timestamp;
bytes32 transactionHash;
uint256 blockNumber;
}
struct CandidateHistory {
uint256 id;
string name;
string visi;
string misi;
uint256 voteCount;
uint256 timestamp;
bytes32 transactionHash;
uint256 blockNumber;
}
struct VoteCountHistory {
uint256 candidateId;
uint256 voteCount;
uint256 timestamp;
bytes32 transactionHash;
uint256 blockNumber;
}
event VoterAdded(uint256 id, string name);
event VoterUpdated(uint256 id, string name);
event VoterDeleted(uint256 id, string name);
event CandidateAdded(uint256 id, string name);
event CandidateUpdated(uint256 id, string name);
event CandidateDeleted(uint256 id, string name);
event ElectionEnded();
bool public electionActive;
uint256[] public voterIds;
uint256[] public candidateIds;
mapping(uint256 => Voter) public voters;
mapping(uint256 => Candidate) public candidates;
mapping(uint256 => VoterHistory[]) public voterHistories;
mapping(uint256 => CandidateHistory[]) public candidateHistories;
mapping(uint256 => VoteCountHistory[]) public voteCountHistories;
modifier onlyActiveElection() {
require(electionActive, "Election is not active");
_;
}
modifier onlyOwner() {
require(msg.sender == owner, "Only contract owner can call this function");
_;
}
constructor() {
owner = payable(msg.sender);
electionActive = true;
}
function addVoter(uint256 _id, string memory _name, string memory _email, string memory _password) public onlyOwner {
require(voters[_id].id == 0, "Voter already registered");
voters[_id] = Voter({
id: _id,
name: _name,
email: _email,
hasVoted: false,
passwordHash: keccak256(abi.encodePacked(_password)),
lastUpdated: block.timestamp,
isActive: true,
transactionHash: blockhash(block.number - 1),
blockNumber: block.number
});
voterIds.push(_id);
emit VoterAdded(_id, _name);
}
function updateVoter(uint256 _id, string memory _name, string memory _email, string memory _password) public onlyOwner {
require(voters[_id].id != 0, "Voter not registered");
// Record the current state to history before updating
voterHistories[_id].push(VoterHistory({
id: _id,
name: voters[_id].name,
email: voters[_id].email,
hasVoted: voters[_id].hasVoted,
passwordHash: voters[_id].passwordHash,
timestamp: block.timestamp,
transactionHash: blockhash(block.number - 1),
blockNumber: block.number
}));
voters[_id].name = _name;
voters[_id].email = _email;
voters[_id].passwordHash = keccak256(abi.encodePacked(_password));
voters[_id].lastUpdated = block.timestamp;
voters[_id].transactionHash = blockhash(block.number - 1);
voters[_id].blockNumber = block.number;
emit VoterUpdated(_id, _name);
}
function deleteVoter(uint256 _id) public onlyOwner {
require(voters[_id].id != 0, "Voter not registered");
// Record the current state to history before deleting
voterHistories[_id].push(VoterHistory({
id: _id,
name: voters[_id].name,
email: voters[_id].email,
hasVoted: voters[_id].hasVoted,
passwordHash: voters[_id].passwordHash,
timestamp: block.timestamp,
transactionHash: blockhash(block.number - 1),
blockNumber: block.number
}));
voters[_id].isActive = false; // Mark voter as inactive instead of deleting
emit VoterDeleted(_id, voters[_id].name);
}
function addCandidate(uint256 _id, string memory _name, string memory _visi, string memory _misi) public onlyOwner {
require(candidates[_id].id == 0, "Candidate already exists");
candidates[_id] = Candidate({
id: _id,
name: _name,
visi: _visi,
misi: _misi,
voteCount: 0,
lastUpdated: block.timestamp,
isActive: true,
transactionHash: blockhash(block.number - 1),
blockNumber: block.number
});
candidateIds.push(_id);
emit CandidateAdded(_id, _name);
}
function updateCandidate(uint256 _id, string memory _name, string memory _visi, string memory _misi) public onlyOwner {
require(candidates[_id].id != 0, "Candidate not registered");
// Record the current state to history before updating
candidateHistories[_id].push(CandidateHistory({
id: _id,
name: candidates[_id].name,
visi: candidates[_id].visi,
misi: candidates[_id].misi,
voteCount: candidates[_id].voteCount,
timestamp: block.timestamp,
transactionHash: blockhash(block.number - 1),
blockNumber: block.number
}));
candidates[_id].name = _name;
candidates[_id].visi = _visi;
candidates[_id].misi = _misi;
candidates[_id].lastUpdated = block.timestamp;
candidates[_id].transactionHash = blockhash(block.number - 1);
candidates[_id].blockNumber = block.number;
emit CandidateUpdated(_id, _name);
}
function deleteCandidate(uint256 _id) public onlyOwner {
require(candidates[_id].id != 0, "Candidate not registered");
// Record the current state to history before marking as inactive
candidateHistories[_id].push(CandidateHistory({
id: _id,
name: candidates[_id].name,
visi: candidates[_id].visi,
misi: candidates[_id].misi,
voteCount: candidates[_id].voteCount,
timestamp: block.timestamp,
transactionHash: blockhash(block.number - 1),
blockNumber: block.number
}));
candidates[_id].isActive = false; // Mark candidate as inactive instead of deleting
emit CandidateDeleted(_id, candidates[_id].name);
}
function vote(uint256 _voterId, uint256 _candidateId, string memory _password) public onlyActiveElection {
require(voters[_voterId].id != 0, "Voter not registered");
require(!voters[_voterId].hasVoted, "Voter already voted");
require(candidates[_candidateId].id != 0, "Candidate not found");
require(voters[_voterId].passwordHash == keccak256(abi.encodePacked(_password)), "Invalid password");
// Record the current state to history before voting
voterHistories[_voterId].push(VoterHistory({
id: _voterId,
name: voters[_voterId].name,
email: voters[_voterId].email,
hasVoted: voters[_voterId].hasVoted,
passwordHash: voters[_voterId].passwordHash,
timestamp: block.timestamp,
transactionHash: blockhash(block.number - 1),
blockNumber: block.number
}));
candidates[_candidateId].voteCount++;
// Record vote count history
voteCountHistories[_candidateId].push(VoteCountHistory({
candidateId: _candidateId,
voteCount: candidates[_candidateId].voteCount,
timestamp: block.timestamp,
transactionHash: blockhash(block.number - 1),
blockNumber: block.number
}));
voters[_voterId].hasVoted = true;
voters[_voterId].lastUpdated = block.timestamp;
voters[_voterId].transactionHash = blockhash(block.number - 1);
voters[_voterId].blockNumber = block.number;
}
function endElection() public onlyOwner {
electionActive = false;
emit ElectionEnded();
}
function getVoteCount(uint256 _candidateId) public view returns (uint256) {
require(candidates[_candidateId].id != 0, "Candidate not found");
return candidates[_candidateId].voteCount;
}
function getAllVoters() public view returns (Voter[] memory) {
uint256 activeCount = 0;
// Count active voters
for (uint256 i = 0; i < voterIds.length; i++) {
if (voters[voterIds[i]].isActive) {
activeCount++;
}
}
Voter[] memory allVoters = new Voter[](activeCount);
uint256 index = 0;
for (uint256 i = 0; i < voterIds.length; i++) {
uint256 voterId = voterIds[i];
if (voters[voterId].isActive) {
allVoters[index] = voters[voterId];
index++;
}
}
return allVoters;
}
function getAllCandidates() public view returns (Candidate[] memory) {
Candidate[] memory allCandidates = new Candidate[](candidateIds.length);
uint256 index = 0;
for (uint256 i = 0; i < candidateIds.length; i++) {
uint256 candidateId = candidateIds[i];
if (candidates[candidateId].id != 0) {
allCandidates[index] = candidates[candidateId];
index++;
}
}
return allCandidates;
}
function isVoterEligible(uint256 _voterId) public view returns (bool) {
return voters[_voterId].id != 0 && !voters[_voterId].hasVoted;
}
function getAllVoterHistories() public view returns (VoterHistory[] memory) {
uint256 totalHistories = 0;
// Count total histories
for (uint256 i = 0; i < voterIds.length; i++) {
totalHistories += voterHistories[voterIds[i]].length + 1; // +1 for initial state
}
VoterHistory[] memory allHistories = new VoterHistory[](totalHistories);
uint256 index = 0;
// Gather all histories
for (uint256 i = 0; i < voterIds.length; i++) {
uint256 voterId = voterIds[i];
// Add initial state
allHistories[index] = VoterHistory({
id: voters[voterId].id,
name: voters[voterId].name,
email: voters[voterId].email,
hasVoted: voters[voterId].hasVoted,
passwordHash: voters[voterId].passwordHash,
timestamp: voters[voterId].lastUpdated,
transactionHash: voters[voterId].transactionHash,
blockNumber: voters[voterId].blockNumber
});
index++;
// Add historical states
VoterHistory[] memory histories = voterHistories[voterId];
for (uint256 j = 0; j < histories.length; j++) {
allHistories[index] = histories[j];
index++;
}
}
return allHistories;
}
function getAllCandidateHistories() public view returns (CandidateHistory[] memory) {
uint256 totalHistories = 0;
// Count total histories
for (uint256 i = 0; i < candidateIds.length; i++) {
totalHistories += candidateHistories[candidateIds[i]].length + 1; // +1 for initial state
}
CandidateHistory[] memory allHistories = new CandidateHistory[](totalHistories);
uint256 index = 0;
// Gather all histories
for (uint256 i = 0; i < candidateIds.length; i++) {
uint256 candidateId = candidateIds[i];
// Add initial state
allHistories[index] = CandidateHistory({
id: candidates[candidateId].id,
name: candidates[candidateId].name,
visi: candidates[candidateId].visi,
misi: candidates[candidateId].misi,
voteCount: candidates[candidateId].voteCount,
timestamp: candidates[candidateId].lastUpdated,
transactionHash: candidates[candidateId].transactionHash,
blockNumber: candidates[candidateId].blockNumber
});
index++;
// Add historical states
CandidateHistory[] memory histories = candidateHistories[candidateId];
for (uint256 j = 0; j < histories.length; j++) {
allHistories[index] = histories[j];
index++;
}
}
return allHistories;
}
function getAllVoteCountHistories() public view returns (VoteCountHistory[] memory) {
uint256 totalHistories = 0;
// Count total histories
for (uint256 i = 0; i < candidateIds.length; i++) {
totalHistories += voteCountHistories[candidateIds[i]].length;
}
VoteCountHistory[] memory allHistories = new VoteCountHistory[](totalHistories);
uint256 index = 0;
// Gather all histories
for (uint256 i = 0; i < candidateIds.length; i++) {
uint256 candidateId = candidateIds[i];
VoteCountHistory[] memory histories = voteCountHistories[candidateId];
for (uint256 j = 0; j < histories.length; j++) {
allHistories[index] = histories[j];
index++;
}
}
return allHistories;
}
// Add login function
function login(uint256 _voterId, string memory _password) public view returns (string memory, bool) {
Voter memory voter = voters[_voterId];
if (voter.id != 0 && voter.passwordHash == keccak256(abi.encodePacked(_password))) {
return (voter.name, true);
} else {
return ("", false);
}
}
}

View File

@ -0,0 +1,22 @@
require("@nomicfoundation/hardhat-toolbox");
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: "0.8.24",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
networks: {
// Daftar jaringan lainnya
volta: {
url: "https://volta-rpc.energyweb.org/", // Ganti dengan URL RPC jaringan Volta
},
},
paths: {
contracts: "./contracts",
artifacts: "./artifacts",
},
};

View File

@ -0,0 +1,15 @@
const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules");
const JAN_1ST_2030 = 1893456000;
const ONE_GWEI = 1_000_000_000n;
module.exports = buildModule("LockModule", (m) => {
const unlockTime = m.getParameter("unlockTime", JAN_1ST_2030);
const lockedAmount = m.getParameter("lockedAmount", ONE_GWEI);
const lock = m.contract("Lock", [unlockTime], {
value: lockedAmount,
});
return { lock };
});

View File

@ -0,0 +1,323 @@
const ethers = require('ethers');
require('dotenv').config();
const express = require('express');
const jwt = require('jsonwebtoken');
const API_URL = process.env.API_URL;
const PRIVATE_KEY = process.env.PRIVATE_KEY;
const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESS;
const JWT_SECRET = process.env.JWT_SECRET;
const provider = new ethers.providers.JsonRpcProvider(API_URL);
const signer = new ethers.Wallet(PRIVATE_KEY, provider);
const { abi } = require("./artifacts/contracts/Election.sol/Election.json");
const contractInstance = new ethers.Contract(CONTRACT_ADDRESS, abi, signer);
const app = express();
app.use(express.json());
// Function to sign and send a transaction
const sendTransaction = async (method, ...params) => {
const tx = await contractInstance[method](...params);
return tx.wait();
};
// Endpoint for login
app.post('/login', async (req, res) => {
const { voterId, password } = req.body;
try {
const [name, isLoginSuccessful] = await contractInstance.login(voterId, password);
if (isLoginSuccessful) {
const token = jwt.sign({ voterId }, JWT_SECRET, { expiresIn: '1h' });
res.json({
error: false,
message: "success",
loginResult: {
userId: voterId,
name: name,
token: token
}
});
} else {
res.status(401).json({ error: true, message: "Invalid credentials" });
}
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to add a new voter
app.post('/voters', async (req, res) => {
const { id, name, email, password } = req.body;
try {
const receipt = await sendTransaction('addVoter', id, name, email, password);
res.json({ receipt });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to update a voter
app.put('/voters/:id', async (req, res) => {
const { id } = req.params;
const { name, email, password } = req.body;
try {
const receipt = await sendTransaction('updateVoter', id, name, email, password);
res.json({ receipt });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to delete a voter
app.delete('/voters/:id', async (req, res) => {
const { id } = req.params;
try {
const receipt = await sendTransaction('deleteVoter', id);
res.json({ receipt });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to add a new candidate
app.post('/candidates', async (req, res) => {
const { id, name, visi, misi } = req.body;
try {
const receipt = await sendTransaction('addCandidate', id, name, visi, misi);
res.json({ receipt });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to update a candidate
app.put('/candidates/:id', async (req, res) => {
const { id } = req.params;
const { name, visi, misi } = req.body;
try {
const receipt = await sendTransaction('updateCandidate', id, name, visi, misi);
res.json({ receipt });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to delete a candidate
app.delete('/candidates/:id', async (req, res) => {
const { id } = req.params;
try {
const receipt = await sendTransaction('deleteCandidate', id);
res.json({ receipt });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to get all voters
app.get('/voters', async (req, res) => {
try {
const allVoters = await contractInstance.getAllVoters();
const response = {
error: false,
message: "Voters fetched successfully",
voters: allVoters.map(voter => ({
id: voter.id,
name: voter.name,
email: voter.email,
password: voter.password,
hasVoted: voter.hasVoted,
lastUpdated: voter.lastUpdated,
transactionHash: voter.transactionHash,
blockNumber: voter.blockNumber
}))
};
res.json(response);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to get all candidates
app.get('/candidates', async (req, res) => {
try {
const allCandidates = await contractInstance.getAllCandidates();
const response = {
error: false,
message: "Candidates fetched successfully",
candidates: allCandidates.map(candidate => ({
id: candidate.id,
name: candidate.name,
visi: candidate.visi,
misi: candidate.misi,
voteCount: candidate.voteCount,
lastUpdated: candidate.lastUpdated,
transactionHash: candidate.transactionHash,
blockNumber: candidate.blockNumber
}))
};
res.json(response);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to get a specific voter by ID
app.get('/voters/:id', async (req, res) => {
const voterId = req.params.id;
try {
const voter = await contractInstance.voters(voterId);
res.json({
id: voter.id,
name: voter.name,
email: voter.email,
password: voter.password,
hasVoted: voter.hasVoted,
lastUpdated: voter.lastUpdated,
transactionHash: voter.transactionHash,
blockNumber: voter.blockNumber
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to get a specific candidate by ID
app.get('/candidates/:id', async (req, res) => {
const candidateId = req.params.id;
try {
const candidate = await contractInstance.candidates(candidateId);
res.json({
id: candidate.id,
name: candidate.name,
visi: candidate.visi,
misi: candidate.misi,
voteCount: candidate.voteCount,
lastUpdated: candidate.lastUpdated,
transactionHash: candidate.transactionHash,
blockNumber: candidate.blockNumber
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to vote
app.post('/vote', async (req, res) => {
const { voterId, candidateId, password } = req.body;
try {
const receipt = await sendTransaction('vote', voterId, candidateId, password);
res.json({ receipt });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to get vote count for a candidate
app.get('/vote-count/:id', async (req, res) => {
const candidateId = req.params.id;
try {
const voteCount = await contractInstance.getVoteCount(candidateId);
res.json({ voteCount });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to get vote count for all candidates
app.get('/vote-counts', async (req, res) => {
try {
const allCandidates = await contractInstance.getAllCandidates();
const voteCounts = allCandidates.map(candidate => ({
id: candidate.id,
voteCount: candidate.voteCount
}));
res.json({ voteCounts });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to get vote status of a user
app.get('/voteStatus/:userId', async (req, res) => {
const { userId } = req.params;
try {
const voter = await contractInstance.voters(userId);
if (!voter.id) {
return res.status(404).json({ hasVoted: false });
}
res.json({ hasVoted: voter.hasVoted });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to get voter history
app.get('/voter-history/:id', async (req, res) => {
const voterId = req.params.id;
try {
const history = await contractInstance.getVoterHistory(voterId);
res.json(history);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to get candidate history
app.get('/candidate-history/:id', async (req, res) => {
const candidateId = req.params.id;
try {
const history = await contractInstance.getCandidateHistory(candidateId);
res.json(history);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to get vote count history
app.get('/vote-count-history/:id', async (req, res) => {
const candidateId = req.params.id;
try {
const history = await contractInstance.getVoteCountHistory(candidateId);
res.json(history);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to get all voter histories
app.get('/all-voter-histories', async (req, res) => {
try {
const allHistories = await contractInstance.getAllVoterHistories();
res.json(allHistories);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to get all candidate histories
app.get('/all-candidate-histories', async (req, res) => {
try {
const allHistories = await contractInstance.getAllCandidateHistories();
res.json(allHistories);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Endpoint to get all vote count histories
app.get('/all-vote-count-histories', async (req, res) => {
try {
const allHistories = await contractInstance.getAllVoteCountHistories();
res.json(allHistories);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(3000, () => {
console.log('Election API listening at http://localhost:3000');
});

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,25 @@
{
"name": "election-api",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node index.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"@nomicfoundation/hardhat-toolbox": "^2.0.1",
"dotenv": "^16.0.3",
"ethers": "^5.7.1",
"express": "^4.18.2",
"express-fileupload": "^1.4.0",
"hardhat": "^2.22.3",
"jsonwebtoken": "^9.0.2",
"path": "^0.12.7"
},
"devDependencies": {
"@nomicfoundation/hardhat-verify": "^2.0.6"
}
}

View File

@ -0,0 +1,17 @@
const hre = require("hardhat");
async function main() {
const Election = await hre.ethers.getContractFactory("Election");
const election_ = await Election.deploy();
await election_.deployed();
console.log(
`Contract Address: ${election_.address}`
);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});

View File

@ -0,0 +1,126 @@
const {
time,
loadFixture,
} = require("@nomicfoundation/hardhat-toolbox/network-helpers");
const { anyValue } = require("@nomicfoundation/hardhat-chai-matchers/withArgs");
const { expect } = require("chai");
describe("Lock", function () {
// We define a fixture to reuse the same setup in every test.
// We use loadFixture to run this setup once, snapshot that state,
// and reset Hardhat Network to that snapshot in every test.
async function deployOneYearLockFixture() {
const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60;
const ONE_GWEI = 1_000_000_000;
const lockedAmount = ONE_GWEI;
const unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS;
// Contracts are deployed using the first signer/account by default
const [owner, otherAccount] = await ethers.getSigners();
const Lock = await ethers.getContractFactory("Lock");
const lock = await Lock.deploy(unlockTime, { value: lockedAmount });
return { lock, unlockTime, lockedAmount, owner, otherAccount };
}
describe("Deployment", function () {
it("Should set the right unlockTime", async function () {
const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture);
expect(await lock.unlockTime()).to.equal(unlockTime);
});
it("Should set the right owner", async function () {
const { lock, owner } = await loadFixture(deployOneYearLockFixture);
expect(await lock.owner()).to.equal(owner.address);
});
it("Should receive and store the funds to lock", async function () {
const { lock, lockedAmount } = await loadFixture(
deployOneYearLockFixture
);
expect(await ethers.provider.getBalance(lock.target)).to.equal(
lockedAmount
);
});
it("Should fail if the unlockTime is not in the future", async function () {
// We don't use the fixture here because we want a different deployment
const latestTime = await time.latest();
const Lock = await ethers.getContractFactory("Lock");
await expect(Lock.deploy(latestTime, { value: 1 })).to.be.revertedWith(
"Unlock time should be in the future"
);
});
});
describe("Withdrawals", function () {
describe("Validations", function () {
it("Should revert with the right error if called too soon", async function () {
const { lock } = await loadFixture(deployOneYearLockFixture);
await expect(lock.withdraw()).to.be.revertedWith(
"You can't withdraw yet"
);
});
it("Should revert with the right error if called from another account", async function () {
const { lock, unlockTime, otherAccount } = await loadFixture(
deployOneYearLockFixture
);
// We can increase the time in Hardhat Network
await time.increaseTo(unlockTime);
// We use lock.connect() to send a transaction from another account
await expect(lock.connect(otherAccount).withdraw()).to.be.revertedWith(
"You aren't the owner"
);
});
it("Shouldn't fail if the unlockTime has arrived and the owner calls it", async function () {
const { lock, unlockTime } = await loadFixture(
deployOneYearLockFixture
);
// Transactions are sent using the first signer by default
await time.increaseTo(unlockTime);
await expect(lock.withdraw()).not.to.be.reverted;
});
});
describe("Events", function () {
it("Should emit an event on withdrawals", async function () {
const { lock, unlockTime, lockedAmount } = await loadFixture(
deployOneYearLockFixture
);
await time.increaseTo(unlockTime);
await expect(lock.withdraw())
.to.emit(lock, "Withdrawal")
.withArgs(lockedAmount, anyValue); // We accept any value as `when` arg
});
});
describe("Transfers", function () {
it("Should transfer the funds to the owner", async function () {
const { lock, unlockTime, lockedAmount, owner } = await loadFixture(
deployOneYearLockFixture
);
await time.increaseTo(unlockTime);
await expect(lock.withdraw()).to.changeEtherBalances(
[owner, lock],
[lockedAmount, -lockedAmount]
);
});
});
});
});

View File

@ -0,0 +1,15 @@
{
"version": 2,
"builds": [
{
"src": "index.js",
"use": "@vercel/node"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "index.js"
}
]
}

View File

@ -0,0 +1 @@
01d50f22d405dfe756d340bb99518cabc86d482b7f8d03722164c196406af71f

Binary file not shown.

View File

@ -0,0 +1 @@
enode://968165baa9dcb895735ab6ee442703ea28ea69e0b61bd855cb37e9d14d71e06141616c454a19954212c798cfdf7a5104fb0a045b9898ca67489a3fef0f4cac26@127.0.0.1:0?discport=30301

View File

@ -0,0 +1,26 @@
{
"config": {
"chainId": 120202,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"berlinBlock": 0,
"clique": {
"period": 5,
"epoch": 30000
}
},
"difficulty": "1",
"gasLimit": "8000000",
"extradata": "0x00000000000000000000000000000000000000000000000000000000000000004258347DeDB78fBDFd5891Da6c280f1fd3d3c4910000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"alloc": {
"4258347DeDB78fBDFd5891Da6c280f1fd3d3c491": { "balance": "1000000000000000000000000000000" },
"FB6Cd3f865570b3f86631c71dE0Efce5Be0940D3": { "balance": "1000000000000000000000000000000" },
"bF3fe388cd2B24248fBA34b13F549078ece6A727": { "balance": "1000000000000000000000000000000" }
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
MANIFEST-000037

View File

@ -0,0 +1,107 @@
[Version]
pebble_version=0.1
[Options]
bytes_per_sync=524288
cache_size=536870912
cleaner=delete
compaction_debt_concurrency=1073741824
comparer=leveldb.BytewiseComparator
disable_wal=false
flush_delay_delete_range=0s
flush_delay_range_key=0s
flush_split_bytes=4194304
format_major_version=1
l0_compaction_concurrency=10
l0_compaction_file_threshold=500
l0_compaction_threshold=4
l0_stop_writes_threshold=12
lbase_max_bytes=67108864
max_concurrent_compactions=8
max_manifest_file_size=134217728
max_open_files=524288
mem_table_size=134217728
mem_table_stop_writes_threshold=2
min_deletion_rate=0
merger=pebble.concatenate
read_compaction_rate=16000
read_sampling_multiplier=-1
strict_wal_tail=true
table_cache_shards=8
table_property_collectors=[]
validate_on_ingest=false
wal_dir=
wal_bytes_per_sync=0
max_writer_concurrency=0
force_writer_parallelism=false
secondary_cache_size_bytes=0
[Level "0"]
block_restart_interval=16
block_size=4096
block_size_threshold=90
compression=Snappy
filter_policy=rocksdb.BuiltinBloomFilter
filter_type=table
index_block_size=4096
target_file_size=2097152
[Level "1"]
block_restart_interval=16
block_size=4096
block_size_threshold=90
compression=Snappy
filter_policy=rocksdb.BuiltinBloomFilter
filter_type=table
index_block_size=4096
target_file_size=2097152
[Level "2"]
block_restart_interval=16
block_size=4096
block_size_threshold=90
compression=Snappy
filter_policy=rocksdb.BuiltinBloomFilter
filter_type=table
index_block_size=4096
target_file_size=2097152
[Level "3"]
block_restart_interval=16
block_size=4096
block_size_threshold=90
compression=Snappy
filter_policy=rocksdb.BuiltinBloomFilter
filter_type=table
index_block_size=4096
target_file_size=2097152
[Level "4"]
block_restart_interval=16
block_size=4096
block_size_threshold=90
compression=Snappy
filter_policy=rocksdb.BuiltinBloomFilter
filter_type=table
index_block_size=4096
target_file_size=2097152
[Level "5"]
block_restart_interval=16
block_size=4096
block_size_threshold=90
compression=Snappy
filter_policy=rocksdb.BuiltinBloomFilter
filter_type=table
index_block_size=4096
target_file_size=2097152
[Level "6"]
block_restart_interval=16
block_size=4096
block_size_threshold=90
compression=Snappy
filter_policy=rocksdb.BuiltinBloomFilter
filter_type=table
index_block_size=4096
target_file_size=2097152

View File

@ -0,0 +1 @@
<EFBFBD><01>

View File

@ -0,0 +1 @@
<EFBFBD><01>

View File

@ -0,0 +1 @@
<EFBFBD><01>

View File

@ -0,0 +1 @@
<EFBFBD><01>

View File

@ -0,0 +1 @@
0x2637865a56823c3cdb62ea6e775d6dfd0ef2de98c60de8d09ddb73fec4cdbaa6

View File

@ -0,0 +1 @@
MANIFEST-000001

View File

@ -0,0 +1,107 @@
[Version]
pebble_version=0.1
[Options]
bytes_per_sync=524288
cache_size=16777216
cleaner=delete
compaction_debt_concurrency=1073741824
comparer=leveldb.BytewiseComparator
disable_wal=false
flush_delay_delete_range=0s
flush_delay_range_key=0s
flush_split_bytes=4194304
format_major_version=1
l0_compaction_concurrency=10
l0_compaction_file_threshold=500
l0_compaction_threshold=4
l0_stop_writes_threshold=12
lbase_max_bytes=67108864
max_concurrent_compactions=8
max_manifest_file_size=134217728
max_open_files=16
mem_table_size=4194304
mem_table_stop_writes_threshold=2
min_deletion_rate=0
merger=pebble.concatenate
read_compaction_rate=16000
read_sampling_multiplier=-1
strict_wal_tail=true
table_cache_shards=8
table_property_collectors=[]
validate_on_ingest=false
wal_dir=
wal_bytes_per_sync=0
max_writer_concurrency=0
force_writer_parallelism=false
secondary_cache_size_bytes=0
[Level "0"]
block_restart_interval=16
block_size=4096
block_size_threshold=90
compression=Snappy
filter_policy=rocksdb.BuiltinBloomFilter
filter_type=table
index_block_size=4096
target_file_size=2097152
[Level "1"]
block_restart_interval=16
block_size=4096
block_size_threshold=90
compression=Snappy
filter_policy=rocksdb.BuiltinBloomFilter
filter_type=table
index_block_size=4096
target_file_size=2097152
[Level "2"]
block_restart_interval=16
block_size=4096
block_size_threshold=90
compression=Snappy
filter_policy=rocksdb.BuiltinBloomFilter
filter_type=table
index_block_size=4096
target_file_size=2097152
[Level "3"]
block_restart_interval=16
block_size=4096
block_size_threshold=90
compression=Snappy
filter_policy=rocksdb.BuiltinBloomFilter
filter_type=table
index_block_size=4096
target_file_size=2097152
[Level "4"]
block_restart_interval=16
block_size=4096
block_size_threshold=90
compression=Snappy
filter_policy=rocksdb.BuiltinBloomFilter
filter_type=table
index_block_size=4096
target_file_size=2097152
[Level "5"]
block_restart_interval=16
block_size=4096
block_size_threshold=90
compression=Snappy
filter_policy=rocksdb.BuiltinBloomFilter
filter_type=table
index_block_size=4096
target_file_size=2097152
[Level "6"]
block_restart_interval=16
block_size=4096
block_size_threshold=90
compression=Snappy
filter_policy=rocksdb.BuiltinBloomFilter
filter_type=table
index_block_size=4096
target_file_size=2097152

View File

@ -0,0 +1 @@
7ba18c866a4de9a8a4da97d707f432c9fe820843191ae63a59e8cc7dc52b2abb

Some files were not shown because too many files have changed in this diff Show More