I've found myself accessing a lot of internal/private variables in Solidity recently, and decided to write out a reference guide for me in the future.
contract C {
address private myAddr; // Slot 0;
bytes32[] private myBytes; // Slot 1; Keccak256(1) + offset
struct MyStruct {
uint256 a;
uint256 b;
}
MyStruct private myStruct; // Slot 2;
// Slot 2 + 0 = a;
// Slot 2 + 1 = b;
}
const ethers = require("ethers");
const provider = new ethers.providers.JsonRpcProvider();
const ONE = ethers.constants.One;
const MY_CONTRACT_ADDR = "0x0....";
const main = async () => {
const myAddr = await provider.getStorageAt(MY_CONTRACT_ADDR, 0);
// myBytes is located at Slot 1
const myBytesLoc = ethers.BigNumber.from(
ethers.utils.solidityKeccak256(["uint256"], [1])
);
// myBytes.length
const myBytesLength = await provider.getStorageAt(MY_CONTRACT_ADDR, 1);
// myBytes[0]
const myBytes0 = await provider.getStorageAt(MY_CONTRACT_ADDR, myBytesLoc);
// myBytes[1]
const myBytes1 = await provider.getStorageAt(
MY_CONTRACT_ADDR,
myBytesLoc.add(ONE)
);
// myStruct is located at Slot 2
// myStruct.a
const myStructA = await provider.getStorageAt(MY_CONTRACT_ADD, 2);
// myStruct.b
const myStructB = await provider.getStorageAt(
MY_CONTRACT_ADD,
3
);
};
contract C {
address public myAddr; // Slot 0
mapping(address => bool) myAddrMapping; // Slot 1
mapping(uint256 => address) myUintMapping; // Slot 2
}
const ethers = require("ethers");
const provider = new ethers.providers.JsonRpcProvider();
const ONE = ethers.constants.One;
const MY_CONTRACT_ADDR = "0x0....";
const main = async () => {
const myAddr = await provider.getStorageAt(MY_CONTRACT_ADDR, 0);
const dai = "0x6b175474e89094c44da98b954eedeac495271d0f";
const usdc = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48";
// myAddrMapping is located at Slot 1
// myAddrMapping[dai]
// Note it has to be uint256 as its padded
const myAddrMappingDaiLoc = ethers.utils.solidityKeccak256(
["uint256", "uint256"],
[dai, 1] // key, slot
);
// myAddrMapping[usdc]
// Note it has to be uint256 as its padded
const myAddrMappingUsdcLoc = ethers.utils.solidityKeccak256(
["uint256", "uint256"],
[usdc, 1] // key, slot
);
// myUintMapping is located at Slot 2
// myUintMapping[1]
const myUintMappingOneLoc = ethers.utils.solidityKeccak256(
["uint256", "uint256"],
[1, 2] // key, slot
);
// myUintMapping[100]
const myUintMappingOneHundredLoc = ethers.utils.solidityKeccak256(
["uint256", "uint256"],
[100, 2] // key, slot
);
};