Skip to content

Commit

Permalink
init hardhat
Browse files Browse the repository at this point in the history
  • Loading branch information
cyri113 committed Jul 18, 2024
0 parents commit 74fe57a
Show file tree
Hide file tree
Showing 9 changed files with 3,972 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -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
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.ts
```
34 changes: 34 additions & 0 deletions contracts/Lock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

// Uncomment this line to use console.log
// import "hardhat/console.sol";

contract Lock {
uint public unlockTime;
address payable public owner;

event Withdrawal(uint amount, uint when);

constructor(uint _unlockTime) payable {
require(
block.timestamp < _unlockTime,
"Unlock time should be in the future"
);

unlockTime = _unlockTime;
owner = payable(msg.sender);
}

function withdraw() public {
// Uncomment this line, and the import of "hardhat/console.sol", to print a log in your terminal
// console.log("Unlock time is %o and block timestamp is %o", unlockTime, block.timestamp);

require(block.timestamp >= unlockTime, "You can't withdraw yet");
require(msg.sender == owner, "You aren't the owner");

emit Withdrawal(address(this).balance, block.timestamp);

owner.transfer(address(this).balance);
}
}
8 changes: 8 additions & 0 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox-viem";

const config: HardhatUserConfig = {
solidity: "0.8.24",
};

export default config;
18 changes: 18 additions & 0 deletions ignition/modules/Lock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
import { parseEther } from "viem";

const JAN_1ST_2030 = 1893456000;
const ONE_GWEI: bigint = parseEther("0.001");

const LockModule = 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 };
});

export default LockModule;
27 changes: 27 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "contracts",
"version": "1.0.0",
"main": "index.js",
"repository": "https://github.com/TogetherCrew/contracts.git",
"author": "Cyrille Derche <[email protected]>",
"license": "MIT",
"devDependencies": {
"@nomicfoundation/hardhat-ignition": "^0.15.0",
"@nomicfoundation/hardhat-ignition-viem": "^0.15.0",
"@nomicfoundation/hardhat-network-helpers": "^1.0.0",
"@nomicfoundation/hardhat-toolbox-viem": "^3.0.0",
"@nomicfoundation/hardhat-verify": "^2.0.0",
"@nomicfoundation/hardhat-viem": "^2.0.0",
"@types/chai": "^4.2.0",
"@types/chai-as-promised": "^7.1.6",
"@types/mocha": ">=9.1.0",
"@types/node": ">=18.0.0",
"chai": "^4.2.0",
"hardhat": "^2.22.6",
"hardhat-gas-reporter": "^1.0.8",
"solidity-coverage": "^0.8.0",
"ts-node": ">=8.0.0",
"typescript": "~5.0.4",
"viem": "^2.7.6"
}
}
134 changes: 134 additions & 0 deletions test/Lock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import {
time,
loadFixture,
} from "@nomicfoundation/hardhat-toolbox-viem/network-helpers";
import { expect } from "chai";
import hre from "hardhat";
import { getAddress, parseGwei } from "viem";

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 lockedAmount = parseGwei("1");
const unlockTime = BigInt((await time.latest()) + ONE_YEAR_IN_SECS);

// Contracts are deployed using the first signer/account by default
const [owner, otherAccount] = await hre.viem.getWalletClients();

const lock = await hre.viem.deployContract("Lock", [unlockTime], {
value: lockedAmount,
});

const publicClient = await hre.viem.getPublicClient();

return {
lock,
unlockTime,
lockedAmount,
owner,
otherAccount,
publicClient,
};
}

describe("Deployment", function () {
it("Should set the right unlockTime", async function () {
const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture);

expect(await lock.read.unlockTime()).to.equal(unlockTime);
});

it("Should set the right owner", async function () {
const { lock, owner } = await loadFixture(deployOneYearLockFixture);

expect(await lock.read.owner()).to.equal(
getAddress(owner.account.address)
);
});

it("Should receive and store the funds to lock", async function () {
const { lock, lockedAmount, publicClient } = await loadFixture(
deployOneYearLockFixture
);

expect(
await publicClient.getBalance({
address: lock.address,
})
).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 = BigInt(await time.latest());
await expect(
hre.viem.deployContract("Lock", [latestTime], {
value: 1n,
})
).to.be.rejectedWith("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.write.withdraw()).to.be.rejectedWith(
"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 retrieve the contract with a different account to send a transaction
const lockAsOtherAccount = await hre.viem.getContractAt(
"Lock",
lock.address,
{ client: { wallet: otherAccount } }
);
await expect(lockAsOtherAccount.write.withdraw()).to.be.rejectedWith(
"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.write.withdraw()).to.be.fulfilled;
});
});

describe("Events", function () {
it("Should emit an event on withdrawals", async function () {
const { lock, unlockTime, lockedAmount, publicClient } =
await loadFixture(deployOneYearLockFixture);

await time.increaseTo(unlockTime);

const hash = await lock.write.withdraw();
await publicClient.waitForTransactionReceipt({ hash });

// get the withdrawal events in the latest block
const withdrawalEvents = await lock.getEvents.Withdrawal();
expect(withdrawalEvents).to.have.lengthOf(1);
expect(withdrawalEvents[0].args.amount).to.equal(lockedAmount);
});
});
});
});
11 changes: 11 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"resolveJsonModule": true
}
}
Loading

0 comments on commit 74fe57a

Please sign in to comment.