|
@@ -0,0 +1,161 @@
|
|
|
+// SPDX-License-Identifier: MIT
|
|
|
+// This file was procedurally generated from scripts/generate/templates/SlotDerivation.js.
|
|
|
+
|
|
|
+pragma solidity ^0.8.20;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots
|
|
|
+ * corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by
|
|
|
+ * the solidity language / compiler.
|
|
|
+ *
|
|
|
+ * See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.].
|
|
|
+ *
|
|
|
+ * Example usage:
|
|
|
+ * ```solidity
|
|
|
+ * contract Example {
|
|
|
+ * // Add the library methods
|
|
|
+ * using StorageSlot for bytes32;
|
|
|
+ * using SlotDerivation for bytes32;
|
|
|
+ *
|
|
|
+ * // Declare a namespace
|
|
|
+ * string private constant _NAMESPACE = "<namespace>" // eg. OpenZeppelin.Slot
|
|
|
+ *
|
|
|
+ * function setValueInNamespace(uint256 key, address newValue) internal {
|
|
|
+ * _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue;
|
|
|
+ * }
|
|
|
+ *
|
|
|
+ * function getValueInNamespace(uint256 key) internal view returns (address) {
|
|
|
+ * return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value;
|
|
|
+ * }
|
|
|
+ * }
|
|
|
+ * ```
|
|
|
+ *
|
|
|
+ * TIP: Consider using this library along with {StorageSlot}.
|
|
|
+ *
|
|
|
+ * NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking
|
|
|
+ * upgrade safety will ignore the slots accessed through this library.
|
|
|
+ */
|
|
|
+library SlotDerivation {
|
|
|
+ /**
|
|
|
+ * @dev Derive an ERC-7201 slot from a string (namespace).
|
|
|
+ */
|
|
|
+ function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) {
|
|
|
+ /// @solidity memory-safe-assembly
|
|
|
+ assembly {
|
|
|
+ mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1))
|
|
|
+ slot := and(keccak256(0x00, 0x20), not(0xff))
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @dev Add an offset to a slot to get the n-th element of a structure or an array.
|
|
|
+ */
|
|
|
+ function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) {
|
|
|
+ unchecked {
|
|
|
+ return bytes32(uint256(slot) + pos);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @dev Derive the location of the first element in an array from the slot where the length is stored.
|
|
|
+ */
|
|
|
+ function deriveArray(bytes32 slot) internal pure returns (bytes32 result) {
|
|
|
+ /// @solidity memory-safe-assembly
|
|
|
+ assembly {
|
|
|
+ mstore(0x00, slot)
|
|
|
+ result := keccak256(0x00, 0x20)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @dev Derive the location of a mapping element from the key.
|
|
|
+ */
|
|
|
+ function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) {
|
|
|
+ /// @solidity memory-safe-assembly
|
|
|
+ assembly {
|
|
|
+ mstore(0x00, key)
|
|
|
+ mstore(0x20, slot)
|
|
|
+ result := keccak256(0x00, 0x40)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @dev Derive the location of a mapping element from the key.
|
|
|
+ */
|
|
|
+ function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) {
|
|
|
+ /// @solidity memory-safe-assembly
|
|
|
+ assembly {
|
|
|
+ mstore(0x00, key)
|
|
|
+ mstore(0x20, slot)
|
|
|
+ result := keccak256(0x00, 0x40)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @dev Derive the location of a mapping element from the key.
|
|
|
+ */
|
|
|
+ function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) {
|
|
|
+ /// @solidity memory-safe-assembly
|
|
|
+ assembly {
|
|
|
+ mstore(0x00, key)
|
|
|
+ mstore(0x20, slot)
|
|
|
+ result := keccak256(0x00, 0x40)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @dev Derive the location of a mapping element from the key.
|
|
|
+ */
|
|
|
+ function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) {
|
|
|
+ /// @solidity memory-safe-assembly
|
|
|
+ assembly {
|
|
|
+ mstore(0x00, key)
|
|
|
+ mstore(0x20, slot)
|
|
|
+ result := keccak256(0x00, 0x40)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @dev Derive the location of a mapping element from the key.
|
|
|
+ */
|
|
|
+ function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) {
|
|
|
+ /// @solidity memory-safe-assembly
|
|
|
+ assembly {
|
|
|
+ mstore(0x00, key)
|
|
|
+ mstore(0x20, slot)
|
|
|
+ result := keccak256(0x00, 0x40)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @dev Derive the location of a mapping element from the key.
|
|
|
+ */
|
|
|
+ function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) {
|
|
|
+ /// @solidity memory-safe-assembly
|
|
|
+ assembly {
|
|
|
+ let length := mload(key)
|
|
|
+ let begin := add(key, 0x20)
|
|
|
+ let end := add(begin, length)
|
|
|
+ let cache := mload(end)
|
|
|
+ mstore(end, slot)
|
|
|
+ result := keccak256(begin, add(length, 0x20))
|
|
|
+ mstore(end, cache)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @dev Derive the location of a mapping element from the key.
|
|
|
+ */
|
|
|
+ function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) {
|
|
|
+ /// @solidity memory-safe-assembly
|
|
|
+ assembly {
|
|
|
+ let length := mload(key)
|
|
|
+ let begin := add(key, 0x20)
|
|
|
+ let end := add(begin, length)
|
|
|
+ let cache := mload(end)
|
|
|
+ mstore(end, slot)
|
|
|
+ result := keccak256(begin, add(length, 0x20))
|
|
|
+ mstore(end, cache)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|