Introduction
Lets understand the smart contract storage model in Ethereum and EVM-based chains and how you can access the public and private variables of any smart contract deployed on the blockchain. We can do this by using cast storage.
Contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
contract Storage {
address public contractAddress = address(this);
bytes private BlockApex = hex"426c6f636b41706578";
uint256 public Slot = 0;
struct Passwords {
string name;
uint256 secretKey;
string password;
}
Passwords[] private passwords;
mapping (uint256 => Passwords) private destiny;
}
Contract Address (Rinkeby) : 0xfE43d853eBa639c40d071ebd046c9F61fF215ebF
Contract Link : https://rinkeby.etherscan.io/address/0xfe43d853eba639c40d071ebd046c9f61ff215ebf
Let’s start:
| - - - - - - - - - - - -Slot 0 - - - - - - - - - - - -|
address public contractAddress = address(this);
| - - - - - - - - - - - -Slot 1 - - - - - - - - - - - -|
bytes private BlockApex = hex"426c6f636b41706578";
| - - - - - - - - - - - -Slot 2 - - - - - - - - - - - -|
uint256 public Slot = 0;
| - - - - - - - -No Slot Consumed- - - - - - - -|
struct Passwords {
string name;
uint256 secretKey;
string password;
}
| - - - - - - - - - - - -Slot 3 - - - - - - - - - - - -| // size will be here
Passwords[] private passwords;
| - - - - - - - - - - - -Slot 4 - - - - - - - - - - - -|
mapping (uint256 => Passwords) private destiny;
Static Sized Variables can be simply accessed with command of cast storage
Cast storage $ContractAddress slotNumber
cast storage 0xfE43d853eBa639c40d071ebd046c9F61fF215ebF 0
Similarly for the storage slot 1
cast storage 0xfE43d853eBa639c40d071ebd046c9F61fF215ebF 1
This command will lead you to the data stored in memory slots. .
The data you receive might be in hex, to make it meaningful try using (cast —to-ascii (hex))
Eg:
cast storage 0xfE43d853eBa639c40d071ebd046c9F61fF215ebF 1
Result: 0x426c6f636b417065780000000000000000000000000000000000000000000012
cast –to-ascii 0x426c6f636b417065780000000000000000000000000000000000000000000012
Result: BlockApex
Accessing mapping data in solidity is a little bit complex. First you identify the slot where your mapping currently stands. In our case, the mapping is on the 4th slot. Another important thing to note is since mappings are hashTables they are only accessed by keys so you need to pass [key + StorageSlot] to the keccak hashing function in order to retrieve the data.
Eg:
cast keccak (key + storageSlot)
cast keccak “0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004
This command will give you the respective hash which is actually the slot of the first element stored in mapping. To access the 2nd element increment in the key like:
Eg:
cast keccak (key++ + storageSlot)
cast keccak “0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000004
It will give you the hash slot of the 2nd item of the mapping, if you iterate through you can access all the items.
Now send this hash (result of keccak) to the cast command as follows
Eg:
cast storage $contractAddress hash
cast storage 0xfE43d853eBa639c40d071ebd046c9F61fF215ebF 0xabd6e7cb50984ff9c2f3e18a2660c3353dadf4e3291deeb275dae2cd1e44fe05
This command leads you to the 1st property of the struct that is saved in the mapping and further on as you increment in the key.
Now the problem is if your mapping contains a struct, you only get the 1st element of the struct which is the string property [name] in our case.
Eg:
struct Passwords {
string name;
uint256 secretKey;
string password;
}
To iterate further in the same struct, you need to increment one in your keccak hash, for instance if you get a hash like
0xabd6e7cb50984ff9c2f3e18a2660c3353dadf4e3291deeb275dae2cd1e44fe05+1 (add 1)
the next element is held in
0xabd6e7cb50984ff9c2f3e18a2660c3353dadf4e3291deeb275dae2cd1e44fe06
Now we send this updated hash to the cast command like
Eg:
cast storage $contractAddress hash
cast storage 0xfE43d853eBa639c40d071ebd046c9F61fF215ebF 0xabd6e7cb50984ff9c2f3e18a2660c3353dadf4e3291deeb275dae2cd1e44fe06
This leads you to the second element of the struct which is the secretKey.
Further add 1 again in the hash.
0xabd6e7cb50984ff9c2f3e18a2660c3353dadf4e3291deeb275dae2cd1e44fe06+1
the next element is held in 0xabd6e7cb50984ff9c2f3e18a2660c3353dadf4e3291deeb275dae2cd1e44fe07
Again hit the contract with the updated hash and you will get the password which is the last element of the struct stored in mapping!
Congrats you have unveiled the mystery of Solidity internals!
PS: cast can come handy only if you want.
Also read :
Liquidity Challenges In Illiquid Marketplaces.