# Mainnet forking with Forge **Published by:** [Sushi](https://paragraph.com/@susheen/) **Published on:** 2022-02-03 **URL:** https://paragraph.com/@susheen/mainnet-forking-with-forge ## Content How a solidity engineer feels while using FoundryFoundry is a fast, portable toolkit for Ethereum development. It’s an improvement on the amazing 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 for the first time, then I suggest you first check outIntroducing the Foundry Ethereum development toolbox for a general overview.These two articles (by Cris garner, by Wilson) 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 forkingMainnet forking with ForgeIn 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 dataIn 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’s awesome MultiFaucet. 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.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 MetaMaskWe 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 MetaMaskNow we haveThe 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 detourBefore we start, let’s quickly see what the call data encodes. For this, we can use this ETH Calldata Decoder by Apoorv Lathey. 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.Setting up the projectGo 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 contractPaste 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 codeWhat 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 myAddressvm.warp(uint) allows you to set the block.timestamp.For more details check out the repoHow 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 callEmitting the balance before and after to make sure the swap worked.Environment set upWe 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 swapNow 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 thisWell done! You just successfully forked the state of a live network and played God with it.BonusIf 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! ## Publication Information - [Sushi](https://paragraph.com/@susheen/): Publication homepage - [All Posts](https://paragraph.com/@susheen/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@susheen): Subscribe to updates - [Twitter](https://twitter.com/statemachines_): Follow on Twitter