SlotDerivation.sol 5.4 KB

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