Use Foundry fork to read intenal state in Solidity?
Learn to query internal variables of a smart contract easily, using Foundry ⚒️ without calculating storage slots! 🧮
The trick is: vm.etch()
cheatcode
Let’s say we have this simple Token contract already deployed
And we want to fetch the value of _decimals
, which is an internal variable.
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.23;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract Token is ERC20("Token", "TKN") {
uint8 internal _decimals;
}
To do so we first clone the contract in our foundry repo
Then add a public function that returns _decimals
like this:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.23;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract ModifiedToken is ERC20("Token", "TKN") {
uint8 internal _decimals;
function getDecimals() external view returns (uint8) {
return _decimals;
}
}
The last step is to create Test file as follow:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.23;
import {Test} from "forge-std/Test.sol";
import {console} from "forge-std/console.sol";
import {Token} from "src/Token.sol";
import {ModifiedToken} from "src/ModifiedToken.sol";
contract TokenFetchInternalTest is Test {
address deployedToken = 0x50ecf50eE63Af22a4bc450366413B6646a23B5AF;
function setUp() public {
vm.createSelectFork(vm.envString("MUMBAI_RPC_URL"));
}
function testFetchInternalValue() public {
emit log_bytes(address(deployedToken).code);
bytes memory code = vm.getCode("ModifiedToken.sol:ModifiedToken");
vm.etch(deployedToken, code);
emit log_bytes(address(deployedToken).code);
ModifiedToken modifiedToken = ModifiedToken(deployedToken);
console.log(modifiedToken.getDecimals());
}
}
-
We fork with RPC URL
-
Using vm.etch() we can modify the bytecode locally, of an already deployed contract
-
This allows us to call our new getDecimals() function, which exposes the internal variable’s value.
Another cool use case of vm.etch()
is that you can add console.log
to existing contracts and run tests
This way you can easily get intermediate values from a txn without debugging through the stack trace!
Happy coding!