> For the complete documentation index, see [llms.txt](https://notes.nomanaziz.me/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://notes.nomanaziz.me/development/blockchain/freecodecamp-course/7.-hardhat-or-fund-me.md).

# 7. Hardhat | Fund Me

### Linting

* `solhint` is a linter for solidity which will analyze code for potential errors, checks for best practices of code and does formatting

***

### Hardhat Deploy

* `hardhat-deploy` is an npm package which automates the process of writing deploy scripts for our contracts
  * Needs to be overriden as per github instructions
* Add a `require` statement in `hardhat.config.js`
* Make a `deploy` folder in the project which will contain deployment configuration

#### deploy/01-deploy-fund-me.js

```js
// Method 1
// function deployFunc() {
//     console.log("Hi!")
// }

// module.exports.default = deployFunc

// Method 2
// module.exports = async (hre) => {
//     // hre.getNamedAccounts, hre.deployments
//     const { getNamedAccounts, deployments } = hre
// }

// Method 3
module.exports = async ({ getNamedAccounts, deployments }) => {
    const { deploy, log } = deployments
    const { deployer } = await getNamedAccounts()
    const chainId = network.config.chainId
}
```

***

### Mocking & helper-hardhat-config

* Mocking which is used in unit testing is creating objects that simulate behaviour of real objects
* We want to use mock when using localhost or hardhat network for the price converter contract
* helper-hardhat-config is a javascript file taken from `aave` [repository](https://github.com/aave/aave-v3-core) which deploys their code to multiple different chains and multiple different addresses, it will help us get priceFeed address (of chainlink) for the chain that we uses
* When we run a local hardhat node, it will automatically deploy all the contracts

#### contracts/FundMe.sol

Added `priceFeedAddress` in constructor for dynamic chain eth/usd mapping

```sol
// ...
contract FundMe {
    // ...
    AggregatorV3Interface public priceFeed;

    constructor(address priceFeedAddress) {
        i_owner = msg.sender;
        priceFeed = AggregatorV3Interface(priceFeedAddress);
    }

    function fund() public payable {
        require(
            msg.value.getConversionRate(priceFeed) >= MINIMUM_USD,
            "Didn't send enough!"
        );
        funders.push(msg.sender);
        addressToAmountFunded[msg.sender] = msg.value;
    }
    // ...
}
```

#### contracts/PriceConverter.sol

Adjusted this contract as per FundMe contract to accept dynamic `priceFeed` contract address

```sol
// ...
library PriceConverter {
    function getPrice(AggregatorV3Interface priceFeed)
        internal
        view
        returns (uint256)
    {
        (, int256 price, , , ) = priceFeed.latestRoundData();
        return uint256(price * 1e10);
    }

    function getConversionRate(
        uint256 ethAmount,
        AggregatorV3Interface priceFeed
    ) internal view returns (uint256) {
        uint256 ethPrice = getPrice(priceFeed);
        uint256 ethAmountInUsd = (ethPrice * ethAmount);
        ethAmountInUsd /= 1e18;
        return ethAmountInUsd;
    }
}
```

#### contracts/test/MockV3Aggregator.sol

```sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0; // We can add different solidity compiler versions in hardhat config

// Importing directly the mock contract from chainlink repo
import "@chainlink/contracts/src/v0.6/tests/MockV3Aggregator.sol";
```

#### helper-hardhat-config.js

```js
const networkConfig = {
    5: {
        name: "goerli",
        ethUsdPriceFeed: "0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e"
    },
    137: {
        name: "polygon",
        ethUsdPriceFeed: "0xF9680D99D6C9589e2a93a78A04A279e509205945"
    }
}

const developmentChains = ["hardhat", "localhost"]
const DECIMALS = "8"
const INITIAL_PRICE = "200000000000"

module.exports = {
    networkConfig,
    developmentChains,
    DECIMALS,
    INITIAL_PRICE,
}
```

#### deploy/00-deploy-mocks.js

```js
const { network } = require("hardhat")
const { developmentChains, DECIMALS, INITIAL_PRICE } = require("../helper-hardhat-config")

module.exports = async ({ getNamedAccounts, deployments }) => {
    const { deploy, log } = deployments
    const { deployer } = await getNamedAccounts()
    const chainId = network.config.chainId

    if (developmentChains.includes(network.name)) {
        log("Local network detected! Deploying mocks...")

        await deploy("MockV3Aggregator", {
            contract: "MockV3Aggregator",
            from: deployer,
            log: true,
            args: [DECIMALS, INITIAL_PRICE], // Required arguments in mock contract as per github code
        })

        log("Mocks deployed!")
        log("--------------------------------------------------")
    }
}

// run only when we specify these tags in deploy command i.e `yarn hardhat deploy --tags mocks`
module.exports.tags = ["all", "mocks"]
```

#### 01-deploy-fund-me.js

```js
const { networkConfig, developmentChains } = require("../helper-hardhat-config")
const { network } = require("hardhat")

module.exports = async ({ getNamedAccounts, deployments }) => {
    const { deploy, log, get } = deployments
    const { deployer } = await getNamedAccounts()
    const chainId = network.config.chainId

    // if chainId is X use address Y
    // if chainId is Z use address A
    let ethUsdPriceFeedAddress

    if (developmentChains.includes(network.name)) {
        const ethUsdAggregator = await get("MockV3Aggregator")
        ethUsdPriceFeedAddress = ethUsdAggregator.address
    } else {
        ethUsdPriceFeedAddress = networkConfig[chainId]["ethUsdPriceFeed"];
    }

	// if the contract doesn't exist, we deploy a minimal version of contract for our testing
	// what happens when we want to change chains
	// when going for localhost or hardhat network, we want to use a mock

    const fundMe = await deploy("FundMe", {
        from: deployer,
        args: [ethUsdPriceFeedAddress], // put price feed address
        log: true
    })

    log("-------------------------------------------------------")
}

module.exports.tags = ["all", "fundme"]
```

***

### Utils Folder

* We put commonly used scripts in this folder like the verify contract so that every one uses it (OOP)

#### utils/verify.js

```js
const { run } = require("hardhat")

const verify = async (contractAddress, args) => {
    console.log("Verifying contract...")
    try {
        await run("verify:verify", {
            address: contractAddress,
            constructorArguments: args
        })
    } catch (e) {
        if (e.message.toLowerCase().includes("already verified")) {
            console.log("Already Verified!")
        } else {
            console.log(e)
        }
    }
}

module.exports = { verify }
```

#### deploy/01-deploy-fund-me.js

```js
// ...
    const args = [ethUsdPriceFeedAddress]
    const fundMe = await deploy("FundMe", {
        from: deployer,
        args: args, // put price feed address
        log: true,
        waitConfirmations: network.config.blockConfirmations || 1,
    })

    if (!developmentChains.includes(network.name) && process.env.ETHERSCAN_API_KEY) {
        // verify the contracts
        await verify(fundMe.address, args)
    }

    log("-------------------------------------------------------")
```

***

### Solidity Style Guide

* We are going to follow solidity docs official style guide to make our code much neater and readable by following orders and conventions
* We use `Natspec` format to document our code
  * Used later on to automatically generate code documentation for other developeres

***

### Test FundMe

* We make seperate tests for `staging` & `unit`
* In unit tests, individual components are tested
  * They are done `locally`
    * on local hardhat network
    * fored hardhat network
  * Similar to SimpleStorage tests written in previous notes section
* In staging or integration tests, whole flow is tested, usually done before deploying to production
  * They are done on a `testnet`

***

### Debugging & Breakpoints

* We can pin a breakpoint in vscode & use `javascript debug terminal` to debug the code and see variable values on the breakpoints

***

### Solidity-Console-Log

* In solidity, we can import `hardhat/console.sol;` and use `console.log()` inside the solidity code to debug the contract

***

### Storage in Solidity

* Each global/storage variable is stored seperately in the storage
* Each slot is 32 bytes long and represents the bytes version of the object
  * e.g, uint256 25 is 0x000...0019 since thats the hex representation
  * For aa "true" boolean, it would be 0x000...001 since thats its hex
* For dynamic values like mappings and dynamic arrays, the elements are stored using a hashing function. More info in documentation
  * For arrays, a sequential storage spot is taken up for the length of the array
  * For mappings, a sequantial storage spot is taken up, but left blank
* Constants and immutable variables are not stored in storage, but they are considered part of the core of the bytecode of the contract

#### getStorageAt

We can query smart contracts to find out values of stored variables at a particular slot

```js
log("logging storage")
for (let i = 0; i < 10; i++) {
	log(
		`Location ${i}: ${await ethers.provider.getStorageAt(
			fundMe.address,
			i
		)}`
	)
}
```

#### Gas & OpCodes

* When we compile our contracts, in our bytecode object, there are opcodes present. Each opCode represent an operation in the contract
* Each opCode has a gas price associated with it
* `SLOAD` opcode is used to load word from storage and it costs 800 gas
* `SSTORE` opcode is used to save word to storage and it costs 20000\*\* gas
* Therefore, in our contracts, we prepend `s_` keyword with variable names to denote that they are storage varaibles and will cost a lot of gas

***

### Solidity Chainlink Style Guide

* For normal contract users, we should make the `s_<variables>` private and make naming friendly getter functions for them.

***

### Reference Code

<https://github.com/Noman-Aziz/Hardhat-101-FundMe>

***
