Project Ready
This commit is contained in:
parent
a76b612818
commit
d1b444988e
65
README.md
65
README.md
@ -5,9 +5,13 @@ A fully functional Smart Contract wrriten with ```solidity```, ```node.js``` and
|
||||
* solidity prettier code beautifier setup
|
||||
* standard of developing Smart Contract with ```solidity```
|
||||
* standard of developing ```node.js``` script to use ```hardhat``` library efficiently
|
||||
* auto verify contract in Etherscan.io
|
||||
* creating automate test cases
|
||||
* check gas fee & gas price in real-time, with usage of ```coverage```
|
||||
* auto verify contract on Etherscan.io
|
||||
* creating automate test cases - unit test & staging test
|
||||
* creating tasks etc.
|
||||
* refactor codes to reduce gas fee
|
||||
* write code in best practice, with usage of ```solhint```
|
||||
* prettier ```solidity``` & ```node.js``` code
|
||||
* gitea version control
|
||||
|
||||
This project mainly to keep as a reference for future Web 3.0 Developments.
|
||||
@ -46,13 +50,23 @@ Standard Update:
|
||||
git add .
|
||||
git commit -m "Describe what changes"
|
||||
git push -u origin main
|
||||
// After set this, later easier usage via below line
|
||||
git push
|
||||
git pull
|
||||
```
|
||||
|
||||
Development need exlude file can create root file with name .gitignore
|
||||
```
|
||||
.env
|
||||
node_modules
|
||||
.encryptedkey.json
|
||||
package.json
|
||||
img
|
||||
artifacts
|
||||
cache
|
||||
coverage
|
||||
.env
|
||||
.*
|
||||
README.md
|
||||
coverage.json
|
||||
```
|
||||
|
||||
## 2. Setup Visual Studio Code Development Environment
|
||||
@ -100,8 +114,14 @@ yarn hardhat
|
||||
yarn add --dev prettier prettier-plugin-solidity
|
||||
yarn add --dev dotenv
|
||||
yarn add --dev @nomiclabs/hardhat-etherscan // Auto verify Etherscan Samrt Contract
|
||||
yarn add --dev @nomiclabs/hardhat-waffle
|
||||
yarn add --dev solhint
|
||||
yarn add --dev @nomiclabs/hardhat-ethers@npm:hardhat-deploy-ethers ethers
|
||||
yarn add --dev hardhat-gas-reporter
|
||||
yarn add --dev solidity-coverage
|
||||
yarn add --dev solhint
|
||||
```
|
||||
Other Terminal Useful Command
|
||||
Other Terminal Useful Command 1:
|
||||
```
|
||||
// For Debuging Hardhat
|
||||
npx hardhat --versose
|
||||
@ -120,20 +140,45 @@ yarn hardhat custom-task-name
|
||||
// Need create file in /tasks/custom-task-name.js
|
||||
// Add import in hardhat.config.js -> requir("/tasks/custom-task-name");
|
||||
yarn hardhat test
|
||||
yarn hardhat test --grep customKeyword
|
||||
// Only will run the test with describe test that contain "customKeyword"
|
||||
yarn hardhat test --grep customSearchKeyword
|
||||
// Only will run the test with describe test that contain "customSearchKeyword"
|
||||
```
|
||||
Other Terminal Useful Command 2:
|
||||
```
|
||||
// For Getting Gas Used & Gas Price
|
||||
yarn hardhat test
|
||||
// Will create a file in ./gas-report.txt
|
||||
// With .env of etherscan API key
|
||||
// For Getting Coverage
|
||||
yarn hardhat coverage
|
||||
// Checking code usage & tested percentage
|
||||
// For Checking Code Best Practice
|
||||
yarn solhint contracts/*.sol
|
||||
// For Get Fake Price Feed On Localhost & Ganache
|
||||
yarn hardhat deploy --tags mocks --network localhost
|
||||
```
|
||||
Debug ```Node.js``` need to open **Javascript Debug Terminal** first, via ```ctrl + shift + p```
|
||||
|
||||
#### Reduce Gas Used:
|
||||
* Prioritize use ```private``` instead of ```public```
|
||||
* Use ```constant``` which declare once in constructor
|
||||
* Use ```immutable ``` which declare once only
|
||||
|
||||
This is because blockchain will have higher ```read``` and ```store``` gas fee on storage block, lesser in bytes code block.
|
||||
|
||||
|
||||
## 3. Known Issue
|
||||
* Cannot use ```expect``` in test, most probably due to the dependencies mismatched. Future will upgrade and test newer version dependencies.
|
||||
* Dependencies combination is old, need update...
|
||||
* ...
|
||||
|
||||
### Find a bug?
|
||||
If you found an issue or would like to submit an improvement to this demo project, please submit an issue using the issues tab above.
|
||||
|
||||
## 4. Looking Web 3.0 Developer For Your Project?
|
||||
Mr Hoelee is Welcome Web 3.0 Remote Job, Contact Me Immediately Via WhatsApp <a href="https://wa.me/60175885290">+60175885290</a>
|
||||
. Or You can email <a href="mailto:me@hoelee.com">me@hoelee.com</a> now. Thanks.
|
||||
**Mr Hoelee** is Welcome Web 3.0 Remote Job, Contact Me Immediately Via WhatsApp <a href="https://wa.me/60175885290">+60175885290</a>
|
||||
.
|
||||
|
||||
Or You can email <a href="mailto:me@hoelee.com">me@hoelee.com</a> now. Thanks.
|
||||
|
||||
## 5. Like this project?
|
||||
If you are feeling generous, buy me a coffee! - <a href="https://buymeacoffee.com/hoelee">buymeacoffee.com/hoelee</a>
|
||||
|
@ -24,9 +24,11 @@ contract FunWithStorage {
|
||||
i_not_in_storage = 123;
|
||||
}
|
||||
|
||||
/*
|
||||
function doStuff() public {
|
||||
uint256 newVar = favoriteNumber + 1; // SLOAD
|
||||
bool otherVar = someBool; // SLOAD
|
||||
// ^^ memory variables
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
10
package.json
10
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hardhat-simple-storage",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Hoelee Practical Using Hardhat To Create Smart Contract",
|
||||
"repository": "https://git.hoelee.com/hoelee/hardhat-simple-storage.git",
|
||||
"author": "hoelee <me@hoelee.com>",
|
||||
@ -34,5 +34,13 @@
|
||||
"solhint": "^5.0.2",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-solidity": "^1.3.1"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "yarn hardhat test",
|
||||
"test:staging": "hardhat test --network sepolia",
|
||||
"lint": "solhint 'contracts/**/*.sol'",
|
||||
"lint:fix": "solhint 'contracts/**/*.sol' --fix",
|
||||
"format": "prettier --write .",
|
||||
"coverage": "hardhat coverage"
|
||||
}
|
||||
}
|
||||
|
19
scripts/fund.js
Normal file
19
scripts/fund.js
Normal file
@ -0,0 +1,19 @@
|
||||
const { ethers, getNamedAccounts } = require("hardhat");
|
||||
|
||||
async function main() {
|
||||
const { deployer } = await getNamedAccounts();
|
||||
const fundMe = await ethers.getContract("FundMe", deployer);
|
||||
console.log("Funding Contract...");
|
||||
const transactionResponse = await fundMe.fund({
|
||||
value: ethers.utils.parseEther("0.1"),
|
||||
});
|
||||
await transactionResponse.wait(1);
|
||||
console.log("Funded!");
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
18
scripts/withdraw.js
Normal file
18
scripts/withdraw.js
Normal file
@ -0,0 +1,18 @@
|
||||
const { ethers, getNamedAccounts } = require("hardhat");
|
||||
|
||||
async function main() {
|
||||
const { deployer } = await getNamedAccounts();
|
||||
const fundMe = await ethers.getContract("FundMe", deployer);
|
||||
console.log(`Got contract FundMe at ${fundMe.address}`);
|
||||
console.log("Withdrawing from contract...");
|
||||
const transactionResponse = await fundMe.withdraw();
|
||||
await transactionResponse.wait();
|
||||
console.log("Got it back!");
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
36
test/staging/FundMe.staging.test.js
Normal file
36
test/staging/FundMe.staging.test.js
Normal file
@ -0,0 +1,36 @@
|
||||
//Last Step Before Going to Mainnet
|
||||
|
||||
const { ethers, deployments, getNamedAccounts } = require("hardhat");
|
||||
const { expect, assert } = require("chai");
|
||||
const { developmentChains } = require("../../helper-hardhat-config");
|
||||
|
||||
// Run on testnet
|
||||
developmentChains.includes(network.name)
|
||||
? describe.skip
|
||||
: describe("FundMe", async function () {
|
||||
let fundMe;
|
||||
let deployer;
|
||||
const sendValue = ethers.utils.parseEther("1");
|
||||
// Assume already deployed
|
||||
// Assume on testnet, no need mock
|
||||
beforeEach(async function () {
|
||||
deployer = (await getNamedAccounts()).deployer;
|
||||
fundMe = await ethers.getContract("FundMe", deployer);
|
||||
});
|
||||
|
||||
it("allows people to fund and withdraw", async function () {
|
||||
const fundTxResponse = await fundMe.fund({ value: sendValue });
|
||||
await fundTxResponse.wait(1);
|
||||
const withdrawTxResponse = await fundMe.withdraw();
|
||||
await withdrawTxResponse.wait(1);
|
||||
|
||||
const endingFundMeBalance = await fundMe.provider.getBalance(
|
||||
fundMe.address,
|
||||
);
|
||||
console.log(
|
||||
endingFundMeBalance.toString() +
|
||||
" should equal 0, running assert equal...",
|
||||
);
|
||||
assert.equal(endingFundMeBalance.toString(), "0");
|
||||
});
|
||||
});
|
@ -1,310 +1,322 @@
|
||||
const { ethers, deployments, getNamedAccounts } = require("hardhat");
|
||||
const { expect, assert } = require("chai");
|
||||
const { developmentChains } = require("../../helper-hardhat-config");
|
||||
|
||||
describe("FundMe", function () {
|
||||
//// Test For The Constructor
|
||||
let fundMe;
|
||||
let deployer;
|
||||
let mockV3Aggregator;
|
||||
beforeEach(async () => {
|
||||
deployer = (await getNamedAccounts()).deployer;
|
||||
/* // Alternative To Above, Localhost will get 10 fake accounts
|
||||
// Run on development chain
|
||||
!developmentChains.includes(network.name)
|
||||
? describe.skip
|
||||
: describe("FundMe", function () {
|
||||
//// Test For The Constructor
|
||||
let fundMe;
|
||||
let deployer;
|
||||
let mockV3Aggregator;
|
||||
beforeEach(async () => {
|
||||
deployer = (await getNamedAccounts()).deployer;
|
||||
/* // Alternative To Above, Localhost will get 10 fake accounts
|
||||
const accounts = await ethers.getSigners();
|
||||
const account1 = accounts[0];
|
||||
const account2 = accounts[1];
|
||||
*/
|
||||
await deployments.fixture(["all"]);
|
||||
fundMe = await ethers.getContract("FundMe", deployer);
|
||||
mockV3Aggregator = await ethers.getContract(
|
||||
"MockV3Aggregator",
|
||||
deployer,
|
||||
);
|
||||
});
|
||||
await deployments.fixture(["all"]);
|
||||
fundMe = await ethers.getContract("FundMe", deployer);
|
||||
mockV3Aggregator = await ethers.getContract(
|
||||
"MockV3Aggregator",
|
||||
deployer,
|
||||
);
|
||||
});
|
||||
|
||||
let eth1 = "1000000000000000000"; // 1 ETH
|
||||
eth1 = ethers.utils.parseEther("1"); // Same 1 ETH
|
||||
describe("constructor", async function () {
|
||||
it("Set the aggregator priceFeedAddress correctly", async function () {
|
||||
const response = await fundMe.getPriceFeed(); // AggregatorV3Interface
|
||||
//console.log("AggregatorV3Interface" + response);
|
||||
assert.equal(response, mockV3Aggregator.address);
|
||||
});
|
||||
it("Updated the amount funded data structure", async function () {
|
||||
await fundMe.fund({ value: eth1 });
|
||||
const response = await fundMe.getAddressToAmountFunded(deployer);
|
||||
assert.equal(response.toString(), eth1.toString()); // Send 1 ETH
|
||||
});
|
||||
it("Adds funder to array of funders", async function () {
|
||||
await fundMe.fund({ value: eth1 });
|
||||
const funder = await fundMe.getFunders(0);
|
||||
assert.equal(funder, deployer);
|
||||
});
|
||||
});
|
||||
let eth1 = "1000000000000000000"; // 1 ETH
|
||||
eth1 = ethers.utils.parseEther("1"); // Same 1 ETH
|
||||
describe("constructor", async function () {
|
||||
it("Set the aggregator priceFeedAddress correctly", async function () {
|
||||
const response = await fundMe.getPriceFeed(); // AggregatorV3Interface
|
||||
//console.log("AggregatorV3Interface" + response);
|
||||
assert.equal(response, mockV3Aggregator.address);
|
||||
});
|
||||
it("Updated the amount funded data structure", async function () {
|
||||
await fundMe.fund({ value: eth1 });
|
||||
const response =
|
||||
await fundMe.getAddressToAmountFunded(deployer);
|
||||
assert.equal(response.toString(), eth1.toString()); // Send 1 ETH
|
||||
});
|
||||
it("Adds funder to array of funders", async function () {
|
||||
await fundMe.fund({ value: eth1 });
|
||||
const funder = await fundMe.getFunders(0);
|
||||
assert.equal(funder, deployer);
|
||||
});
|
||||
});
|
||||
|
||||
// Test for the fund() function
|
||||
describe("fund function", async function () {
|
||||
it("Fail if you don't send enough ETH", async function () {
|
||||
await expect(fundMe.fund()).to.be.revertedWith(
|
||||
"Didn't send enough",
|
||||
);
|
||||
});
|
||||
});
|
||||
// Test for the fund() function
|
||||
describe("fund function", async function () {
|
||||
it("Fail if you don't send enough ETH", async function () {
|
||||
await expect(fundMe.fund()).to.be.revertedWith(
|
||||
"Didn't send enough",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// Test For The receive() function
|
||||
let FundMe;
|
||||
let owner;
|
||||
let addr1;
|
||||
let addr2;
|
||||
let addrs;
|
||||
beforeEach(async function () {
|
||||
// Get the ContractFactory and Signers here.
|
||||
[owner, addr1, addr2, ...addrs] = await ethers.getSigners();
|
||||
// Test For The receive() function
|
||||
let FundMe;
|
||||
let owner;
|
||||
let addr1;
|
||||
let addr2;
|
||||
let addrs;
|
||||
beforeEach(async function () {
|
||||
// Get the ContractFactory and Signers here.
|
||||
[owner, addr1, addr2, ...addrs] = await ethers.getSigners();
|
||||
|
||||
// Deploy Mock Price Feed
|
||||
const MockV3Aggregator =
|
||||
await ethers.getContractFactory("MockV3Aggregator");
|
||||
mockV3Aggregator = await MockV3Aggregator.deploy(8, 2000 * 1e8);
|
||||
// Deploy Mock Price Feed
|
||||
const MockV3Aggregator =
|
||||
await ethers.getContractFactory("MockV3Aggregator");
|
||||
mockV3Aggregator = await MockV3Aggregator.deploy(8, 2000 * 1e8);
|
||||
|
||||
// Deploy FundMe contract
|
||||
FundMe = await ethers.getContractFactory("FundMe");
|
||||
fundMe = await FundMe.deploy(mockV3Aggregator.address);
|
||||
await fundMe.deployed();
|
||||
});
|
||||
// Deploy FundMe contract
|
||||
FundMe = await ethers.getContractFactory("FundMe");
|
||||
fundMe = await FundMe.deploy(mockV3Aggregator.address);
|
||||
await fundMe.deployed();
|
||||
});
|
||||
|
||||
describe("receive function", function () {
|
||||
it("should call the fund function when receiving Ether", async function () {
|
||||
// Send ETH to the contract
|
||||
await addr1.sendTransaction({
|
||||
to: fundMe.address,
|
||||
value: ethers.utils.parseEther("1.0"), // 1 ETH
|
||||
});
|
||||
describe("receive function", function () {
|
||||
it("should call the fund function when receiving Ether", async function () {
|
||||
// Send ETH to the contract
|
||||
await addr1.sendTransaction({
|
||||
to: fundMe.address,
|
||||
value: ethers.utils.parseEther("1.0"), // 1 ETH
|
||||
});
|
||||
|
||||
// Check if addr1 is added to funders
|
||||
expect(await fundMe.getFunders(0)).to.equal(addr1.address);
|
||||
// Check if the amount funded is recorded
|
||||
expect(
|
||||
await fundMe.getAddressToAmountFunded(addr1.address),
|
||||
).to.equal(ethers.utils.parseEther("1.0"));
|
||||
});
|
||||
// Check if addr1 is added to funders
|
||||
expect(await fundMe.getFunders(0)).to.equal(addr1.address);
|
||||
// Check if the amount funded is recorded
|
||||
expect(
|
||||
await fundMe.getAddressToAmountFunded(addr1.address),
|
||||
).to.equal(ethers.utils.parseEther("1.0"));
|
||||
});
|
||||
|
||||
it("should revert if the amount sent is below the minimum funding value", async function () {
|
||||
// 1 USD = 0.0005 ETH (Assuming 1 ETH = 2000 USD)
|
||||
const minFunding = ethers.utils.parseEther("0.0005"); // 0.5 USD
|
||||
it("should revert if the amount sent is below the minimum funding value", async function () {
|
||||
// 1 USD = 0.0005 ETH (Assuming 1 ETH = 2000 USD)
|
||||
const minFunding = ethers.utils.parseEther("0.0005"); // 0.5 USD
|
||||
|
||||
await expect(
|
||||
addr1.sendTransaction({
|
||||
to: fundMe.address,
|
||||
value: minFunding.sub(1), // Slightly less than the minimum
|
||||
}),
|
||||
).to.be.revertedWith("Didn't send enough");
|
||||
});
|
||||
await expect(
|
||||
addr1.sendTransaction({
|
||||
to: fundMe.address,
|
||||
value: minFunding.sub(1), // Slightly less than the minimum
|
||||
}),
|
||||
).to.be.revertedWith("Didn't send enough");
|
||||
});
|
||||
|
||||
it("should accept funds greater than or equal to the minimum funding value", async function () {
|
||||
// 50 USD = 0.025 ETH (Assuming 1 ETH = 2000 USD)
|
||||
const minFunding = ethers.utils.parseEther("0.025");
|
||||
it("should accept funds greater than or equal to the minimum funding value", async function () {
|
||||
// 50 USD = 0.025 ETH (Assuming 1 ETH = 2000 USD)
|
||||
const minFunding = ethers.utils.parseEther("0.025");
|
||||
|
||||
await expect(
|
||||
addr1.sendTransaction({
|
||||
to: fundMe.address,
|
||||
value: minFunding, // Exactly the minimum
|
||||
}),
|
||||
).not.to.be.reverted;
|
||||
await expect(
|
||||
addr1.sendTransaction({
|
||||
to: fundMe.address,
|
||||
value: minFunding, // Exactly the minimum
|
||||
}),
|
||||
).not.to.be.reverted;
|
||||
|
||||
expect(await fundMe.getFunders(0)).to.equal(addr1.address);
|
||||
expect(
|
||||
await fundMe.getAddressToAmountFunded(addr1.address),
|
||||
).to.equal(minFunding);
|
||||
});
|
||||
});
|
||||
expect(await fundMe.getFunders(0)).to.equal(addr1.address);
|
||||
expect(
|
||||
await fundMe.getAddressToAmountFunded(addr1.address),
|
||||
).to.equal(minFunding);
|
||||
});
|
||||
});
|
||||
|
||||
describe("withdraw", async function () {
|
||||
beforeEach(async function () {
|
||||
await fundMe.fund({ value: eth1 }); // Add 1 ETH first
|
||||
});
|
||||
it("Withdraw ETH from a single funder", async function () {
|
||||
/*
|
||||
* Deployer = funder
|
||||
* fundMe and replace with ethers, important to getBalance
|
||||
*/
|
||||
describe("withdraw", async function () {
|
||||
beforeEach(async function () {
|
||||
await fundMe.fund({ value: eth1 }); // Add 1 ETH first
|
||||
});
|
||||
it("Withdraw ETH from a single funder", async function () {
|
||||
/*
|
||||
* Deployer = funder
|
||||
* fundMe and replace with ethers, important to getBalance
|
||||
*/
|
||||
|
||||
// Arrange
|
||||
const startingFundMeBalance = await fundMe.provider.getBalance(
|
||||
fundMe.address,
|
||||
);
|
||||
const startingDeployerBalance =
|
||||
await fundMe.provider.getBalance(deployer);
|
||||
// Arrange
|
||||
const startingFundMeBalance =
|
||||
await fundMe.provider.getBalance(fundMe.address);
|
||||
const startingDeployerBalance =
|
||||
await fundMe.provider.getBalance(deployer);
|
||||
|
||||
// Act
|
||||
const transactionResponse = await fundMe.withdraw();
|
||||
const transactionReceipt = await transactionResponse.wait(1);
|
||||
// Act
|
||||
const transactionResponse = await fundMe.withdraw();
|
||||
const transactionReceipt = await transactionResponse.wait(1);
|
||||
|
||||
const endingFundMeBalance = await fundMe.provider.getBalance(
|
||||
fundMe.address,
|
||||
);
|
||||
const endingDeployerBalance =
|
||||
await fundMe.provider.getBalance(deployer);
|
||||
const endingFundMeBalance = await fundMe.provider.getBalance(
|
||||
fundMe.address,
|
||||
);
|
||||
const endingDeployerBalance =
|
||||
await fundMe.provider.getBalance(deployer);
|
||||
|
||||
const { gasUsed, effectiveGasPrice } = transactionReceipt; //gasUsed = "0x8b14"; effectiveGasPrice = "0x4e4814ec";
|
||||
const gasCost = gasUsed.mul(effectiveGasPrice);
|
||||
const { gasUsed, effectiveGasPrice } = transactionReceipt; //gasUsed = "0x8b14"; effectiveGasPrice = "0x4e4814ec";
|
||||
const gasCost = gasUsed.mul(effectiveGasPrice);
|
||||
|
||||
// Assert
|
||||
assert.equal(endingFundMeBalance, 0);
|
||||
assert.equal(
|
||||
startingFundMeBalance.add(startingDeployerBalance),
|
||||
endingDeployerBalance.add(gasCost).toString(),
|
||||
);
|
||||
});
|
||||
// Assert
|
||||
assert.equal(endingFundMeBalance, 0);
|
||||
assert.equal(
|
||||
startingFundMeBalance.add(startingDeployerBalance),
|
||||
endingDeployerBalance.add(gasCost).toString(),
|
||||
);
|
||||
});
|
||||
|
||||
it("Allow us to withdraw with multiple funders", async function () {
|
||||
const accounts = await ethers.getSigners();
|
||||
for (let a = 0; a < 6; a++) {
|
||||
const fundMeConnectedContract = await fundMe.connect(
|
||||
accounts[a],
|
||||
);
|
||||
await fundMeConnectedContract.fund({ value: eth1 });
|
||||
}
|
||||
it("Allow us to withdraw with multiple funders", async function () {
|
||||
const accounts = await ethers.getSigners();
|
||||
for (let a = 0; a < 6; a++) {
|
||||
const fundMeConnectedContract = await fundMe.connect(
|
||||
accounts[a],
|
||||
);
|
||||
await fundMeConnectedContract.fund({ value: eth1 });
|
||||
}
|
||||
|
||||
const startingFundMeBalance = await fundMe.provider.getBalance(
|
||||
fundMe.address,
|
||||
);
|
||||
const startingDeployerBalance =
|
||||
await fundMe.provider.getBalance(deployer);
|
||||
const startingFundMeBalance =
|
||||
await fundMe.provider.getBalance(fundMe.address);
|
||||
const startingDeployerBalance =
|
||||
await fundMe.provider.getBalance(deployer);
|
||||
|
||||
// Act
|
||||
const transactionResponse = await fundMe.withdraw();
|
||||
// Let's comapre gas costs :)
|
||||
// const transactionResponse = await fundMe.withdraw()
|
||||
const transactionReceipt = await transactionResponse.wait();
|
||||
const { gasUsed, effectiveGasPrice } = transactionReceipt;
|
||||
const withdrawGasCost = gasUsed.mul(effectiveGasPrice);
|
||||
console.log(`GasCost: ${withdrawGasCost}`);
|
||||
console.log(`GasUsed: ${gasUsed}`);
|
||||
console.log(`GasPrice: ${effectiveGasPrice}`);
|
||||
const endingFundMeBalance = await fundMe.provider.getBalance(
|
||||
fundMe.address,
|
||||
);
|
||||
const endingDeployerBalance =
|
||||
await fundMe.provider.getBalance(deployer);
|
||||
// Assert
|
||||
assert.equal(
|
||||
startingFundMeBalance.add(startingDeployerBalance).toString(),
|
||||
endingDeployerBalance.add(withdrawGasCost).toString(),
|
||||
);
|
||||
// Make a getter for storage variables
|
||||
await expect(fundMe.getFunders(0)).to.be.reverted;
|
||||
// Act
|
||||
const transactionResponse = await fundMe.withdraw();
|
||||
// Let's comapre gas costs :)
|
||||
// const transactionResponse = await fundMe.withdraw()
|
||||
const transactionReceipt = await transactionResponse.wait();
|
||||
const { gasUsed, effectiveGasPrice } = transactionReceipt;
|
||||
const withdrawGasCost = gasUsed.mul(effectiveGasPrice);
|
||||
console.log(`GasCost: ${withdrawGasCost}`);
|
||||
console.log(`GasUsed: ${gasUsed}`);
|
||||
console.log(`GasPrice: ${effectiveGasPrice}`);
|
||||
const endingFundMeBalance = await fundMe.provider.getBalance(
|
||||
fundMe.address,
|
||||
);
|
||||
const endingDeployerBalance =
|
||||
await fundMe.provider.getBalance(deployer);
|
||||
// Assert
|
||||
assert.equal(
|
||||
startingFundMeBalance
|
||||
.add(startingDeployerBalance)
|
||||
.toString(),
|
||||
endingDeployerBalance.add(withdrawGasCost).toString(),
|
||||
);
|
||||
// Make a getter for storage variables
|
||||
await expect(fundMe.getFunders(0)).to.be.reverted;
|
||||
|
||||
for (i = 1; i < 6; i++) {
|
||||
assert.equal(
|
||||
await fundMe.getAddressToAmountFunded(accounts[i].address),
|
||||
0,
|
||||
);
|
||||
}
|
||||
});
|
||||
for (i = 1; i < 6; i++) {
|
||||
assert.equal(
|
||||
await fundMe.getAddressToAmountFunded(
|
||||
accounts[i].address,
|
||||
),
|
||||
0,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("Only allow the owner to withdraw", async function () {
|
||||
const accounts = await ethers.getSigners();
|
||||
const attacker = accounts[1];
|
||||
const attacherConnectedContract = await fundMe.connect(attacker);
|
||||
await expect(attacherConnectedContract.withdraw()).to.be.reverted;
|
||||
await expect(
|
||||
attacherConnectedContract.withdraw(),
|
||||
).to.be.revertedWith("FundMe__NotOwner");
|
||||
});
|
||||
});
|
||||
it("Only allow the owner to withdraw", async function () {
|
||||
const accounts = await ethers.getSigners();
|
||||
const attacker = accounts[1];
|
||||
const attacherConnectedContract =
|
||||
await fundMe.connect(attacker);
|
||||
await expect(attacherConnectedContract.withdraw()).to.be
|
||||
.reverted;
|
||||
await expect(
|
||||
attacherConnectedContract.withdraw(),
|
||||
).to.be.revertedWith("FundMe__NotOwner");
|
||||
});
|
||||
});
|
||||
|
||||
describe("cheaperWithdraw", async function () {
|
||||
beforeEach(async function () {
|
||||
await fundMe.fund({ value: eth1 }); // Add 1 ETH first
|
||||
});
|
||||
it("Withdraw ETH from a single funder", async function () {
|
||||
/*
|
||||
* Deployer = funder
|
||||
* fundMe and replace with ethers, important to getBalance
|
||||
*/
|
||||
describe("cheaperWithdraw", async function () {
|
||||
beforeEach(async function () {
|
||||
await fundMe.fund({ value: eth1 }); // Add 1 ETH first
|
||||
});
|
||||
it("Withdraw ETH from a single funder", async function () {
|
||||
/*
|
||||
* Deployer = funder
|
||||
* fundMe and replace with ethers, important to getBalance
|
||||
*/
|
||||
|
||||
// Arrange
|
||||
const startingFundMeBalance = await fundMe.provider.getBalance(
|
||||
fundMe.address,
|
||||
);
|
||||
const startingDeployerBalance =
|
||||
await fundMe.provider.getBalance(deployer);
|
||||
// Arrange
|
||||
const startingFundMeBalance =
|
||||
await fundMe.provider.getBalance(fundMe.address);
|
||||
const startingDeployerBalance =
|
||||
await fundMe.provider.getBalance(deployer);
|
||||
|
||||
// Act
|
||||
const transactionResponse = await fundMe.cheaperWithdraw();
|
||||
const transactionReceipt = await transactionResponse.wait(1);
|
||||
// Act
|
||||
const transactionResponse = await fundMe.cheaperWithdraw();
|
||||
const transactionReceipt = await transactionResponse.wait(1);
|
||||
|
||||
const endingFundMeBalance = await fundMe.provider.getBalance(
|
||||
fundMe.address,
|
||||
);
|
||||
const endingDeployerBalance =
|
||||
await fundMe.provider.getBalance(deployer);
|
||||
const endingFundMeBalance = await fundMe.provider.getBalance(
|
||||
fundMe.address,
|
||||
);
|
||||
const endingDeployerBalance =
|
||||
await fundMe.provider.getBalance(deployer);
|
||||
|
||||
const { gasUsed, effectiveGasPrice } = transactionReceipt; //gasUsed = "0x8b14"; effectiveGasPrice = "0x4e4814ec";
|
||||
const gasCost = gasUsed.mul(effectiveGasPrice);
|
||||
const { gasUsed, effectiveGasPrice } = transactionReceipt; //gasUsed = "0x8b14"; effectiveGasPrice = "0x4e4814ec";
|
||||
const gasCost = gasUsed.mul(effectiveGasPrice);
|
||||
|
||||
// Assert
|
||||
assert.equal(endingFundMeBalance, 0);
|
||||
assert.equal(
|
||||
startingFundMeBalance.add(startingDeployerBalance),
|
||||
endingDeployerBalance.add(gasCost).toString(),
|
||||
);
|
||||
});
|
||||
// Assert
|
||||
assert.equal(endingFundMeBalance, 0);
|
||||
assert.equal(
|
||||
startingFundMeBalance.add(startingDeployerBalance),
|
||||
endingDeployerBalance.add(gasCost).toString(),
|
||||
);
|
||||
});
|
||||
|
||||
it("Allow us to withdraw with multiple funders", async function () {
|
||||
const accounts = await ethers.getSigners();
|
||||
for (let a = 0; a < 6; a++) {
|
||||
const fundMeConnectedContract = await fundMe.connect(
|
||||
accounts[a],
|
||||
);
|
||||
await fundMeConnectedContract.fund({ value: eth1 });
|
||||
}
|
||||
it("Allow us to withdraw with multiple funders", async function () {
|
||||
const accounts = await ethers.getSigners();
|
||||
for (let a = 0; a < 6; a++) {
|
||||
const fundMeConnectedContract = await fundMe.connect(
|
||||
accounts[a],
|
||||
);
|
||||
await fundMeConnectedContract.fund({ value: eth1 });
|
||||
}
|
||||
|
||||
const startingFundMeBalance = await fundMe.provider.getBalance(
|
||||
fundMe.address,
|
||||
);
|
||||
const startingDeployerBalance =
|
||||
await fundMe.provider.getBalance(deployer);
|
||||
const startingFundMeBalance =
|
||||
await fundMe.provider.getBalance(fundMe.address);
|
||||
const startingDeployerBalance =
|
||||
await fundMe.provider.getBalance(deployer);
|
||||
|
||||
// Act
|
||||
const transactionResponse = await fundMe.cheaperWithdraw();
|
||||
// Let's comapre gas costs :)
|
||||
// const transactionResponse = await fundMe.cheaperWithdraw()
|
||||
const transactionReceipt = await transactionResponse.wait();
|
||||
const { gasUsed, effectiveGasPrice } = transactionReceipt;
|
||||
const withdrawGasCost = gasUsed.mul(effectiveGasPrice);
|
||||
console.log(`GasCost: ${withdrawGasCost}`);
|
||||
console.log(`GasUsed: ${gasUsed}`);
|
||||
console.log(`GasPrice: ${effectiveGasPrice}`);
|
||||
const endingFundMeBalance = await fundMe.provider.getBalance(
|
||||
fundMe.address,
|
||||
);
|
||||
const endingDeployerBalance =
|
||||
await fundMe.provider.getBalance(deployer);
|
||||
// Assert
|
||||
assert.equal(
|
||||
startingFundMeBalance.add(startingDeployerBalance).toString(),
|
||||
endingDeployerBalance.add(withdrawGasCost).toString(),
|
||||
);
|
||||
// Make a getter for storage variables
|
||||
await expect(fundMe.getFunders(0)).to.be.reverted;
|
||||
// Act
|
||||
const transactionResponse = await fundMe.cheaperWithdraw();
|
||||
// Let's comapre gas costs :)
|
||||
// const transactionResponse = await fundMe.cheaperWithdraw()
|
||||
const transactionReceipt = await transactionResponse.wait();
|
||||
const { gasUsed, effectiveGasPrice } = transactionReceipt;
|
||||
const withdrawGasCost = gasUsed.mul(effectiveGasPrice);
|
||||
console.log(`GasCost: ${withdrawGasCost}`);
|
||||
console.log(`GasUsed: ${gasUsed}`);
|
||||
console.log(`GasPrice: ${effectiveGasPrice}`);
|
||||
const endingFundMeBalance = await fundMe.provider.getBalance(
|
||||
fundMe.address,
|
||||
);
|
||||
const endingDeployerBalance =
|
||||
await fundMe.provider.getBalance(deployer);
|
||||
// Assert
|
||||
assert.equal(
|
||||
startingFundMeBalance
|
||||
.add(startingDeployerBalance)
|
||||
.toString(),
|
||||
endingDeployerBalance.add(withdrawGasCost).toString(),
|
||||
);
|
||||
// Make a getter for storage variables
|
||||
await expect(fundMe.getFunders(0)).to.be.reverted;
|
||||
|
||||
for (i = 1; i < 6; i++) {
|
||||
assert.equal(
|
||||
await fundMe.getAddressToAmountFunded(accounts[i].address),
|
||||
0,
|
||||
);
|
||||
}
|
||||
});
|
||||
for (i = 1; i < 6; i++) {
|
||||
assert.equal(
|
||||
await fundMe.getAddressToAmountFunded(
|
||||
accounts[i].address,
|
||||
),
|
||||
0,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("Only allow the owner to withdraw", async function () {
|
||||
const accounts = await ethers.getSigners();
|
||||
const attacker = accounts[1];
|
||||
const attacherConnectedContract = await fundMe.connect(attacker);
|
||||
await expect(attacherConnectedContract.cheaperWithdraw()).to.be
|
||||
.reverted;
|
||||
await expect(
|
||||
attacherConnectedContract.cheaperWithdraw(),
|
||||
).to.be.revertedWith("FundMe__NotOwner");
|
||||
});
|
||||
});
|
||||
});
|
||||
it("Only allow the owner to withdraw", async function () {
|
||||
const accounts = await ethers.getSigners();
|
||||
const attacker = accounts[1];
|
||||
const attacherConnectedContract =
|
||||
await fundMe.connect(attacker);
|
||||
await expect(attacherConnectedContract.cheaperWithdraw()).to
|
||||
.be.reverted;
|
||||
await expect(
|
||||
attacherConnectedContract.cheaperWithdraw(),
|
||||
).to.be.revertedWith("FundMe__NotOwner");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user