Example of solidity with explicit storage slots
nvm use
npm install
npm run lint
npm run test
npm run coverage
npm run format
Storage slot specification allows specifying the underlying storage slot for Solidity state variables, which makes upgrading contracts less error-prone.
As an example, a contract like:
contract StorageSlotExample {
uint256 public storage[0x1234] a;
}
Will create a contract where the first storage element is mapped to storage slot 0x1234 instead of storage slot 0. This allows a future version of the contract to add or remove state variables without changing the on-chain storage layout. An alternate (and likely recommended) syntax is
contract StorageSlotExample {
uint256 public storage["io.beam.storageslot.a"] a;
}
This will use map element a
to storage slot
keccak256('io.beam.storageslot.a')
.
This is a small, working example with unit tests, linter, prettier and code coverage. Code generation incudes sanity checks (overlapping slots etc), and the linter includes rules to encourage storage specification consistency.
The syntax for the storage slot specification has been neither finalized nor discussed. As such, this example should be taken only as a suggested starting point for discussion and a feasibility study of integrating the new syntax in toolchains.
This includes patched and working versions of:
List is shown in practical dependency order, which will drive the order of PRs.
Should it be possible to specify the bit offset as well as storage offset? When not specifying storage slots, a contract like
constract PackedExample {
uint128 public a;
uint128 public b;
}
will store both elements in storage slot 0
, with element b at a
128-bit offset. It is feasible to do the same with a slot specification,
potentially something like uint128 public storage[0:128] b
. The only
known use-case is when retroactively adding storage slot specifiers to an
already-deployed contract that uses less-than-256bit types. Is that
sufficient motivation to add this extended syntax now?
Numerical slots are very practical when adding specifications to a new revision of a contract that already has storage deployed. However, it doesn't feel like a good practice to use it in new contracts.
Our current recommendation for this is to allow it in the compiler, but make it a default error-level complaint in the linters. Thus, it becomes something the user has to explicitly (and hopefully counciously) allow.