refactor: move brother_node development artifact to dev/test-nodes subdirectory

Development Artifact Cleanup:
 BROTHER_NODE REORGANIZATION: Moved development test node to appropriate location
- dev/test-nodes/brother_node/: Moved from root directory for better organization
- Contains development configuration, test logs, and test chain data
- No impact on production systems - purely development/testing artifact

 DEVELOPMENT ARTIFACTS IDENTIFIED:
- Chain ID: aitbc-brother-chain (test/development chain)
- Ports: 8010 (P2P) and 8011 (RPC) - different from production
- Environment: .env file with test configuration
- Logs: rpc.log and node.log from development testing session (March 15, 2026)

 ROOT DIRECTORY CLEANUP: Removed development clutter from production directory
- brother_node/ moved to dev/test-nodes/brother_node/
- Root directory now contains only production-ready components
- Development artifacts properly organized in dev/ subdirectory

DIRECTORY STRUCTURE IMPROVEMENT:
📁 dev/test-nodes/: Development and testing node configurations
🏗️ Root Directory: Clean production structure with only essential components
🧪 Development Isolation: Test environments separated from production

BENEFITS:
 Clean Production Directory: No development artifacts in root
 Better Organization: Development nodes grouped in dev/ subdirectory
 Clear Separation: Production vs development environments clearly distinguished
 Maintainability: Easier to identify and manage development components

RESULT: Successfully moved brother_node development artifact to dev/test-nodes/ subdirectory, cleaning up the root directory while preserving development testing environment for future use.
This commit is contained in:
2026-03-30 17:09:06 +02:00
parent bf730dcb4a
commit 816e258d4c
11734 changed files with 2001707 additions and 0 deletions

24
dev/env/node_modules/hardhat/templates/README.md generated vendored Executable file
View File

@@ -0,0 +1,24 @@
# Templates
This directory contains `hardhat --init` templates. A template serves as a blueprint for initializing a new project.
Each template is a directory with a `package.json` file and other template files.
The `package.json` file contains the template's metadata. The following fields are used during project initialization:
- `description`: A short description of the template which is displayed to the user during template selection.
- `devDependencies`: The list of dependencies that should be installed in the project.
- `peerDependencies`: The list of dependencies that should also be installed in the project as dev dependencies if the used package manager does not install peer dependencies by default.
Note that the `workspace:` prefix is stripped from the version of the template dependencies during project initialization.
The other template files are copied to the project during project initialization.
#### .gitignore files
Due to a limitation in npm, `.gitignore` files are always ignored during project packing/publishing (see https://github.com/npm/npm/issues/3763).
To work around this, we use the following convention:
- if a template file is named `gitignore`, it is copied to the project workspace as `.gitignore`;
- if a template file is named `.gitignore`, it is ignored during the project initialization (this should only affect local development, or future versions of `npm` if the aforementioned issue is resolved).

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,34 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
// 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);
}
}

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,6 @@
require("@nomicfoundation/hardhat-toolbox");
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: "0.8.28",
};

View File

@@ -0,0 +1,18 @@
// This setup uses Hardhat Ignition to manage smart contract deployments.
// Learn more about it at https://hardhat.org/ignition
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,23 @@
{
"name": "template-v2-mocha-ethers-js",
"private": true,
"version": "0.0.1",
"description": "A Javascript project using Mocha and Ethers.js",
"devDependencies": {
"@nomicfoundation/hardhat-chai-matchers": "^2.0.0",
"@nomicfoundation/hardhat-ethers": "^3.0.0",
"@nomicfoundation/hardhat-ignition": "^0.15.0",
"@nomicfoundation/hardhat-ignition-ethers": "^0.15.0",
"@nomicfoundation/hardhat-network-helpers": "^1.0.0",
"@nomicfoundation/hardhat-toolbox": "^6.0.0",
"@nomicfoundation/hardhat-verify": "^2.0.0",
"@typechain/ethers-v6": "^0.5.0",
"@typechain/hardhat": "^9.0.0",
"chai": "^4.2.0",
"ethers": "^6.4.0",
"hardhat": "^2.14.0",
"hardhat-gas-reporter": "^2.3.0",
"solidity-coverage": "^0.8.0",
"typechain": "^8.3.0"
}
}

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,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,34 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
// 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);
}
}

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,6 @@
require("@nomicfoundation/hardhat-toolbox");
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: "0.8.28",
};

View File

@@ -0,0 +1,18 @@
// This setup uses Hardhat Ignition to manage smart contract deployments.
// Learn more about it at https://hardhat.org/ignition
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
const JAN_1ST_2030 = 1893456000;
const ONE_GWEI = 1_000_000_000n;
export default 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,24 @@
{
"name": "template-v2-mocha-ethers-js-esm",
"private": true,
"version": "0.0.1",
"description": "A Javascript project using Mocha and Ethers.js (ESM)",
"type": "module",
"devDependencies": {
"@nomicfoundation/hardhat-chai-matchers": "^2.0.0",
"@nomicfoundation/hardhat-ethers": "^3.0.0",
"@nomicfoundation/hardhat-ignition": "^0.15.0",
"@nomicfoundation/hardhat-ignition-ethers": "^0.15.0",
"@nomicfoundation/hardhat-network-helpers": "^1.0.0",
"@nomicfoundation/hardhat-toolbox": "^6.0.0",
"@nomicfoundation/hardhat-verify": "^2.0.0",
"@typechain/ethers-v6": "^0.5.0",
"@typechain/hardhat": "^9.0.0",
"chai": "^4.2.0",
"ethers": "^6.4.0",
"hardhat": "^2.14.0",
"hardhat-gas-reporter": "^2.3.0",
"solidity-coverage": "^0.8.0",
"typechain": "^8.3.0"
}
}

View File

@@ -0,0 +1,128 @@
import {
time,
loadFixture,
} from "@nomicfoundation/hardhat-toolbox/network-helpers.js";
import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs.js";
import chai from "chai";
const { expect } = 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,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
```

View File

@@ -0,0 +1,34 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
// 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);
}
}

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,8 @@
import type { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
const config: HardhatUserConfig = {
solidity: "0.8.28",
};
export default config;

View File

@@ -0,0 +1,20 @@
// This setup uses Hardhat Ignition to manage smart contract deployments.
// Learn more about it at https://hardhat.org/ignition
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
const JAN_1ST_2030 = 1893456000;
const ONE_GWEI: bigint = 1_000_000_000n;
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;

View File

@@ -0,0 +1,28 @@
{
"name": "template-v2-mocha-ethers-ts",
"private": true,
"version": "0.0.1",
"description": "A Typescript project using Mocha and Ethers.js",
"devDependencies": {
"@nomicfoundation/hardhat-chai-matchers": "^2.0.0",
"@nomicfoundation/hardhat-ethers": "^3.0.0",
"@nomicfoundation/hardhat-ignition": "^0.15.0",
"@nomicfoundation/hardhat-ignition-ethers": "^0.15.0",
"@nomicfoundation/hardhat-network-helpers": "^1.0.0",
"@nomicfoundation/hardhat-toolbox": "^6.0.0",
"@nomicfoundation/hardhat-verify": "^2.0.0",
"@typechain/ethers-v6": "^0.5.0",
"@typechain/hardhat": "^9.0.0",
"@types/chai": "^4.2.0",
"@types/mocha": ">=9.1.0",
"@types/node": ">=22.0.0",
"chai": "^4.2.0",
"ethers": "^6.4.0",
"hardhat": "^2.14.0",
"hardhat-gas-reporter": "^2.3.0",
"solidity-coverage": "^0.8.0",
"ts-node": ">=8.0.0",
"typechain": "^8.3.0",
"typescript": ">=4.5.0"
}
}

View File

@@ -0,0 +1,127 @@
import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs";
import {
time,
loadFixture,
} from "@nomicfoundation/hardhat-toolbox/network-helpers";
import { expect } from "chai";
import hre from "hardhat";
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 hre.ethers.getSigners();
const Lock = await hre.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 hre.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 hre.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,11 @@
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"resolveJsonModule": true
}
}

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.ts
```

View File

@@ -0,0 +1,34 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
// 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);
}
}

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,8 @@
import type { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox-viem";
const config: HardhatUserConfig = {
solidity: "0.8.28",
};
export default config;

View File

@@ -0,0 +1,21 @@
// This setup uses Hardhat Ignition to manage smart contract deployments.
// Learn more about it at https://hardhat.org/ignition
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;

View File

@@ -0,0 +1,25 @@
{
"name": "template-v2-mocha-viem-ts",
"private": true,
"version": "0.0.1",
"description": "A Typescript project using Mocha and Viem",
"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": "^4.1.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": ">=22.0.0",
"chai": "^4.2.0",
"hardhat": "^2.14.0",
"hardhat-gas-reporter": "^2.3.0",
"solidity-coverage": "^0.8.0",
"ts-node": ">=8.0.0",
"typescript": "~5.0.4",
"viem": "^2.43.0"
}
}

View File

@@ -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);
});
});
});
});

View File

@@ -0,0 +1,11 @@
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"resolveJsonModule": true
}
}

View File

@@ -0,0 +1,4 @@
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: "0.8.28",
};

View File

@@ -0,0 +1,9 @@
{
"name": "template-v2-empty-hardhat-config-js",
"private": true,
"version": "0.0.1",
"description": "An empty config file (hardhat.config.js)",
"devDependencies": {
"hardhat": "^2.14.0"
}
}

View File

@@ -0,0 +1,57 @@
# Sample Hardhat 3 Beta Project (`node:test` and `viem`)
This project showcases a Hardhat 3 Beta project using the native Node.js test runner (`node:test`) and the `viem` library for Ethereum interactions.
To learn more about the Hardhat 3 Beta, please visit the [Getting Started guide](https://hardhat.org/docs/getting-started#getting-started-with-hardhat-3). To share your feedback, join our [Hardhat 3 Beta](https://hardhat.org/hardhat3-beta-telegram-group) Telegram group or [open an issue](https://github.com/NomicFoundation/hardhat/issues/new) in our GitHub issue tracker.
## Project Overview
This example project includes:
- A simple Hardhat configuration file.
- Foundry-compatible Solidity unit tests.
- TypeScript integration tests using [`node:test`](nodejs.org/api/test.html), the new Node.js native test runner, and [`viem`](https://viem.sh/).
- Examples demonstrating how to connect to different types of networks, including locally simulating OP mainnet.
## Usage
### Running Tests
To run all the tests in the project, execute the following command:
```shell
npx hardhat test
```
You can also selectively run the Solidity or `node:test` tests:
```shell
npx hardhat test solidity
npx hardhat test nodejs
```
### Make a deployment to Sepolia
This project includes an example Ignition module to deploy the contract. You can deploy this module to a locally simulated chain or to Sepolia.
To run the deployment to a local chain:
```shell
npx hardhat ignition deploy ignition/modules/Counter.ts
```
To run the deployment to Sepolia, you need an account with funds to send the transaction. The provided Hardhat configuration includes a Configuration Variable called `SEPOLIA_PRIVATE_KEY`, which you can use to set the private key of the account you want to use.
You can set the `SEPOLIA_PRIVATE_KEY` variable using the `hardhat-keystore` plugin or by setting it as an environment variable.
To set the `SEPOLIA_PRIVATE_KEY` config variable using `hardhat-keystore`:
```shell
npx hardhat keystore set SEPOLIA_PRIVATE_KEY
```
After setting the variable, you can run the deployment with the Sepolia network:
```shell
npx hardhat ignition deploy --network sepolia ignition/modules/Counter.ts
```

View File

@@ -0,0 +1,19 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
contract Counter {
uint public x;
event Increment(uint by);
function inc() public {
x++;
emit Increment(1);
}
function incBy(uint by) public {
require(by > 0, "incBy: increment should be positive");
x += by;
emit Increment(by);
}
}

View File

@@ -0,0 +1,29 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import {Counter} from "./Counter.sol";
import {Test} from "forge-std/Test.sol";
contract CounterTest is Test {
Counter counter;
function setUp() public {
counter = new Counter();
}
function test_InitialValue() public view {
require(counter.x() == 0, "Initial value should be 0");
}
function testFuzz_Inc(uint8 x) public {
for (uint8 i = 0; i < x; i++) {
counter.inc();
}
require(counter.x() == x, "Value after calling inc x times should be x");
}
function test_IncByZero() public {
vm.expectRevert();
counter.incBy(0);
}
}

View File

@@ -0,0 +1,20 @@
# Node modules
/node_modules
# Compilation output
/dist
# pnpm deploy output
/bundle
# Hardhat Build Artifacts
/artifacts
# Hardhat compilation (v2) support directory
/cache
# Typechain output
/types
# Hardhat coverage reports
/coverage

View File

@@ -0,0 +1,38 @@
import hardhatToolboxViemPlugin from "@nomicfoundation/hardhat-toolbox-viem";
import { configVariable, defineConfig } from "hardhat/config";
export default defineConfig({
plugins: [hardhatToolboxViemPlugin],
solidity: {
profiles: {
default: {
version: "0.8.28",
},
production: {
version: "0.8.28",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},
},
},
networks: {
hardhatMainnet: {
type: "edr-simulated",
chainType: "l1",
},
hardhatOp: {
type: "edr-simulated",
chainType: "op",
},
sepolia: {
type: "http",
chainType: "l1",
url: configVariable("SEPOLIA_RPC_URL"),
accounts: [configVariable("SEPOLIA_PRIVATE_KEY")],
},
},
});

View File

@@ -0,0 +1,9 @@
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
export default buildModule("CounterModule", (m) => {
const counter = m.contract("Counter");
m.call(counter, "incBy", [5n]);
return { counter };
});

View File

@@ -0,0 +1,26 @@
{
"name": "template-node-test-runner-viem",
"private": true,
"version": "0.0.1",
"description": "A TypeScript Hardhat project using Node Test Runner and Viem",
"type": "module",
"devDependencies": {
"hardhat": "workspace:^3.1.10",
"@nomicfoundation/hardhat-toolbox-viem": "workspace:^5.0.2",
"@nomicfoundation/hardhat-ignition": "workspace:^3.0.8",
"@types/node": "^22.8.5",
"forge-std": "foundry-rs/forge-std#v1.9.4",
"typescript": "~5.8.0",
"viem": "^2.43.0"
},
"peerDependencies": {
"@nomicfoundation/hardhat-ignition-viem": "workspace:^3.0.8",
"@nomicfoundation/hardhat-keystore": "workspace:^3.0.5",
"@nomicfoundation/hardhat-network-helpers": "workspace:^3.0.4",
"@nomicfoundation/hardhat-node-test-runner": "workspace:^3.0.9",
"@nomicfoundation/hardhat-viem": "workspace:^3.0.3",
"@nomicfoundation/hardhat-viem-assertions": "workspace:^3.0.6",
"@nomicfoundation/hardhat-verify": "workspace:^3.0.11",
"@nomicfoundation/ignition-core": "workspace:^3.0.8"
}
}

View File

@@ -0,0 +1,31 @@
import { network } from "hardhat";
const { viem } = await network.connect({
network: "hardhatOp",
chainType: "op",
});
console.log("Sending transaction using the OP chain type");
const publicClient = await viem.getPublicClient();
const [senderClient] = await viem.getWalletClients();
console.log("Sending 1 wei from", senderClient.account.address, "to itself");
const l1Gas = await publicClient.estimateL1Gas({
account: senderClient.account.address,
to: senderClient.account.address,
value: 1n,
});
console.log("Estimated L1 gas:", l1Gas);
console.log("Sending L2 transaction");
const tx = await senderClient.sendTransaction({
to: senderClient.account.address,
value: 1n,
});
await publicClient.waitForTransactionReceipt({ hash: tx });
console.log("Transaction sent successfully");

View File

@@ -0,0 +1,46 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { network } from "hardhat";
describe("Counter", async function () {
const { viem } = await network.connect();
const publicClient = await viem.getPublicClient();
it("Should emit the Increment event when calling the inc() function", async function () {
const counter = await viem.deployContract("Counter");
await viem.assertions.emitWithArgs(
counter.write.inc(),
counter,
"Increment",
[1n],
);
});
it("The sum of the Increment events should match the current value", async function () {
const counter = await viem.deployContract("Counter");
const deploymentBlockNumber = await publicClient.getBlockNumber();
// run a series of increments
for (let i = 1n; i <= 10n; i++) {
await counter.write.incBy([i]);
}
const events = await publicClient.getContractEvents({
address: counter.address,
abi: counter.abi,
eventName: "Increment",
fromBlock: deploymentBlockNumber,
strict: true,
});
// check that the aggregated events match the current value
let total = 0n;
for (const event of events) {
total += event.args.by;
}
assert.equal(total, await counter.read.x());
});
});

View File

@@ -0,0 +1,13 @@
/* Based on https://github.com/tsconfig/bases/blob/501da2bcd640cf95c95805783e1012b992338f28/bases/node22.json */
{
"compilerOptions": {
"lib": ["es2023"],
"module": "node16",
"target": "es2022",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"moduleResolution": "node16",
"outDir": "dist"
}
}

View File

@@ -0,0 +1,57 @@
# Sample Hardhat 3 Beta Project (`mocha` and `ethers`)
This project showcases a Hardhat 3 Beta project using `mocha` for tests and the `ethers` library for Ethereum interactions.
To learn more about the Hardhat 3 Beta, please visit the [Getting Started guide](https://hardhat.org/docs/getting-started#getting-started-with-hardhat-3). To share your feedback, join our [Hardhat 3 Beta](https://hardhat.org/hardhat3-beta-telegram-group) Telegram group or [open an issue](https://github.com/NomicFoundation/hardhat/issues/new) in our GitHub issue tracker.
## Project Overview
This example project includes:
- A simple Hardhat configuration file.
- Foundry-compatible Solidity unit tests.
- TypeScript integration tests using `mocha` and ethers.js
- Examples demonstrating how to connect to different types of networks, including locally simulating OP mainnet.
## Usage
### Running Tests
To run all the tests in the project, execute the following command:
```shell
npx hardhat test
```
You can also selectively run the Solidity or `mocha` tests:
```shell
npx hardhat test solidity
npx hardhat test mocha
```
### Make a deployment to Sepolia
This project includes an example Ignition module to deploy the contract. You can deploy this module to a locally simulated chain or to Sepolia.
To run the deployment to a local chain:
```shell
npx hardhat ignition deploy ignition/modules/Counter.ts
```
To run the deployment to Sepolia, you need an account with funds to send the transaction. The provided Hardhat configuration includes a Configuration Variable called `SEPOLIA_PRIVATE_KEY`, which you can use to set the private key of the account you want to use.
You can set the `SEPOLIA_PRIVATE_KEY` variable using the `hardhat-keystore` plugin or by setting it as an environment variable.
To set the `SEPOLIA_PRIVATE_KEY` config variable using `hardhat-keystore`:
```shell
npx hardhat keystore set SEPOLIA_PRIVATE_KEY
```
After setting the variable, you can run the deployment with the Sepolia network:
```shell
npx hardhat ignition deploy --network sepolia ignition/modules/Counter.ts
```

View File

@@ -0,0 +1,19 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
contract Counter {
uint public x;
event Increment(uint by);
function inc() public {
x++;
emit Increment(1);
}
function incBy(uint by) public {
require(by > 0, "incBy: increment should be positive");
x += by;
emit Increment(by);
}
}

View File

@@ -0,0 +1,32 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import {Counter} from "./Counter.sol";
import {Test} from "forge-std/Test.sol";
// Solidity tests are compatible with foundry, so they
// use the same syntax and offer the same functionality.
contract CounterTest is Test {
Counter counter;
function setUp() public {
counter = new Counter();
}
function test_InitialValue() public view {
require(counter.x() == 0, "Initial value should be 0");
}
function testFuzz_Inc(uint8 x) public {
for (uint8 i = 0; i < x; i++) {
counter.inc();
}
require(counter.x() == x, "Value after calling inc x times should be x");
}
function test_IncByZero() public {
vm.expectRevert();
counter.incBy(0);
}
}

View File

@@ -0,0 +1,20 @@
# Node modules
/node_modules
# Compilation output
/dist
# pnpm deploy output
/bundle
# Hardhat Build Artifacts
/artifacts
# Hardhat compilation (v2) support directory
/cache
# Typechain output
/types
# Hardhat coverage reports
/coverage

View File

@@ -0,0 +1,38 @@
import hardhatToolboxMochaEthersPlugin from "@nomicfoundation/hardhat-toolbox-mocha-ethers";
import { configVariable, defineConfig } from "hardhat/config";
export default defineConfig({
plugins: [hardhatToolboxMochaEthersPlugin],
solidity: {
profiles: {
default: {
version: "0.8.28",
},
production: {
version: "0.8.28",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},
},
},
networks: {
hardhatMainnet: {
type: "edr-simulated",
chainType: "l1",
},
hardhatOp: {
type: "edr-simulated",
chainType: "op",
},
sepolia: {
type: "http",
chainType: "l1",
url: configVariable("SEPOLIA_RPC_URL"),
accounts: [configVariable("SEPOLIA_PRIVATE_KEY")],
},
},
});

View File

@@ -0,0 +1,9 @@
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
export default buildModule("CounterModule", (m) => {
const counter = m.contract("Counter");
m.call(counter, "incBy", [5n]);
return { counter };
});

View File

@@ -0,0 +1,34 @@
{
"name": "template-mocha-ethers",
"private": true,
"version": "0.0.1",
"description": "A TypeScript Hardhat project using Mocha and Ethers.js",
"type": "module",
"devDependencies": {
"hardhat": "workspace:^3.1.10",
"@nomicfoundation/hardhat-toolbox-mocha-ethers": "workspace:^3.0.3",
"@nomicfoundation/hardhat-ethers": "workspace:^4.0.5",
"@nomicfoundation/hardhat-ignition": "workspace:^3.0.8",
"@types/chai": "^5.2.3",
"@types/chai-as-promised": "^8.0.1",
"@types/mocha": ">=10.0.10",
"@types/node": "^22.8.5",
"chai": "^6.2.2",
"ethers": "^6.14.0",
"forge-std": "foundry-rs/forge-std#v1.9.4",
"mocha": "^11.0.0",
"typescript": "~5.8.0"
},
"peerDependencies": {
"@nomicfoundation/hardhat-ethers": "workspace:^4.0.5",
"@nomicfoundation/hardhat-ethers-chai-matchers": "workspace:^3.0.3",
"@nomicfoundation/hardhat-ignition": "workspace:^3.0.8",
"@nomicfoundation/hardhat-ignition-ethers": "workspace:^3.0.8",
"@nomicfoundation/hardhat-keystore": "workspace:^3.0.5",
"@nomicfoundation/hardhat-mocha": "workspace:^3.0.11",
"@nomicfoundation/hardhat-network-helpers": "workspace:^3.0.4",
"@nomicfoundation/hardhat-typechain": "workspace:^3.0.3",
"@nomicfoundation/hardhat-verify": "workspace:^3.0.11",
"@nomicfoundation/ignition-core": "workspace:^3.0.8"
}
}

View File

@@ -0,0 +1,22 @@
import { network } from "hardhat";
const { ethers } = await network.connect({
network: "hardhatOp",
chainType: "op",
});
console.log("Sending transaction using the OP chain type");
const [sender] = await ethers.getSigners();
console.log("Sending 1 wei from", sender.address, "to itself");
console.log("Sending L2 transaction");
const tx = await sender.sendTransaction({
to: sender.address,
value: 1n,
});
await tx.wait();
console.log("Transaction sent successfully");

View File

@@ -0,0 +1,36 @@
import { expect } from "chai";
import { network } from "hardhat";
const { ethers } = await network.connect();
describe("Counter", function () {
it("Should emit the Increment event when calling the inc() function", async function () {
const counter = await ethers.deployContract("Counter");
await expect(counter.inc()).to.emit(counter, "Increment").withArgs(1n);
});
it("The sum of the Increment events should match the current value", async function () {
const counter = await ethers.deployContract("Counter");
const deploymentBlockNumber = await ethers.provider.getBlockNumber();
// run a series of increments
for (let i = 1; i <= 10; i++) {
await counter.incBy(i);
}
const events = await counter.queryFilter(
counter.filters.Increment(),
deploymentBlockNumber,
"latest",
);
// check that the aggregated events match the current value
let total = 0n;
for (const event of events) {
total += event.args.by;
}
expect(await counter.x()).to.equal(total);
});
});

View File

@@ -0,0 +1,13 @@
/* Based on https://github.com/tsconfig/bases/blob/501da2bcd640cf95c95805783e1012b992338f28/bases/node22.json */
{
"compilerOptions": {
"lib": ["es2023"],
"module": "node16",
"target": "es2022",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"moduleResolution": "node16",
"outDir": "dist"
}
}

View File

@@ -0,0 +1,7 @@
# Sample Hardhat 3 Beta Project (minimal)
This project has a minimal setup of Hardhat 3 Beta, without any plugins.
## What's included?
The project includes native support for TypeScript, Hardhat scripts, tasks, and support for Solidity compilation and tests.

View File

@@ -0,0 +1,20 @@
# Node modules
/node_modules
# Compilation output
/dist
# pnpm deploy output
/bundle
# Hardhat Build Artifacts
/artifacts
# Hardhat compilation (v2) support directory
/cache
# Typechain output
/types
# Hardhat coverage reports
/coverage

View File

@@ -0,0 +1,7 @@
import { defineConfig } from "hardhat/config";
export default defineConfig({
solidity: {
version: "0.8.28",
},
});

View File

@@ -0,0 +1,12 @@
{
"name": "template-minimal",
"private": true,
"version": "0.0.1",
"description": "A minimal Hardhat project",
"type": "module",
"devDependencies": {
"hardhat": "workspace:^3.1.10",
"@types/node": "^22.8.5",
"typescript": "~5.8.0"
}
}

View File

@@ -0,0 +1,13 @@
/* Based on https://github.com/tsconfig/bases/blob/501da2bcd640cf95c95805783e1012b992338f28/bases/node22.json */
{
"compilerOptions": {
"lib": ["es2023"],
"module": "node16",
"target": "es2022",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"moduleResolution": "node16",
"outDir": "dist"
}
}