SlotDerivation.sol 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts (last updated v5.3.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. * _Available since v5.1._
  38. */
  39. library SlotDerivation {
  40. /**
  41. * @dev Derive an ERC-7201 slot from a string (namespace).
  42. */
  43. function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) {
  44. assembly ("memory-safe") {
  45. mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1))
  46. slot := and(keccak256(0x00, 0x20), not(0xff))
  47. }
  48. }
  49. /**
  50. * @dev Add an offset to a slot to get the n-th element of a structure or an array.
  51. */
  52. function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) {
  53. unchecked {
  54. return bytes32(uint256(slot) + pos);
  55. }
  56. }
  57. /**
  58. * @dev Derive the location of the first element in an array from the slot where the length is stored.
  59. */
  60. function deriveArray(bytes32 slot) internal pure returns (bytes32 result) {
  61. assembly ("memory-safe") {
  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. assembly ("memory-safe") {
  71. mstore(0x00, and(key, shr(96, not(0))))
  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. assembly ("memory-safe") {
  81. mstore(0x00, iszero(iszero(key)))
  82. mstore(0x20, slot)
  83. result := keccak256(0x00, 0x40)
  84. }
  85. }
  86. /**
  87. * @dev Derive the location of a mapping element from the key.
  88. */
  89. function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) {
  90. assembly ("memory-safe") {
  91. mstore(0x00, key)
  92. mstore(0x20, slot)
  93. result := keccak256(0x00, 0x40)
  94. }
  95. }
  96. /**
  97. * @dev Derive the location of a mapping element from the key.
  98. */
  99. function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) {
  100. assembly ("memory-safe") {
  101. mstore(0x00, key)
  102. mstore(0x20, slot)
  103. result := keccak256(0x00, 0x40)
  104. }
  105. }
  106. /**
  107. * @dev Derive the location of a mapping element from the key.
  108. */
  109. function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) {
  110. assembly ("memory-safe") {
  111. mstore(0x00, key)
  112. mstore(0x20, slot)
  113. result := keccak256(0x00, 0x40)
  114. }
  115. }
  116. /**
  117. * @dev Derive the location of a mapping element from the key.
  118. */
  119. function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) {
  120. assembly ("memory-safe") {
  121. let length := mload(key)
  122. let begin := add(key, 0x20)
  123. let end := add(begin, length)
  124. let cache := mload(end)
  125. mstore(end, slot)
  126. result := keccak256(begin, add(length, 0x20))
  127. mstore(end, cache)
  128. }
  129. }
  130. /**
  131. * @dev Derive the location of a mapping element from the key.
  132. */
  133. function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) {
  134. assembly ("memory-safe") {
  135. let length := mload(key)
  136. let begin := add(key, 0x20)
  137. let end := add(begin, length)
  138. let cache := mload(end)
  139. mstore(end, slot)
  140. result := keccak256(begin, add(length, 0x20))
  141. mstore(end, cache)
  142. }
  143. }
  144. }