-
Hello! I am on the timestampt (11:23:41) of the course where patrick runs the command My FundMe.sol file code: //SPDX-License-Identifier: MIT
// We want to
// Get funds from users, withdraw funds and set a minimum funding value in USD
// in solidity, there r 2 keywords using which we can keep variables constant:
// Conventions: constant var: ALL CAPS, immutable var: i_varname
// we can further make our contract gas efficient by
// pragma:
pragma solidity ^0.8.8;
// imports:
import "./PriceConvertor.sol"; // imported the library
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
// error codes: shud be written as NameOfContract_Error()
error FundMe__NotOwner(); // to replace if statement
// INterfaces, Libraries, Contracts
/** @title A Contract For Crowd Funding
* @author Patrick Collins
* @notice This contract is to demo a sample funding contracts
* @dev This implements price feeds as our library
*/
contract FundMe {
// Type Declarations
using PriceConvertor for uint256; // using this as a library on top of uinit256
//uint256 public number;
// State Variables
// lets set the min USD value that we want peoPle to send
// multiplied by 1e18 bcoz ConversionRate() will return a value with 18 zeros
uint256 public constant minUSD = 50 * 1e18; // This value is assigned outside the BC and to get this value in BC
// lets create some data structures to keep a track of funders
//creating an array of addresses called funders and we will keep adding all the funders who keep sending money to us
address[] public funders;
mapping(address => uint256) public addressToAmountFunded; // crating a mapping from addresses to value funded
address public immutable owner; //creating a global variable. we will set this only once
AggregatorV3Interface public priceFeed;
// current issue: anybody can withdraw from this contract, we want withdraw func to be called only by the owner of this contract
// modifier is gonna be a keyword that we gonna add right in the function declaration to modify the func with that functionality
modifier onlyOwner() {
// this part will get looked into 1st and then the rest of the code of withdraw()
//require(msg.sender == i_owner, "Sender is not owner");// as we want the condition of only owner to withdraw funds
if (msg.sender != owner) {
revert FundMe__NotOwner();
} // this ends up saving lots of gas as we don't have to store a string
// revert keyword does the exact same thing as require, without the condition
_; // this underscore represents doing the rest of the code
} // if the require statement would have been below underscore, the rest of the code would have been executed 1st and then the condition
// we are parameterizing the priceFeedAddress and passing it with a constructor that gets saved as a global var into an
// aggregatorV3 interface type, or passing it to a getConversionRate function, which passes it to the het price function, which then just calls latestRoundData
constructor(address priceFeedAddress) {
// one of the parameters which we would like constructor to have is the address
// func that gets called immediately, whenever u deploy a contract
// we can have the constructor set up who the owner of this contract is
owner = msg.sender; // msg.sender will be whoever deployed this contract
priceFeed = AggregatorV3Interface(priceFeedAddress);
}
// What happens if someone sends this contract ETH without calling the fund function ?
// we can add fallback and receive funcs just in case somebody actully sends us contract money instead of calling fund()
receive() external payable {
fund();
}
fallback() external payable {
fund();
}
/**
* @notice This function funds this contract
* @dev This implements price feeds as our library
*/
function fund() public payable {
require(
msg.value.getConversionRate(priceFeed) >= minUSD, // initial parameter of getConversionRate is gonna be msg.value
"Didn't send enough!" // contract will fail if not enuf ETH is sent
); //msg.value helps to access value. atleast 1 eth needs to be sent is sending anything
// we r not passing any value in getConversionRate() as msg,value in itself is that parameter
funders.push(msg.sender); // msg,sender is also an always available gloabal keyword
//.value stands for how much eth is send, .sender stands for the address of whoever calls the fund()
// since our address is sending the ether, we gonna add our address to this funders list/array
// this way we can keep track of all the donaters who are donating to our contract
addressToAmountFunded[msg.sender] = msg.value;
// money math is done in terms of wei
// require keyword is a checker
// reverting is cancelling the transaction when requirement is not met and undoing any action before and sending the remaining gas back
}
// once the funders have gone ahr=ead and funded, we r going to want the project to be able to withdraw the funds out of this contract
// so that they can actually go ahead and buy things for this project
function withdraw() public onlyOwner {
// we will have to reset our funders array and addressToAmountFunded
// since we will be withdrawing all the fund, those amnts shud go back down to 0
// hence we shud loop thru the funders array and update our mapping object so that each of these funders now has 0
for (
uint256 funderIndex = 0;
funderIndex < funders.length;
funderIndex++
) {
address funder = funders[funderIndex]; // now we have this funder address and we will use this to reset our mapping
addressToAmountFunded[funder] = 0; //in fund() we update the amnt, in withdraw() we will reset it back to 0
// we still need to reset funders array to a blank array and actually withdarw the funds
// to reset the array, we cud loop thru it and delete the objects or just totally refresh this variable
}
funders = new address[](0); // we r saying this funders var now equals a brand new address array with 0 objects in it to start
(
bool callSuccess, /*bytes memory dataReturned*/
) = payable(msg.sender).call{value: address(this).balance}(""); // leaving blank as we don't wanna call any func rn
// we will use this call func as if its a regular transaction and we can add stuff like msg.value
// call returns 2 vars
// since bytes objects are arrays, data returns needs to be in memory but as in our code, we r not callin any func, we dont care abt the data returned
require(callSuccess, "Call Failed");
}
}
hardhat,config: require("@nomicfoundation/hardhat-toolbox")
require("hardhat-deploy")
require("@nomiclabs/hardhat-ethers")
require("dotenv").config()
require("solidity-coverage")
/** @type import('hardhat/config').HardhatUserConfig */
const SEPOLIA_URL = process.env.SEPOLIA_URL || "https://eth-sepolia" // just if I do not use sepolia
const PRIVATE_KEY = process.env.PRIVATE_KEY || "Oxkey"
const ETHERSCAN_API_KEY = process.env.ETHERSCAN_API_KEY || "key"
const COINMARKETCAP_API_KEY = process.env.COINMARKETCAP_API_KEY || "key"
module.exports = {
// solidity: "0.8.8",
solidity: {
compilers: [{ version: "0.8.8" }, { version: "0.6.6" }],
},
namedAccounts: {
deployer: {
default: 0, // here this will by default take the first account as deployer
1: 0,
},
},
defaultNetwork: "hardhat",
networks: {
hardhat: {
chainId: 31337,
// gasPrice: 130000000000,
},
sepolia: {
url: SEPOLIA_URL,
accounts: [PRIVATE_KEY],
chainId: 11155111,
blockConfirmations: 6, //how many blocks we wanna wait
},
},
gasReporter: {
enabled: false,
outputFile: "gas-report.txt",
noColors: true, // the reason we do this is bcoz the colors can get messed up after adding to the file
currency: "USD", // to get the cost in USD for a BC like ethereum
coinmarketcap: COINMARKETCAP_API_KEY, // getting the API key
token: "MATIC",
},
etherscan: {
apiKey: ETHERSCAN_API_KEY,
},
}
// the deploy folder is where our hardhat deploy module looks to deploy our scripts FundMe.test.js: // we gonna use hardhat-deploy to setup our tests
// we have to 1st puul in our deployments obj
const { assert, expect } = require("chai")
const { deployments, ethers, getNamedAccounts } = require("hardhat")
describe("FundMe", function () {
let fundMe, deployer, mockV3Aggregator
const sendValue = ethers.utils.parseEther("1") // this parseEthers converts this 1 to 10^18 wei
beforeEach(async function () {
// deploy our FundMe contract using hardhat-deploy
// we can also tell ethers, which acc we want connected to fundMe
deployer = (await getNamedAccounts()).deployer // we need to abstract jus the deployer from getNamedAccounts
// another way to get accounts directly from your hardhat.config is:
/* const accounts = await ethers.getSigners()
const accountZero = accounts[0] */
await deployments.fixture(["all"])
// fixture functions allows us to run our deploy folder with as many tags as we want
// everything in that folder gets deployed by just this line
// once all of our contracts have been deployed, we will start getting them
// hardhat deploy grabs ethers with a func called getContract
fundMe = await ethers.getContract("FundMe", deployer)
// getContract will get the most recent deployment of whatever contract we tell it
// whenever we call a func with fundMe, it will automatically be from deployer acc
mockV3Aggregator = await ethers.getContract(
"MockV3Aggregator",
deployer
)
// now we gonna make a bunch of transactions on our fundMe in order to test it
})
describe("constructor", function () {
it("MockAggregator address should be the priceFeed address", async function () {
const response = await fundMe.priceFeed()
assert.equal(response, mockV3Aggregator.address)
})
})
describe("fund", async function () {
it("Fails if enuf ETH is not sent", async function () {
await expect(fundMe.fund()).to.be.revertedWith(
"You need to spend more ETH"
)
})
it("Updates the amount funded data structure", async function () {
await fundMe.fund({ value: sendValue })
const response = await fundMe.addressToAmountFunded(deployer)
assert.equal(response.toString(), sendValue.toString())
})
})
}) Please help to figure out what's wrong and how to rectify it. |
Beta Was this translation helpful? Give feedback.
Answered by
alfaqi
Jun 25, 2023
Replies: 2 comments 6 replies
-
please share your repo |
Beta Was this translation helpful? Give feedback.
1 reply
-
update your I hope this helps |
Beta Was this translation helpful? Give feedback.
5 replies
Answer selected by
Ar11-kgp
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
update your
solidity-coverage
from
"solidity-coverage": "^0.8.0",
to
"solidity-coverage": "^0.8.3",
just run this command
npm i solidity-coverage
or
yarn add solidity-coverage
I hope this helps