Commit 50f6d41d authored by vicotor's avatar vicotor

add code

parents
Pipeline #852 failed with stages
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
{
"manifestVersion": "3.2",
"proxies": [
{
"address": "0xE20fDE775f25fDfc52FeD1765829b716E3aCBf47",
"txHash": "0x2cada1289b75f89126543dc833a09b7089b75bab5464fb635fbc1b35d88c7ff8",
"kind": "transparent"
},
{
"address": "0x863dCa3ec27b12D2005f3cD857eD56153852B224",
"txHash": "0x248609b9f94e1a1e7cedab2f22b7c1b5eff3e202530d2507f57361b20d84f600",
"kind": "transparent"
}
],
"impls": {
"4b7e08503c9ec48bcfcc54f48502ffb579226e20180c7584f272d61b05f0397a": {
"address": "0xBfcD7C4766322bDBd070931Ef5E196A66dA27037",
"txHash": "0x1b72de96901a001f2506f7dacb4677d6477eb8c0853ab591c5d9a3d29c04d78e",
"layout": {
"solcVersion": "0.8.4",
"storage": [
{
"label": "value",
"offset": 0,
"slot": "0",
"type": "t_uint256",
"contract": "Box",
"src": "contracts/Box.sol:6"
}
],
"types": {
"t_uint256": {
"label": "uint256",
"numberOfBytes": "32"
}
},
"namespaces": {}
}
},
"8bc61db7133901ce077df64acaaf71ab7c28a004a019edf704e6045c4102ef5e": {
"address": "0xB06f396135CDb050E47D4982FcbfEcB394c24F23",
"txHash": "0xa15d27672a038020baca1cd2d1991be0372ef5244400ab771cff5c215c2726f0",
"layout": {
"solcVersion": "0.8.4",
"storage": [
{
"label": "value",
"offset": 0,
"slot": "0",
"type": "t_uint256",
"contract": "BoxV2",
"src": "contracts/BoxV2.sol:6"
}
],
"types": {
"t_uint256": {
"label": "uint256",
"numberOfBytes": "32"
}
},
"namespaces": {}
}
}
}
}
# 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
```
// contracts/Box.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract Box {
uint256 private value;
// Emitted when the stored value changes
event ValueChanged(uint256 newValue);
// Stores a new value in the contract
function store(uint256 newValue) public {
value = newValue;
emit ValueChanged(newValue);
}
// Reads the last stored value
function retrieve() public view returns (uint256) {
return value;
}
}
// contracts/Box.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract BoxV2 {
uint256 private value;
// Emitted when the stored value changes
event ValueChanged(uint256 newValue);
// Stores a new value in the contract
function store(uint256 newValue) public {
value = newValue;
emit ValueChanged(newValue);
}
// Reads the last stored value
function retrieve() public view returns (uint256) {
return value;
}
function increment() public {
value = value + 1;
emit ValueChanged(value);
}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;
// 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);
}
}
require("@nomicfoundation/hardhat-toolbox");
require('@openzeppelin/hardhat-upgrades');
require("@nomicfoundation/hardhat-ethers");
require("dotenv").config()
// This is a sample Hardhat task. To learn how to create your own go to
// https://hardhat.org/guides/create-task.html
task("accounts", "Prints the list of accounts", async (taskArgs, hre) => {
const accounts = await hre.ethers.getSigners()
for (const account of accounts) {
console.log(account.address)
}
})
// Define mnemonic for accounts.
let mnemonic = process.env.MNEMONIC
if (!mnemonic) {
// NOTE: this fallback is for development only!
// When using other networks, set the secret in .env.
// DO NOT commit or share your mnemonic with others!
mnemonic = "test test test test test test test test test test test test"
}
// contract owner: 0x9f8fb0488dE145E7467FDeD872098e1115d6ea4C
// contract admin: 0x9f8fb0488dE145E7467FDeD872098e1115d6ea4C
// const fs = require('fs');
// const mnemonic = fs.readFileSync(".secret").toString().trim();
const privateKey = process.env.DEPLOY_PRIVATE_KEY
const accounts = { mnemonic }
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: {
compilers: [
{
version: "0.8.4",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},
],
},
networks: {
hardhat: {
accounts,
gas: 10000000,
gasPrice: 10000000000,
},
cmp_test: {
accounts: [privateKey],
url: "https://rpc.block.caduceus.global",
},
mantle: {
accounts: [privateKey],
url: "https://rpc.sepolia.mantle.xyz",
},
echain: {
url: "https://rpc.echain.bitheart.org",
accounts: [privateKey],
},
polygon: {
network_id: "137", // Matic Mainnet
url: "https://polygon-rpc.com",
accounts: [privateKey],
gas: 10000000,
gasLimit: 1000000,
gasPrice: 50 * 10 ** 9,
},
local: {
url: "http://127.0.0.1:8545",
accounts: [privateKey],
gasLimit: 100000000,
gasPrice: 5000000000,
},
},
};
// 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 };
});
This diff is collapsed.
// scripts/deploy.js
async function main() {
const Box = await ethers.getContractFactory("Box");
console.log("Deploying Box...");
const box = await upgrades.deployProxy(Box, [42], { initializer: 'store' });
await box.waitForDeployment();
const boxAddress = await box.getAddress();
console.log("Box deployed to:", boxAddress);
}
main()
.then(() => process.exit(0))
.catch(error => {
console.error(error);
process.exit(1);
});
// scripts/prepare_upgrade.js
async function main() {
const proxyAddress = '0x863dCa3ec27b12D2005f3cD857eD56153852B224';
const BoxV2 = await ethers.getContractFactory("BoxV2");
console.log("upgrade...");
const boxv2 = await upgrades.upgradeProxy(proxyAddress, BoxV2);
await boxv2.waitForDeployment();
const boxv2Address = await boxv2.getAddress();
console.log("BoxV2 at:", boxv2Address);
}
main()
.then(() => process.exit(0))
.catch(error => {
console.error(error);
process.exit(1);
});
// test/Box.js
// Load dependencies
const { expect } = require('chai');
let Box;
let box;
// Start test block
describe('Box', function () {
beforeEach(async function () {
Box = await ethers.getContractFactory("Box");
box = await Box.deploy();
});
// Test case
it('retrieve returns a value previously stored', async function () {
// Store a value
await box.store(42);
// Test if the returned value is the same one
// Note that we need to use strings to compare the 256 bit integers
expect((await box.retrieve()).toString()).to.equal('42');
});
});
// test/Box.proxy.js
// Load dependencies
const { expect } = require('chai');
let Box;
let box;
// Start test block
describe('Box (proxy)', function () {
beforeEach(async function () {
Box = await ethers.getContractFactory("Box");
box = await upgrades.deployProxy(Box, [42], {initializer: 'store'});
});
// Test case
it('retrieve returns a value previously initialized', async function () {
// Test if the returned value is the same one
// Note that we need to use strings to compare the 256 bit integers
expect((await box.retrieve()).toString()).to.equal('42');
});
});
// test/BoxV2.js
// Load dependencies
const { expect } = require('chai');
let BoxV2;
let boxV2;
// Start test block
describe('BoxV2', function () {
beforeEach(async function () {
BoxV2 = await ethers.getContractFactory("BoxV2");
boxV2 = await BoxV2.deploy();
});
// Test case
it('retrieve returns a value previously stored', async function () {
// Store a value
await boxV2.store(42);
// Test if the returned value is the same one
// Note that we need to use strings to compare the 256 bit integers
expect((await boxV2.retrieve()).toString()).to.equal('42');
});
// Test case
it('retrieve returns a value previously incremented', async function () {
// Increment
await boxV2.increment();
// Test if the returned value is the same one
// Note that we need to use strings to compare the 256 bit integers
expect((await boxV2.retrieve()).toString()).to.equal('1');
});
});
// test/BoxV2.proxy.js
// Load dependencies
const { expect } = require('chai');
let Box;
let BoxV2;
let box;
let boxV2;
// Start test block
describe('BoxV2 (proxy)', function () {
beforeEach(async function () {
Box = await ethers.getContractFactory("Box");
BoxV2 = await ethers.getContractFactory("BoxV2");
box = await upgrades.deployProxy(Box, [42], {initializer: 'store'});
await box.waitForDeployment();
const nBoxAddr = await box.getAddress();
boxV2 = await upgrades.upgradeProxy(nBoxAddr, BoxV2);
});
// Test case
it('retrieve returns a value previously incremented', async function () {
// Increment
await boxV2.increment();
// Test if the returned value is the same one
// Note that we need to use strings to compare the 256 bit integers
expect((await boxV2.retrieve()).toString()).to.equal('43');
});
});
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]
);
});
});
});
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment