Created
September 13, 2022 09:51
-
-
Save 0xGorilla/70b3d4bda1eece336119b66f708f255e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity >=0.8.4 <0.9.0; | |
library StorageAddress { | |
/// @notice compute the storage address of any element of a dynamic array, by its index | |
/// @dev Primitive type agnostic. Elements are supposedly taking one word in storage | |
/// (for other length, you'd have to split/concat them accordingly). | |
/// Main use is in conjunction with hevm.store, as the second parameter | |
/// hevm.store(myContract, offset, valueToWrite) | |
/// @param slot the storage slot where the array is in the contract | |
/// @param index the index in the array | |
/// @return elementAddress the address in storage of myArray[index] | |
function getArrayOffset(uint256 slot, uint256 index) internal pure returns (bytes32 elementAddress) { | |
assembly { | |
mstore(0x0, slot) | |
elementAddress := add(keccak256(0x0, 32), index) | |
} | |
} | |
/// @notice compute the storage address of a 2 levels nested mapping myMapping[levelOne][levelTwo] | |
/// @dev primitive type agnostic, limited only by the current overloads | |
/// (ie currently supports uint=>uint=>x, address=>uint=>x, uint=>address, address=>address) | |
/// Main use is to use it in conjunction with hevm.store, as the second parameter | |
/// hevm.store(myContract, offset, valueToWrite). | |
/// This can be easily extended by adding "layers" of mstore/keccak as needed. | |
/// @param levelOne the first key of the mapping | |
/// @param levelTwo the second key of the mapping | |
/// @param slot the storage slot where the mapping is in the contract | |
/// @return offset the address in storage of myMapping[levelOne][levelTwo] | |
function offsetNested( | |
address levelOne, | |
address levelTwo, | |
uint256 slot | |
) internal pure returns (bytes32 offset) { | |
return offsetNested(addressToBytes32(levelOne), addressToBytes32(levelTwo), slot); | |
} | |
function offsetNested( | |
uint256 levelOne, | |
address levelTwo, | |
uint256 slot | |
) internal pure returns (bytes32 offset) { | |
return offsetNested(bytes32(levelOne), addressToBytes32(levelTwo), slot); | |
} | |
function offsetNested( | |
address levelOne, | |
uint256 levelTwo, | |
uint256 slot | |
) internal pure returns (bytes32 offset) { | |
return offsetNested(addressToBytes32(levelOne), bytes32(levelTwo), slot); | |
} | |
function offsetNested( | |
uint256 levelOne, | |
uint256 levelTwo, | |
uint256 slot | |
) internal pure returns (bytes32 offset) { | |
return offsetNested(bytes32(levelOne), bytes32(levelTwo), slot); | |
} | |
// ----- private ----- | |
function addressToBytes32(address addressIn) private pure returns (bytes32 converted) { | |
assembly { | |
mstore(0x0, addressIn) | |
converted := mload(0x0) | |
} | |
} | |
function offsetNested( | |
bytes32 levelOne, | |
bytes32 levelTwo, | |
uint256 slot | |
) private pure returns (bytes32 offset) { | |
assembly { | |
mstore(0x0, levelOne) | |
mstore(0x20, slot) | |
let hash_first_level := keccak256(0x0, 64) | |
mstore(0x0, levelTwo) | |
mstore(0x20, hash_first_level) | |
offset := keccak256(0x0, 64) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment