# 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>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://thryec.gitbook.io/dev-compedium/ethereum/foundry.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
