Skip to content

Commit b3b59db

Browse files
committed
feat: add subgraph service hardhat project bolierplate
Signed-off-by: Tomás Migone <[email protected]>
1 parent f85b674 commit b3b59db

File tree

10 files changed

+1116
-11
lines changed

10 files changed

+1116
-11
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ cached/
2121
# Build artifacts
2222
dist/
2323
build/
24+
typechain/
25+
typechain-types/
2426

2527
# Ignore solc bin output
2628
bin/

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"packageManager": "[email protected]",
99
"workspaces": [
1010
"packages/contracts",
11+
"packages/subgraph-service",
1112
"packages/sdk"
1213
],
1314
"scripts": {

packages/subgraph-service/README.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Sample Hardhat Project
2+
3+
This project demonstrates a basic Hardhat use case. It comes with a sample contract, a test for that contract, and a script that deploys that contract.
4+
5+
Try running some of the following tasks:
6+
7+
```shell
8+
npx hardhat help
9+
npx hardhat test
10+
REPORT_GAS=true npx hardhat test
11+
npx hardhat node
12+
npx hardhat run scripts/deploy.ts
13+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.24;
3+
4+
// Uncomment this line to use console.log
5+
// import "hardhat/console.sol";
6+
7+
contract Lock {
8+
uint public unlockTime;
9+
address payable public owner;
10+
11+
event Withdrawal(uint amount, uint when);
12+
13+
constructor(uint _unlockTime) payable {
14+
require(
15+
block.timestamp < _unlockTime,
16+
"Unlock time should be in the future"
17+
);
18+
19+
unlockTime = _unlockTime;
20+
owner = payable(msg.sender);
21+
}
22+
23+
function withdraw() public {
24+
// Uncomment this line, and the import of "hardhat/console.sol", to print a log in your terminal
25+
// console.log("Unlock time is %o and block timestamp is %o", unlockTime, block.timestamp);
26+
27+
require(block.timestamp >= unlockTime, "You can't withdraw yet");
28+
require(msg.sender == owner, "You aren't the owner");
29+
30+
emit Withdrawal(address(this).balance, block.timestamp);
31+
32+
owner.transfer(address(this).balance);
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { HardhatUserConfig } from "hardhat/config";
2+
import "@nomicfoundation/hardhat-toolbox";
3+
4+
const config: HardhatUserConfig = {
5+
solidity: "0.8.24",
6+
};
7+
8+
export default config;
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "subgraph-service",
3+
"version": "0.0.1",
4+
"description": "",
5+
"repository": {
6+
"type": "git",
7+
"url": "git+https://github.com/graphprotocol/contracts.git"
8+
},
9+
"author": "The Graph Team",
10+
"license": "GPL-2.0-or-later",
11+
"bugs": {
12+
"url": "https://github.com/graphprotocol/contracts/issues"
13+
},
14+
"homepage": "https://github.com/graphprotocol/contracts#readme",
15+
"devDependencies": {
16+
"@nomicfoundation/hardhat-chai-matchers": "^2.0.0",
17+
"@nomicfoundation/hardhat-ethers": "^3.0.0",
18+
"@nomicfoundation/hardhat-network-helpers": "^1.0.0",
19+
"@nomicfoundation/hardhat-toolbox": "^4.0.0",
20+
"@nomicfoundation/hardhat-verify": "^2.0.0",
21+
"@typechain/ethers-v6": "^0.5.0",
22+
"@typechain/hardhat": "^9.0.0",
23+
"@types/chai": "^4.2.0",
24+
"@types/mocha": ">=9.1.0",
25+
"@types/node": ">=16.0.0",
26+
"chai": "^4.2.0",
27+
"ethers": "^6.4.0",
28+
"hardhat": "^2.20.1",
29+
"hardhat-gas-reporter": "^1.0.8",
30+
"solidity-coverage": "^0.8.0",
31+
"ts-node": ">=8.0.0",
32+
"typechain": "^8.3.0",
33+
"typescript": ">=4.5.0"
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { ethers } from "hardhat";
2+
3+
async function main() {
4+
const currentTimestampInSeconds = Math.round(Date.now() / 1000);
5+
const unlockTime = currentTimestampInSeconds + 60;
6+
7+
const lockedAmount = ethers.parseEther("0.001");
8+
9+
const lock = await ethers.deployContract("Lock", [unlockTime], {
10+
value: lockedAmount,
11+
});
12+
13+
await lock.waitForDeployment();
14+
15+
console.log(
16+
`Lock with ${ethers.formatEther(
17+
lockedAmount
18+
)}ETH and unlock timestamp ${unlockTime} deployed to ${lock.target}`
19+
);
20+
}
21+
22+
// We recommend this pattern to be able to use async/await everywhere
23+
// and properly handle errors.
24+
main().catch((error) => {
25+
console.error(error);
26+
process.exitCode = 1;
27+
});
+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import {
2+
time,
3+
loadFixture,
4+
} from "@nomicfoundation/hardhat-toolbox/network-helpers";
5+
import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs";
6+
import { expect } from "chai";
7+
import { ethers } from "hardhat";
8+
9+
describe("Lock", function () {
10+
// We define a fixture to reuse the same setup in every test.
11+
// We use loadFixture to run this setup once, snapshot that state,
12+
// and reset Hardhat Network to that snapshot in every test.
13+
async function deployOneYearLockFixture() {
14+
const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60;
15+
const ONE_GWEI = 1_000_000_000;
16+
17+
const lockedAmount = ONE_GWEI;
18+
const unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS;
19+
20+
// Contracts are deployed using the first signer/account by default
21+
const [owner, otherAccount] = await ethers.getSigners();
22+
23+
const Lock = await ethers.getContractFactory("Lock");
24+
const lock = await Lock.deploy(unlockTime, { value: lockedAmount });
25+
26+
return { lock, unlockTime, lockedAmount, owner, otherAccount };
27+
}
28+
29+
describe("Deployment", function () {
30+
it("Should set the right unlockTime", async function () {
31+
const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture);
32+
33+
expect(await lock.unlockTime()).to.equal(unlockTime);
34+
});
35+
36+
it("Should set the right owner", async function () {
37+
const { lock, owner } = await loadFixture(deployOneYearLockFixture);
38+
39+
expect(await lock.owner()).to.equal(owner.address);
40+
});
41+
42+
it("Should receive and store the funds to lock", async function () {
43+
const { lock, lockedAmount } = await loadFixture(
44+
deployOneYearLockFixture
45+
);
46+
47+
expect(await ethers.provider.getBalance(lock.target)).to.equal(
48+
lockedAmount
49+
);
50+
});
51+
52+
it("Should fail if the unlockTime is not in the future", async function () {
53+
// We don't use the fixture here because we want a different deployment
54+
const latestTime = await time.latest();
55+
const Lock = await ethers.getContractFactory("Lock");
56+
await expect(Lock.deploy(latestTime, { value: 1 })).to.be.revertedWith(
57+
"Unlock time should be in the future"
58+
);
59+
});
60+
});
61+
62+
describe("Withdrawals", function () {
63+
describe("Validations", function () {
64+
it("Should revert with the right error if called too soon", async function () {
65+
const { lock } = await loadFixture(deployOneYearLockFixture);
66+
67+
await expect(lock.withdraw()).to.be.revertedWith(
68+
"You can't withdraw yet"
69+
);
70+
});
71+
72+
it("Should revert with the right error if called from another account", async function () {
73+
const { lock, unlockTime, otherAccount } = await loadFixture(
74+
deployOneYearLockFixture
75+
);
76+
77+
// We can increase the time in Hardhat Network
78+
await time.increaseTo(unlockTime);
79+
80+
// We use lock.connect() to send a transaction from another account
81+
await expect(lock.connect(otherAccount).withdraw()).to.be.revertedWith(
82+
"You aren't the owner"
83+
);
84+
});
85+
86+
it("Shouldn't fail if the unlockTime has arrived and the owner calls it", async function () {
87+
const { lock, unlockTime } = await loadFixture(
88+
deployOneYearLockFixture
89+
);
90+
91+
// Transactions are sent using the first signer by default
92+
await time.increaseTo(unlockTime);
93+
94+
await expect(lock.withdraw()).not.to.be.reverted;
95+
});
96+
});
97+
98+
describe("Events", function () {
99+
it("Should emit an event on withdrawals", async function () {
100+
const { lock, unlockTime, lockedAmount } = await loadFixture(
101+
deployOneYearLockFixture
102+
);
103+
104+
await time.increaseTo(unlockTime);
105+
106+
await expect(lock.withdraw())
107+
.to.emit(lock, "Withdrawal")
108+
.withArgs(lockedAmount, anyValue); // We accept any value as `when` arg
109+
});
110+
});
111+
112+
describe("Transfers", function () {
113+
it("Should transfer the funds to the owner", async function () {
114+
const { lock, unlockTime, lockedAmount, owner } = await loadFixture(
115+
deployOneYearLockFixture
116+
);
117+
118+
await time.increaseTo(unlockTime);
119+
120+
await expect(lock.withdraw()).to.changeEtherBalances(
121+
[owner, lock],
122+
[lockedAmount, -lockedAmount]
123+
);
124+
});
125+
});
126+
});
127+
});
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es2020",
4+
"module": "commonjs",
5+
"esModuleInterop": true,
6+
"forceConsistentCasingInFileNames": true,
7+
"strict": true,
8+
"skipLibCheck": true,
9+
"resolveJsonModule": true
10+
}
11+
}

0 commit comments

Comments
 (0)