SlotDerivation.sol 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. // SPDX-License-Identifier: MIT
  2. // This file was procedurally generated from scripts/generate/templates/SlotDerivation.js.
  3. pragma solidity ^0.8.20;
  4. /**
  5. * @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots
  6. * corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by
  7. * the solidity language / compiler.
  8. *
  9. * 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.].
  10. *
  11. * Example usage:
  12. * ```solidity
  13. * contract Example {
  14. * // Add the library methods
  15. * using StorageSlot for bytes32;
  16. * using SlotDerivation for bytes32;
  17. *
  18. * // Declare a namespace
  19. * string private constant _NAMESPACE = "<namespace>" // eg. OpenZeppelin.Slot
  20. *
  21. * function setValueInNamespace(uint256 key, address newValue) internal {
  22. * _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue;
  23. * }
  24. *
  25. * function getValueInNamespace(uint256 key) internal view returns (address) {
  26. * return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value;
  27. * }
  28. * }
  29. * ```
  30. *
  31. * TIP: Consider using this library along with {StorageSlot}.
  32. *
  33. * NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking
  34. * upgrade safety will ignore the slots accessed through this library.
  35. */
  36. library SlotDerivation {
  37. /**
  38. * @dev Derive an ERC-7201 slot from a string (namespace).
  39. */
  40. function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) {
  41. /// @solidity memory-safe-assembly
  42. assembly {
  43. mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1))
  44. slot := and(keccak256(0x00, 0x20), not(0xff))
  45. }
  46. }
  47. /**
  48. * @dev Add an offset to a slot to get the n-th element of a structure or an array.
  49. */
  50. function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) {
  51. unchecked {
  52. return bytes32(uint256(slot) + pos);
  53. }
  54. }
  55. /**
  56. * @dev Derive the location of the first element in an array from the slot where the length is stored.
  57. */
  58. function deriveArray(bytes32 slot) internal pure returns (bytes32 result) {
  59. /// @solidity memory-safe-assembly
  60. assembly {
  61. mstore(0x00, slot)
  62. result := keccak256(0x00, 0x20)
  63. }
  64. }
  65. /**
  66. * @dev Derive the location of a mapping element from the key.
  67. */
  68. function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) {
  69. /// @solidity memory-safe-assembly
  70. assembly {
  71. mstore(0x00, key)
  72. mstore(0x20, slot)
  73. result := keccak256(0x00, 0x40)
  74. }
  75. }
  76. /**
  77. * @dev Derive the location of a mapping element from the key.
  78. */
  79. function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) {
  80. /// @solidity memory-safe-assembly
  81. assembly {
  82. mstore(0x00, key)
  83. mstore(0x20, slot)
  84. result := keccak256(0x00, 0x40)
  85. }
  86. }
  87. /**
  88. * @dev Derive the location of a mapping element from the key.
  89. */
  90. function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) {
  91. /// @solidity memory-safe-assembly
  92. assembly {
  93. mstore(0x00, key)
  94. mstore(0x20, slot)
  95. result := keccak256(0x00, 0x40)
  96. }
  97. }
  98. /**
  99. * @dev Derive the location of a mapping element from the key.
  100. */
  101. function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) {
  102. /// @solidity memory-safe-assembly
  103. assembly {
  104. mstore(0x00, key)
  105. mstore(0x20, slot)
  106. result := keccak256(0x00, 0x40)
  107. }
  108. }
  109. /**
  110. * @dev Derive the location of a mapping element from the key.
  111. */
  112. function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) {
  113. /// @solidity memory-safe-assembly
  114. assembly {
  115. mstore(0x00, key)
  116. mstore(0x20, slot)
  117. result := keccak256(0x00, 0x40)
  118. }
  119. }
  120. /**
  121. * @dev Derive the location of a mapping element from the key.
  122. */
  123. function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) {
  124. /// @solidity memory-safe-assembly
  125. assembly {
  126. let length := mload(key)
  127. let begin := add(key, 0x20)
  128. let end := add(begin, length)
  129. let cache := mload(end)
  130. mstore(end, slot)
  131. result := keccak256(begin, add(length, 0x20))
  132. mstore(end, cache)
  133. }
  134. }
  135. /**
  136. * @dev Derive the location of a mapping element from the key.
  137. */
  138. function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) {
  139. /// @solidity memory-safe-assembly
  140. assembly {
  141. let length := mload(key)
  142. let begin := add(key, 0x20)
  143. let end := add(begin, length)
  144. let cache := mload(end)
  145. mstore(end, slot)
  146. result := keccak256(begin, add(length, 0x20))
  147. mstore(end, cache)
  148. }
  149. }
  150. }