# Foundry

## Installation&#x20;

(For Linux and MacOS Users)&#x20;

Install `foundryup`:&#x20;

```shell
curl -L https://foundry.paradigm.xyz | bash
```

This will download `foundryup`. Then install Foundry by running:

```shell
foundryup
```

## Basic Commands &#x20;

To start a new project with Foundry:&#x20;

```shell
forge init hello_foundry
```

Compile Solidity code:&#x20;

```shell
forge build
```

Run Solidity tests:&#x20;

```shell
forge test -vvvv 
```

## Install Dependencies&#x20;

```bash
forge install transmissions11/solmate
forge install openzeppelin/openzeppelin-contracts
forge install smartcontractkit/chainlink-brownie-contracts
```

#### Generate remappings for installed libraries

```bash
forge remappings > remappings.txt
```

#### Update Dependencies&#x20;

```bash
forge update lib/<dependency-name>
```

## Unit Testing&#x20;

{% tabs %}
{% tab title="State Inheritance Testing" %}

```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.16;

import "forge-std/Test.sol";
import "../src/SampleContract.sol";
import "forge-std/console.sol";

// vm deployer address: 0xb4c79daB8f259C7Aee6E5b2Aa729821864227e84

abstract contract StateZero is Test {
    SampleContract internal sampleContract; 
    address alice;
    address bob;
    
    function setUp() public virtual {
        sampleContract = new SampleContract();
        alice = address(0x1);
        bob = address(0x2);

        vm.label(alice, "alice");
        vm.label(bob, "bob");
    }
} 

contract StateZeroTest is StateZero {
    function testChangeStateOne() public {} 
    
    function testChangStateOneReverts() public {
         vm.expectRevert(bytes("revert message"));
         // call function that is intended to revert here 
    }
    
    function testChangStateOneEmitsEvent() public {
         vm.expectEmit(true, true, true, true);
         // 1. emit the event with expected values 
         // 2. call function that is intended to emit the event  
    }
} 

abstract contract StateOne is StateZero {
    function setUp() public virtual override {
        // run initial set-up function from StateZero 
        super.setUp();
        
        // function that changes state from zero to one
        sampleContract.changeStateOne(); 
    }
}

contract StateOneTest is StateOne {
    function testChangeStateTwo() public {} 
    
} 
```

{% endtab %}

{% tab title="SampleContract.sol" %}

```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.16;

import "forge-std/console2.sol";
import "openzeppelin-contracts/contracts/access/Ownable.sol";
import "openzeppelin-contracts/contracts/utils/Counters.sol";

contract SampleContract {
    // initialising new counter variable 
    using Counters for Counters.Counter;
    Counters.Counter public someId; 
    
    .... 

} 
```

{% endtab %}
{% endtabs %}

## Fuzz Testing&#x20;

Fuzz testing is done by using a range of randomized possible inputs to test for edge cases, instead of just testing it with select inputs as in unit testing.&#x20;

Foundry lets us do this natively.&#x20;

{% tabs %}
{% tab title="Fuzz Tests" %}

```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Test.sol";
import "../src/Counter.sol";

contract CounterTest is Test {
    Counter public counter;

    function setUp() public {
        counter = new Counter();
    }

    // Fuzz test for setNumber function
    function testFuzz_SetNumber(uint256 x) public {
        counter.setNumber(x);
        assertEq(counter.number(), x);
    }

    // Fuzz test for multiple increment operations
    function testFuzz_Increment(uint8 numberOfIncrements) public {
        uint256 startingValue = counter.number();
        
        for (uint i = 0; i < numberOfIncrements; i++) {
            counter.increment();
        }
        
        assertEq(counter.number(), startingValue + numberOfIncrements);
    }

    // Fuzz test for combining setNumber and increment
    function testFuzz_SetAndIncrement(uint256 x, uint8 incrementTimes) public {
        counter.setNumber(x);
        
        uint256 expectedValue = x;
        for (uint i = 0; i < incrementTimes; i++) {
            // Check for potential overflow
            if (expectedValue < type(uint256).max) {
                counter.increment();
                expectedValue++;
            } else {
                // If we would overflow, don't increment anymore
                break;
            }
        }
        
        assertEq(counter.number(), expectedValue);
    }
}
```

{% endtab %}

{% tab title=" Base Counter Contract" %}

```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

contract Counter {
    uint256 public number;

    function setNumber(uint256 newNumber) public {
        number = newNumber;
    }

    function increment() public {
        number++;
    }
}

```

{% endtab %}
{% endtabs %}

To run these fuzz tests, use:

```bash
forge test --match-test testFuzz
```

## Additional Security&#x20;

### Checking Test Coverage&#x20;

```bash
forge coverage --report summary
```

### Static Analysis (Slither)&#x20;

### Invariant Testing&#x20;

## Deployment&#x20;

#### Create .env file in root folder:&#x20;

```bash
PRIVATE_KEY=
ETHERSCAN_KEY=
GOERLI_RPC_URL=
```

#### Update foundry.toml:

```toml
[rpc_endpoints]
goerli = "${GOERLI_RPC_URL}"

[etherscan]
goerli = { key = "${ETHERSCAN_KEY}" }

```

#### SampleContract.s.sol&#x20;

```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.16;

import "../src/SampleContract.sol";
import "forge-std/Script.sol";

contract SampleContractScript is Script {
    function setUp() public {}

    function run() public {
        uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
        vm.startBroadcast(deployerPrivateKey);
        
        SampleContract contract = new SampleContract();        
        vm.stopBroadcast();
    }
}

```

To run the above script:&#x20;

```shell
forge script script/SampleContract.s.sol
```

To deploy `SampleContract` to a live testnet, run the following in your terminal:&#x20;

```shell
forge script script/SampleContract.s.sol:SampleContractScript --rpc-url $GOERLI_RPC_URL --broadcast \
```

### Verification&#x20;

To verify an existing contract:

<pre><code>forge verify-contract --chain-id 5 --num-of-optimizations 1000000 --watch \
--compiler-version v0.8.16+commit.fc410830 &#x3C;the_contract_address> \
<strong>src/SampleContract.sol:SampleContract &#x3C;your_etherscan_api_key>
</strong></code></pre>

Check verification status:&#x20;

```
forge verify-check --chain-id 5 <GUID> <your_etherscan_api_key>
```

References:&#x20;

<https://book.getfoundry.sh/tutorials/solidity-scripting#deploying-our-contract>
