323 lines
14 KiB
JavaScript
323 lines
14 KiB
JavaScript
const { ethers, deployments, getNamedAccounts } = require("hardhat");
|
|
const { expect, assert } = require("chai");
|
|
const { developmentChains } = require("../../helper-hardhat-config");
|
|
|
|
// 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,
|
|
);
|
|
});
|
|
|
|
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 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 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
|
|
});
|
|
|
|
// 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
|
|
|
|
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");
|
|
|
|
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);
|
|
});
|
|
});
|
|
|
|
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);
|
|
|
|
// 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 { 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(),
|
|
);
|
|
});
|
|
|
|
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);
|
|
|
|
// 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,
|
|
);
|
|
}
|
|
});
|
|
|
|
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
|
|
*/
|
|
|
|
// 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);
|
|
|
|
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);
|
|
|
|
// 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 });
|
|
}
|
|
|
|
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;
|
|
|
|
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");
|
|
});
|
|
});
|
|
});
|