# Mainnet forking with Forge 

By [Sushi](https://paragraph.com/@susheen) · 2022-02-03

---

![How a solidity engineer feels while using Foundry](https://storage.googleapis.com/papyrus_images/a99e00cf7e019259d8a8e5a5c9d1102c56798bdf6c8526ca037c6161d2f9092d.jpg)

How a solidity engineer feels while using Foundry

**Foundry** is a **fast**, **portable** toolkit for Ethereum development. It’s an improvement on the amazing [Dapptools](https://github.com/dapphub/dapptools) framework, written in **Rust** (_even God is rewriting the human genetic code in Rust and you have doubts anon?_).

If you’re hearing about [Foundry](https://github.com/gakonst/foundry) for the first time, then I suggest you first check out

*   [Introducing the Foundry Ethereum development toolbox](https://www.paradigm.xyz/2021/12/introducing-the-foundry-ethereum-development-toolbox) for a general overview.
    
*   These two articles (by [Cris garner](https://mirror.xyz/crisgarner.eth/BhQzl33tthkJJ3Oh2ehAD_2FXGGlMupKlrUUcDk0ALA), by [Wilson](https://w.mirror.xyz/mOUlpgkWA178HNUW7xR20TdbGRV6dMid7uChqxf9Z58)) to get started with Foundry.
    

What’s Mainnet forking?
-----------------------

Mainnet forking is when you fork the state of a live network and use it locally, usually to test your contracts against the live state. This can be extremely helpful while testing and can get you started without having to deploy a bunch of contracts to a local testnet to set up the environment.

![Basically mainnet forking](https://storage.googleapis.com/papyrus_images/00c80e45e22cf22dfca9cf42cc884c2aff33215e4c740ccc396419e66c712406.jpg)

Basically mainnet forking

Mainnet forking with Forge
--------------------------

In this article, we’re gonna locally simulate a swap on Uniswap. I chose Uniswap because playing around with the live state of something we all use sounded the most fun. I have intentionally chosen an approach that requires the least code to simulate the swap, so we can just focus on forge mainnet forking. We will be simulating the swap on the `Rinkeby` network since it’s easier for this example, but the steps should be identical while forking from Mainnet.

Making the swap using call data
-------------------------------

In Ethereum, all you need to interact with a contract is the contract address, the function you’re calling, and the input parameters. The _function name_ and the _input parameters_ are encoded and set as the call data for the transaction.

The easiest way is to just attempt the same swap on the Uniswap interface and get the generated data from MetaMask. Let’s do that. In case you don’t have Rinkeby Eth, if not you can get some from [Paradigm](https://www.paradigm.xyz)’s awesome [MultiFaucet](https://faucet.paradigm.xyz/).

Go on to the Uniswap interface, make sure you’re on the `Rinkeby` network, and initiate a swap for 1 Eth to Dai. It should look like this.

![](https://storage.googleapis.com/papyrus_images/a0fb7ab38b45b25d18c07da7b7436773e1153e45d244e3025611f77406f908bf.png)

Initiate the swap, and you should get the familiar MetaMask popup. Now instead of confirming the transaction, check out the Data and Hex tab.

![Data information on MetaMask](https://storage.googleapis.com/papyrus_images/6a289037259edda4b39f071f4e61c4678317b021d62dff347d4be2494562d7dd.png)

Data information on MetaMask

We can see that we are calling the `Multicall` function with `uint256` and `bytes[]` as input parameters. (_Ignore the Fetch failed_).

On the HEX tab, you’ll see parameter information and a lot of Hex data (_cropped out here_). This is the _hex encoding_ of the function signature and the input parameters.

![Call data generated by MetaMask](https://storage.googleapis.com/papyrus_images/901337a324a41bb924763f6d0fefd588b82fe58d208387730d4d40e4b3e28950.png)

Call data generated by MetaMask

Now we have

*   The contract address to call. (_Top right on MetaMask_)
    
*   Hex encoded call data (_you can copy the raw transaction data at the bottom of the popup_)
    

We have everything to simulate the swap locally.

Small detour
------------

Before we start, let’s quickly see what the call data encodes. For this, we can use this [ETH Calldata Decoder](https://apoorvlathey.com/eth-calldata-decoder/) by [Apoorv Lathey](https://apoorvlathey.com/). After decoding the calldata, we see that the `uint256` parameter is `deadline` which is a UNIX timestamp. We can assume that’s it’s the deadline before the swap must take place, we will play with this later.

![](https://storage.googleapis.com/papyrus_images/29c781d3264a0e81c995cf3888aee84447d27c6a379ed422bfe016432ad2f3cc.png)

Setting up the project
----------------------

Go to your terminal, and run the following commands to initialize a forge project and `cd` into the newly created folder.

    forge init simulate-swap
    cd simulate-swap
    

Navigate to `src/test/Contract.t.sol` , this is where we will be writing our simulation.

Writing the contract
--------------------

Paste this snippet in `Contract.t.sol`.

    // SPDX-License-Identifier: Unlicense
    pragma solidity ^0.8.6;
    
    import "ds-test/test.sol";
    
    // for cheatcodes
    interface Vm {
        function prank(address) external;
    
        function warp(uint256) external;
    }
    
    // to verfiy that we recevied Dai
    interface Dai {
        function balanceOf(address) external view returns (uint256);
    }
    
    contract ContractTest is DSTest {
        Vm vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
    Dai dai = Dai(0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735);
    
    // your address
        address constant myAddress = "your ethereum address";
    
    // contract address from MetaMask
        address constant swapDai = 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45;
    
       
        
    
        function testSwap() public {
    
    // to verify if we are actually forking
            emit log_named_uint("Current ether balance of myAddress", myAddress.balance);
    
            emit log_named_uint("Dai balance of myAddress before", dai.balanceOf(myAddress));
            
            
            
    // type casting hex call data to bytes
            bytes
                memory data = hex"paste the hex call data here. Remove the leading '0x' ";
    
    // setting the next call's msg.sender as myAddress
            vm.prank(myAddress);
    
    
            (bool sent, ) = payable(swapDai).call{value: 1 ether}(data);
            require(sent, "failed");
    
            
    
            emit log_named_uint("Dai balance of myAddress after", dai.balanceOf(myAddress));
            
        }
    }
    

Explaining the code
-------------------

### What are those interfaces?

*   The `Dai` interface is to get the balance of our address before and after the swap.
    
*   The `Vm` interface is to use **cheatcodes.**
    
    *   You might be familiar with this if you’re coming from Dapptools (or Grand Theft Auto). If you’re not, then think of it like this, Dapptools/Foundry uses a custom EVM to run tests in solidity, this enables us to do wacky stuff like changing the block.timestamp, changing the storage of contracts, setting the msg.sender, etc.
        
    *   You can see how amazing this would be for testing. Add mainnet forking and you have a solid development framework.
        
    *   Here `vm.prank(myAddress)` sets the msg.sender of the next call to `myAddress`
        
    *   `vm.warp(uint)` allows you to set the block.timestamp.
        
    *   For more details check out the [repo](https://github.com/gakonst/foundry/tree/master/forge)
        

### How are we making the swap?

*   We set the contract address we got from MetaMask.
    
*   We typecast the hex call data to bytes.
    
*   Make the contract call using `call`
    
*   Emitting the balance before and after to make sure the swap worked.
    

Environment set up
------------------

We just need to set one environment variable, `ETH_RPC_URL` to your RPC provider endpoint. Make sure it’s the endpoint for the network you want to fork.

Run this command in your terminal.

    ETH_RPC_URL="paste your rpc url here"
    

Making the swap
---------------

Now that’s everything is set up, let’s run the simulation. Run this command in your terminal.

    forge test --fork-url $ETH_RPC_URL -vv
    

You should see an output like this

![](https://storage.googleapis.com/papyrus_images/da9f6eef344b99d77c77cce5f4bc37687f87fbb85f4fdc82fbd84969ff7d7723.png)

Well done! You just successfully forked the state of a live network and played God with it.

Bonus
-----

If you are experimenting with this swap for a considerable amount of time, you might notice that after a while the swap doesn’t work. This is because of the deadline parameter that we saw earlier. After the deadline the swap is invalid. What do can we do? You know where I’m going with this, cheatcodes!

This can be a fun exercise, using `warp(uint)` + the decoded `deadline` timestamp, play around and see when the swap is valid/invalid. Happy forging!

---

*Originally published on [Sushi](https://paragraph.com/@susheen/mainnet-forking-with-forge)*
