@artblocks/contracts 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/README.md +67 -154
  2. package/artifacts/contracts/AdminACLV0.sol/AdminACLV0.json +2 -2
  3. package/artifacts/contracts/AdminACLV1.sol/AdminACLV1.json +2 -2
  4. package/artifacts/contracts/DependencyRegistryV0.sol/DependencyRegistryV0.json +22 -4
  5. package/artifacts/contracts/GenArt721CoreV3.sol/GenArt721CoreV3.json +42 -5
  6. package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExp/MinterDAExpV2.sol/MinterDAExpV2.json +2 -2
  7. package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExp/MinterDAExpV3.sol/MinterDAExpV3.json +2 -2
  8. package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExpSettlement/MinterDAExpSettlementV0.sol/MinterDAExpSettlementV0.json +2 -2
  9. package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExpSettlement/MinterDAExpSettlementV1.sol/MinterDAExpSettlementV1.json +2 -2
  10. package/artifacts/contracts/archive/minter-suite/Minters/MinterDALin/MinterDALinV2.sol/MinterDALinV2.json +2 -2
  11. package/artifacts/contracts/archive/minter-suite/Minters/MinterDALin/MinterDALinV3.sol/MinterDALinV3.json +2 -2
  12. package/artifacts/contracts/archive/minter-suite/Minters/MinterHolder/MinterHolderV1.sol/MinterHolderV1.json +2 -2
  13. package/artifacts/contracts/archive/minter-suite/Minters/MinterHolder/MinterHolderV2.sol/MinterHolderV2.json +2 -2
  14. package/artifacts/contracts/archive/minter-suite/Minters/MinterHolder/MinterHolderV3.sol/MinterHolderV3.json +2 -2
  15. package/artifacts/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV1.sol/MinterMerkleV1.json +2 -2
  16. package/artifacts/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV2.sol/MinterMerkleV2.json +2 -2
  17. package/artifacts/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV3.sol/MinterMerkleV3.json +2 -2
  18. package/artifacts/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV4.sol/MinterMerkleV4.json +2 -2
  19. package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPrice/MinterSetPriceV2.sol/MinterSetPriceV2.json +2 -2
  20. package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPrice/MinterSetPriceV3.sol/MinterSetPriceV3.json +2 -2
  21. package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPriceERC20/MinterSetPriceERC20V2.sol/MinterSetPriceERC20V2.json +2 -2
  22. package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPriceERC20/MinterSetPriceERC20V3.sol/MinterSetPriceERC20V3.json +2 -2
  23. package/artifacts/contracts/engine/{GenArt721CoreV2_ENGINE_FLEX.sol → V2/GenArt721CoreV2_ENGINE_FLEX.sol}/GenArt721CoreV2_ENGINE_FLEX.json +3 -3
  24. package/artifacts/contracts/engine/{GenArt721CoreV2_PBAB.sol → V2/GenArt721CoreV2_PBAB.sol}/GenArt721CoreV2_PBAB.json +3 -3
  25. package/artifacts/contracts/engine/{GenArt721CoreV2_PRTNR.sol → V2/GenArt721CoreV2_PRTNR.sol}/GenArt721CoreV2_PRTNR.json +3 -3
  26. package/artifacts/contracts/engine/{GenArt721MinterBurner_PBAB.sol → V2/GenArt721MinterBurner_PBAB.sol}/GenArt721MinterBurner_PBAB.json +3 -3
  27. package/artifacts/contracts/engine/{GenArt721MinterDAExp_PBAB.sol → V2/GenArt721MinterDAExp_PBAB.sol}/GenArt721MinterDAExp_PBAB.json +3 -3
  28. package/artifacts/contracts/engine/{GenArt721Minter_PBAB.sol → V2/GenArt721Minter_PBAB.sol}/GenArt721Minter_PBAB.json +3 -3
  29. package/artifacts/contracts/engine/V3/GenArt721CoreV3_Engine.sol/GenArt721CoreV3_Engine.json +1960 -0
  30. package/artifacts/contracts/engine/V3/GenArt721CoreV3_Engine_Flex.sol/GenArt721CoreV3_Engine_Flex.json +2247 -0
  31. package/artifacts/contracts/engine/V3/forks/GenArt721CoreV3_Engine_Flex_PROOF.sol/GenArt721CoreV3_Engine_Flex_PROOF.json +2247 -0
  32. package/artifacts/contracts/engine/V3/forks/PROHIBITION/AdminACLV0_PROHIBITION.sol/AdminACLV0_PROHIBITION.json +401 -0
  33. package/artifacts/contracts/engine/V3/forks/PROHIBITION/GenArt721CoreV3_Engine_Flex_PROHIBITION.sol/GenArt721CoreV3_Engine_Flex_PROHIBITION.json +2281 -0
  34. package/artifacts/contracts/engine/V3/forks/PROHIBITION/interfaces/IAdminACLV0_PROHIBITION.sol/IAdminACLV0_PROHIBITION.json +359 -0
  35. package/artifacts/contracts/engine/V3/forks/PROHIBITION/interfaces/IGenArt721CoreContractV3_Engine_Flex_PROHIBITION.sol/IGenArt721CoreContractV3_Engine_Flex_PROHIBITION.json +1094 -0
  36. package/artifacts/contracts/engine-registry/CoreRegistryV1.sol/CoreRegistryV1.json +242 -0
  37. package/artifacts/contracts/engine-registry/EngineRegistryV0.sol/EngineRegistryV0.json +2 -2
  38. package/artifacts/contracts/explorations/GenArt721CoreV3_Explorations.sol/GenArt721CoreV3_Explorations.json +41 -4
  39. package/artifacts/contracts/interfaces/0.8.x/IBytecodeStorageReader.sol/IBytecodeStorageReader.json +111 -0
  40. package/artifacts/contracts/interfaces/0.8.x/ICoreRegistryV1.sol/ICoreRegistryV1.json +172 -0
  41. package/artifacts/contracts/interfaces/0.8.x/IFilteredMinterSEAV0.sol/IFilteredMinterSEAV0.json +1034 -0
  42. package/artifacts/contracts/interfaces/0.8.x/IGenArt721CoreContractExposesHashSeed.sol/IGenArt721CoreContractExposesHashSeed.json +30 -0
  43. package/artifacts/contracts/interfaces/0.8.x/IGenArt721CoreContractV3.sol/IGenArt721CoreContractV3.json +162 -0
  44. package/artifacts/contracts/interfaces/0.8.x/IGenArt721CoreContractV3_Base.sol/IGenArt721CoreContractV3_Base.json +162 -0
  45. package/artifacts/contracts/interfaces/0.8.x/IGenArt721CoreContractV3_Engine.sol/IGenArt721CoreContractV3_Engine.json +137 -13
  46. package/artifacts/contracts/interfaces/0.8.x/IGenArt721CoreContractV3_Engine_Flex.sol/IGenArt721CoreContractV3_Engine_Flex.json +1060 -0
  47. package/artifacts/contracts/interfaces/0.8.x/IMinterFilterV1.sol/IMinterFilterV1.json +429 -0
  48. package/artifacts/contracts/interfaces/0.8.x/IPseudorandomAtomic.sol/IPseudorandomAtomic.json +30 -0
  49. package/artifacts/contracts/interfaces/0.8.x/IRandomizer_V3CoreBase.sol/IRandomizer_V3CoreBase.json +24 -0
  50. package/artifacts/contracts/interfaces/0.8.x/ISharedRandomizerV0.sol/ISharedRandomizerV0.json +207 -0
  51. package/artifacts/contracts/interfaces/0.8.x/IWETH.sol/IWETH.json +55 -0
  52. package/artifacts/contracts/libs/0.8.x/{BytecodeStorage.sol → BytecodeStorageV0.sol}/BytecodeStorage.json +3 -3
  53. package/artifacts/contracts/libs/0.8.x/BytecodeStorageV1.sol/BytecodeStorageReader.json +163 -0
  54. package/artifacts/contracts/libs/0.8.x/BytecodeStorageV1.sol/BytecodeStorageWriter.json +10 -0
  55. package/artifacts/contracts/libs/0.8.x/Bytes32Strings.sol/Bytes32Strings.json +2 -2
  56. package/artifacts/contracts/libs/0.8.x/ERC721_PackedHashSeed.sol/ERC721_PackedHashSeed.json +2 -2
  57. package/artifacts/contracts/libs/0.8.x/SSTORE2.sol/SSTORE2.json +10 -0
  58. package/artifacts/contracts/libs/integration-refs/delegation-registry/DelegationRegistry.sol/DelegationRegistry.json +2 -2
  59. package/artifacts/contracts/libs/integration-refs/gnosis-safe/GnosisSafeMock.sol/GnosisSafeMock.json +2 -2
  60. package/artifacts/contracts/libs/integration-refs/gnosis-safe/GnosisSafeProxyFactoryMock.sol/GnosisSafeProxyFactoryMock.json +2 -2
  61. package/artifacts/contracts/libs/integration-refs/gnosis-safe/MultiSendMock.sol/MultiSendMock.json +2 -2
  62. package/artifacts/contracts/libs/integration-refs/weth9/weth9.sol/WETH9_.json +295 -0
  63. package/artifacts/contracts/minter-suite/MinterFilter/MinterFilterV1.sol/MinterFilterV1.json +2 -2
  64. package/artifacts/contracts/minter-suite/MinterFilter/MinterFilterV2.sol/MinterFilterV2.json +692 -0
  65. package/artifacts/contracts/minter-suite/Minters/MinterDAExpSettlementV2.sol/MinterDAExpSettlementV2.json +2 -2
  66. package/artifacts/contracts/minter-suite/Minters/MinterDAExpV4.sol/MinterDAExpV4.json +2 -2
  67. package/artifacts/contracts/minter-suite/Minters/MinterDALinV4.sol/MinterDALinV4.json +2 -2
  68. package/artifacts/contracts/minter-suite/Minters/MinterHolderV4.sol/MinterHolderV4.json +2 -2
  69. package/artifacts/contracts/minter-suite/Minters/MinterMerkleV5.sol/MinterMerkleV5.json +2 -2
  70. package/artifacts/contracts/minter-suite/Minters/MinterPolyptychV0.sol/IGenArt721CoreContractV3WithRandomizer.json +104 -124
  71. package/artifacts/contracts/minter-suite/Minters/MinterPolyptychV0.sol/MinterPolyptychV0.json +2 -2
  72. package/artifacts/contracts/minter-suite/Minters/MinterSEAV0.sol/MinterSEAV0.json +1289 -0
  73. package/artifacts/contracts/minter-suite/Minters/MinterSetPriceERC20V4.sol/MinterSetPriceERC20V4.json +2 -2
  74. package/artifacts/contracts/minter-suite/Minters/MinterSetPriceV4.sol/MinterSetPriceV4.json +2 -2
  75. package/artifacts/contracts/mock/{BytecodeTextCR_DMock.sol/BytecodeTextCR_DMock.json → BytecodeV0TextCR_DMock.sol/BytecodeV0TextCR_DMock.json} +4 -4
  76. package/artifacts/contracts/mock/BytecodeV1LibCallsMock.sol/BytecodeV1LibCallsMock.json +135 -0
  77. package/artifacts/contracts/mock/BytecodeV1TextCR_DMock.sol/BytecodeV1TextCR_DMock.json +301 -0
  78. package/artifacts/contracts/mock/DeadReceiverBidderMock.sol/DeadReceiverBidderMock.json +33 -0
  79. package/artifacts/contracts/mock/DeadReceiverMock.sol/DeadReceiverMock.json +2 -2
  80. package/artifacts/contracts/mock/DummySharedMinter.sol/DummySharedMinter.json +114 -0
  81. package/artifacts/contracts/mock/ERC20Mock.sol/ERC20Mock.json +2 -2
  82. package/artifacts/contracts/mock/GasLimitReceiverBidderMock.sol/GasLimitReceiverBidderMock.json +46 -0
  83. package/artifacts/contracts/mock/GasLimitReceiverMock.sol/GasLimitReceiverMock.json +28 -0
  84. package/artifacts/contracts/mock/GenArt721CoreV3_Engine_IncorrectCoreType.sol/GenArt721CoreV3_Engine_IncorrectCoreType.json +22 -4
  85. package/artifacts/contracts/mock/MockAdminACLV0.sol/MockAdminACLV0Events.json +2 -2
  86. package/artifacts/contracts/mock/MockAdminACLV0_PROHIBITION.sol/MockAdminACLV0Events_PROHIBITION.json +440 -0
  87. package/artifacts/contracts/mock/OriginRegisterMock.sol/OriginRegisterMock.json +39 -0
  88. package/artifacts/contracts/mock/RandomizerV2_NoAssignMock.sol/RandomizerV2_NoAssignMock.json +2 -2
  89. package/artifacts/contracts/mock/ReentrancyHolderMock.sol/ReentrancyHolderMock.json +2 -2
  90. package/artifacts/contracts/mock/ReentrancyMerkleMock.sol/ReentrancyMerkleMock.json +2 -2
  91. package/artifacts/contracts/mock/ReentrancyMock.sol/ReentrancyMock.json +2 -2
  92. package/artifacts/contracts/mock/ReentrancySEAMock.sol/ReentrancySEAAutoBidderMock.json +51 -0
  93. package/artifacts/contracts/mock/SSTORE2Mock.sol/SSTORE2Mock.json +118 -0
  94. package/artifacts/contracts/{BasicRandomizer.sol → randomizer/deprecated/BasicRandomizer.sol}/BasicRandomizer.json +3 -3
  95. package/artifacts/contracts/randomizer/deprecated/BasicRandomizerBase_v0_0_0.sol/RandomizerBase.json +10 -0
  96. package/artifacts/contracts/randomizer/deprecated/PolyptychRandomizerV0.sol/BasicPolyptychRandomizerV0.json +229 -0
  97. package/artifacts/contracts/randomizer/deprecated/RandomizerV2.sol/BasicRandomizerV2.json +102 -0
  98. package/artifacts/contracts/randomizer/primitive/PseudorandomAtomicBasic.sol/PseudorandomAtomic.json +30 -0
  99. package/artifacts/contracts/randomizer/shared/SharedRandomizerV0.sol/SharedRandomizerV0.json +231 -0
  100. package/artifacts/contracts/royalty-registry/GenArt721RoyaltyOverride.sol/GenArt721RoyaltyOverride.json +2 -2
  101. package/contracts/AdminACLV0.sol +1 -1
  102. package/contracts/AdminACLV1.sol +1 -1
  103. package/contracts/DependencyRegistryV0.sol +89 -141
  104. package/contracts/GenArt721CoreV3.sol +160 -204
  105. package/contracts/archive/minter-suite/Minters/MinterDAExp/MinterDAExpV2.sol +1 -1
  106. package/contracts/archive/minter-suite/Minters/MinterDAExp/MinterDAExpV3.sol +1 -1
  107. package/contracts/archive/minter-suite/Minters/MinterDAExpSettlement/MinterDAExpSettlementV0.sol +1 -1
  108. package/contracts/archive/minter-suite/Minters/MinterDAExpSettlement/MinterDAExpSettlementV1.sol +1 -1
  109. package/contracts/archive/minter-suite/Minters/MinterDALin/MinterDALinV2.sol +1 -1
  110. package/contracts/archive/minter-suite/Minters/MinterDALin/MinterDALinV3.sol +1 -1
  111. package/contracts/archive/minter-suite/Minters/MinterHolder/MinterHolderV1.sol +1 -1
  112. package/contracts/archive/minter-suite/Minters/MinterHolder/MinterHolderV2.sol +1 -1
  113. package/contracts/archive/minter-suite/Minters/MinterHolder/MinterHolderV3.sol +1 -1
  114. package/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV1.sol +1 -1
  115. package/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV2.sol +1 -1
  116. package/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV3.sol +1 -1
  117. package/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV4.sol +1 -1
  118. package/contracts/archive/minter-suite/Minters/MinterSetPrice/MinterSetPriceV2.sol +1 -1
  119. package/contracts/archive/minter-suite/Minters/MinterSetPrice/MinterSetPriceV3.sol +1 -1
  120. package/contracts/archive/minter-suite/Minters/MinterSetPriceERC20/MinterSetPriceERC20V2.sol +1 -1
  121. package/contracts/archive/minter-suite/Minters/MinterSetPriceERC20/MinterSetPriceERC20V3.sol +1 -1
  122. package/contracts/engine/{GenArt721CoreV2_ENGINE_FLEX.sol → V2/GenArt721CoreV2_ENGINE_FLEX.sol} +2 -2
  123. package/contracts/engine/{GenArt721CoreV2_PBAB.sol → V2/GenArt721CoreV2_PBAB.sol} +2 -2
  124. package/contracts/engine/{GenArt721CoreV2_PRTNR.sol → V2/GenArt721CoreV2_PRTNR.sol} +3 -3
  125. package/contracts/engine/{GenArt721MinterBurner_PBAB.sol → V2/GenArt721MinterBurner_PBAB.sol} +2 -2
  126. package/contracts/engine/{GenArt721MinterDAExp_PBAB.sol → V2/GenArt721MinterDAExp_PBAB.sol} +2 -2
  127. package/contracts/engine/{GenArt721Minter_PBAB.sol → V2/GenArt721Minter_PBAB.sol} +2 -2
  128. package/contracts/{GenArt721CoreV3_Engine.sol → engine/V3/GenArt721CoreV3_Engine.sol} +163 -216
  129. package/contracts/engine/V3/GenArt721CoreV3_Engine_Flex.sol +2283 -0
  130. package/contracts/engine/V3/forks/GenArt721CoreV3_Engine_Flex_PROOF.sol +2293 -0
  131. package/contracts/engine/V3/forks/PROHIBITION/AdminACLV0_PROHIBITION.sol +281 -0
  132. package/contracts/engine/V3/forks/PROHIBITION/GenArt721CoreV3_Engine_Flex_PROHIBITION.sol +2354 -0
  133. package/contracts/engine/V3/forks/PROHIBITION/interfaces/IAdminACLV0_PROHIBITION.sol +123 -0
  134. package/contracts/engine/V3/forks/PROHIBITION/interfaces/IGenArt721CoreContractV3_Engine_Flex_PROHIBITION.sol +29 -0
  135. package/contracts/engine-registry/CoreRegistryV1.sol +254 -0
  136. package/contracts/engine-registry/EngineRegistryV0.sol +1 -1
  137. package/contracts/explorations/GenArt721CoreV3_Explorations.sol +164 -190
  138. package/contracts/interfaces/0.8.x/IBytecodeStorageReader.sol +62 -0
  139. package/contracts/interfaces/0.8.x/ICoreRegistryV1.sol +27 -0
  140. package/contracts/interfaces/0.8.x/IDelegationRegistry.sol +1 -1
  141. package/contracts/interfaces/0.8.x/IDependencyRegistryCompatibleV0.sol +1 -1
  142. package/contracts/interfaces/0.8.x/IDependencyRegistryV0.sol +1 -1
  143. package/contracts/interfaces/0.8.x/IEngineRegistryV0.sol +1 -1
  144. package/contracts/interfaces/0.8.x/IFilteredMinterSEAV0.sol +164 -0
  145. package/contracts/interfaces/0.8.x/IGenArt721CoreContractExposesHashSeed.sol +11 -0
  146. package/contracts/interfaces/0.8.x/IGenArt721CoreContractV3_Base.sol +42 -0
  147. package/contracts/interfaces/0.8.x/IGenArt721CoreContractV3_Engine.sol +0 -8
  148. package/contracts/interfaces/0.8.x/IGenArt721CoreContractV3_Engine_Flex.sol +132 -0
  149. package/contracts/interfaces/0.8.x/IMinterFilterV1.sol +158 -0
  150. package/contracts/interfaces/0.8.x/IPseudorandomAtomic.sol +16 -0
  151. package/contracts/interfaces/0.8.x/IRandomizerPolyptychV0.sol +1 -1
  152. package/contracts/interfaces/0.8.x/IRandomizerV2.sol +2 -5
  153. package/contracts/interfaces/0.8.x/IRandomizer_V3CoreBase.sol +10 -0
  154. package/contracts/interfaces/0.8.x/ISharedRandomizerV0.sol +105 -0
  155. package/contracts/interfaces/0.8.x/IWETH.sol +11 -0
  156. package/contracts/libs/0.8.x/BytecodeStorageV1.sol +399 -0
  157. package/contracts/libs/0.8.x/SSTORE2.sol +109 -0
  158. package/contracts/libs/integration-refs/delegation-registry/DelegationRegistry.sol +1 -1
  159. package/contracts/libs/integration-refs/weth9/weth9.sol +765 -0
  160. package/contracts/minter-suite/MinterFilter/MinterFilterV1.sol +36 -48
  161. package/contracts/minter-suite/MinterFilter/MinterFilterV2.sol +756 -0
  162. package/contracts/minter-suite/Minters/MinterDAExpSettlementV2.sol +27 -35
  163. package/contracts/minter-suite/Minters/MinterDAExpV4.sol +17 -22
  164. package/contracts/minter-suite/Minters/MinterDALinV4.sol +16 -18
  165. package/contracts/minter-suite/Minters/MinterHolderV4.sol +20 -20
  166. package/contracts/minter-suite/Minters/MinterMerkleV5.sol +14 -16
  167. package/contracts/minter-suite/Minters/MinterPolyptychV0.sol +37 -36
  168. package/contracts/minter-suite/Minters/MinterSEAV0.sol +1273 -0
  169. package/contracts/minter-suite/Minters/MinterSetPriceERC20V4.sol +12 -12
  170. package/contracts/minter-suite/Minters/MinterSetPriceV4.sol +10 -11
  171. package/contracts/mock/{BytecodeTextCR_DMock.sol → BytecodeV0TextCR_DMock.sol} +5 -5
  172. package/contracts/mock/BytecodeV1LibCallsMock.sol +114 -0
  173. package/contracts/mock/BytecodeV1TextCR_DMock.sol +233 -0
  174. package/contracts/mock/DeadReceiverBidderMock.sol +23 -0
  175. package/contracts/mock/DeadReceiverMock.sol +1 -1
  176. package/contracts/mock/DummySharedMinter.sol +75 -0
  177. package/contracts/mock/GasLimitReceiverBidderMock.sol +23 -0
  178. package/contracts/mock/GasLimitReceiverMock.sol +19 -0
  179. package/contracts/mock/GenArt721CoreV3_Engine_IncorrectCoreType.sol +14 -27
  180. package/contracts/mock/MockAdminACLV0.sol +1 -1
  181. package/contracts/mock/MockAdminACLV0_PROHIBITION.sol +207 -0
  182. package/contracts/mock/OriginRegisterMock.sol +27 -0
  183. package/contracts/mock/RandomizerV2_NoAssignMock.sol +3 -12
  184. package/contracts/mock/ReentrancySEAMock.sol +36 -0
  185. package/contracts/mock/SSTORE2Mock.sol +93 -0
  186. package/contracts/{BasicRandomizer.sol → randomizer/deprecated/BasicRandomizer.sol} +1 -1
  187. package/contracts/randomizer/deprecated/BasicRandomizerBase_v0_0_0.sol +23 -0
  188. package/contracts/{BasicPolyptychRandomizerV0.sol → randomizer/deprecated/PolyptychRandomizerV0.sol} +20 -29
  189. package/contracts/{BasicRandomizerV2.sol → randomizer/deprecated/RandomizerV2.sol} +6 -14
  190. package/contracts/randomizer/primitive/PseudorandomAtomicBasic.sol +30 -0
  191. package/contracts/randomizer/shared/SharedRandomizerV0.sol +245 -0
  192. package/package.json +36 -30
  193. package/.env.example +0 -10
  194. package/artifacts/contracts/BasicPolyptychRandomizerV0.sol/BasicPolyptychRandomizerV0.json +0 -229
  195. package/artifacts/contracts/BasicRandomizerV2.sol/BasicRandomizerV2.json +0 -102
  196. package/artifacts/contracts/GenArt721CoreV3_Engine.sol/GenArt721CoreV3_Engine.json +0 -1942
  197. package/artifacts/contracts/engine-registry/future/EngineRegistryV1.sol/EngineRegistryV1.json +0 -109
  198. package/contracts/engine-registry/future/EngineRegistryV1.sol +0 -86
  199. /package/contracts/libs/0.8.x/{BytecodeStorage.sol → BytecodeStorageV0.sol} +0 -0
@@ -0,0 +1,1273 @@
1
+ // SPDX-License-Identifier: LGPL-3.0-only
2
+ // Created By: Art Blocks Inc.
3
+
4
+ pragma solidity 0.8.19;
5
+
6
+ import "../../interfaces/0.8.x/IGenArt721CoreContractV3_Base.sol";
7
+ import "../../interfaces/0.8.x/IMinterFilterV0.sol";
8
+ import "../../interfaces/0.8.x/IFilteredMinterSEAV0.sol";
9
+ import "./MinterBase_v0_1_1.sol";
10
+
11
+ import "@openzeppelin-4.7/contracts/token/ERC721/IERC721.sol";
12
+ import "@openzeppelin-4.7/contracts/security/ReentrancyGuard.sol";
13
+ import "@openzeppelin-4.7/contracts/utils/math/SafeCast.sol";
14
+ import "@openzeppelin-4.7/contracts/utils/math/Math.sol";
15
+
16
+ /**
17
+ * @title Filtered Minter contract that allows tokens to be minted with ETH.
18
+ * Pricing is achieved using an automated serial English Auction mechanism.
19
+ * This is designed to be used with GenArt721CoreContractV3 flagship or
20
+ * engine contracts.
21
+ * @author Art Blocks Inc.
22
+ * @notice This contract was inspired by the release mechanism implemented by
23
+ * nouns.wtf, and we thank them for their pioneering work in this area.
24
+ /*********************************
25
+ * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
26
+ * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
27
+ * ░░░░░░█████████░░█████████░░░ *
28
+ * ░░░░░░██░░░████░░██░░░████░░░ *
29
+ * ░░██████░░░████████░░░████░░░ *
30
+ * ░░██░░██░░░████░░██░░░████░░░ *
31
+ * ░░██░░██░░░████░░██░░░████░░░ *
32
+ * ░░░░░░█████████░░█████████░░░ *
33
+ * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
34
+ * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
35
+ *********************************
36
+ * @notice Bid Front-Running:
37
+ * Collectors can front-run bids to become the highest bidder by bidding any
38
+ * amount sufficiently higher than the current highest bid, considering the
39
+ * minter-level configured value of `minterMinBidIncrementPercentage`. For
40
+ * instance, if current bid is 1 ETH, and collector A sends a transaction with
41
+ * a bid of 2.50 ETH, collector B may send a transaction with a bid of 2.499
42
+ * ETH, that if successfully front-runs Collector A's transaction, is able to
43
+ * cause collector A's transaction to revert. This is a difficult problem to
44
+ * get around in a decentralized system with public bids, and we have chosen to
45
+ * keep the minter simple and transparent, and leave it up to collectors to
46
+ * understand the risks of front-running and bid accordingly.
47
+ * @notice Token Ownership:
48
+ * This minter contract may own up to two tokens at a time for a given project.
49
+ * The first possible token owned is the token that is currently being
50
+ * auctioned. During the auction, the token is owned by the minter contract.
51
+ * Once the auction ends, the token is transferred to the winning bidder via a
52
+ * call to "settle" the auction.
53
+ * The second possible token owned is the token that will be auctioned next.
54
+ * This token is minted to and owned by the minter contract whenever possible
55
+ * (i.e. when the project's max invocations has not been reached) when an
56
+ * artist configures their project on this minter, or when a new auction is
57
+ * started. The purpose of this token is to allow users to have a preview of
58
+ * the next token that will be auctioned, even before the auction has started.
59
+ * @notice Privileged Roles and Ownership:
60
+ * This contract is designed to be managed, with limited powers.
61
+ * Privileged roles and abilities are controlled by the core contract's Admin
62
+ * ACL contract and a project's artist. Both of these roles hold extensive
63
+ * power and can modify minter details.
64
+ * Care must be taken to ensure that the admin ACL contract and artist
65
+ * addresses are secure behind a multi-sig or other access control mechanism.
66
+ * ----------------------------------------------------------------------------
67
+ * The following functions are restricted to the core contract's Admin ACL
68
+ * contract:
69
+ * - updateAllowableAuctionDurationSeconds
70
+ * - updateMinterMinBidIncrementPercentage
71
+ * - updateMinterTimeBufferSeconds
72
+ * - ejectNextTokenTo
73
+ * ----------------------------------------------------------------------------
74
+ * The following functions are restricted to a project's artist:
75
+ * - setProjectMaxInvocations
76
+ * - manuallyLimitProjectMaxInvocations
77
+ * - configureFutureAuctions
78
+ * - tryPopulateNextToken
79
+ * ----------------------------------------------------------------------------
80
+ * The following functions are restricted to a project's artist or the core
81
+ * contract's Admin ACL contract:
82
+ * - resetAuctionDetails
83
+ * ----------------------------------------------------------------------------
84
+ * Additional admin and artist privileged roles may be described on other
85
+ * contracts that this minter integrates with.
86
+ *
87
+ * @dev Note that while this minter makes use of `block.timestamp` and it is
88
+ * technically possible that this value is manipulated by block producers, such
89
+ * manipulation will not have material impact on the ability for collectors to
90
+ * place a bid before auction end time. This is due to the admin-configured
91
+ * `minterTimeBufferSeconds` parameter, which will used to ensure that
92
+ * collectors have sufficient time to place a bid after the final bid and
93
+ * before the auction end time.
94
+ */
95
+ contract MinterSEAV0 is ReentrancyGuard, MinterBase, IFilteredMinterSEAV0 {
96
+ using SafeCast for uint256;
97
+
98
+ /// Core contract address this minter interacts with
99
+ address public immutable genArt721CoreAddress;
100
+
101
+ /// The core contract integrates with V3 contracts
102
+ IGenArt721CoreContractV3_Base private immutable genArtCoreContract_Base;
103
+
104
+ /// Minter filter address this minter interacts with
105
+ address public immutable minterFilterAddress;
106
+
107
+ /// Minter filter this minter may interact with.
108
+ IMinterFilterV0 private immutable minterFilter;
109
+
110
+ /// minterType for this minter
111
+ string public constant minterType = "MinterSEAV0";
112
+
113
+ /// minter version for this minter
114
+ string public constant minterVersion = "v0.0.1";
115
+
116
+ uint256 constant ONE_MILLION = 1_000_000;
117
+
118
+ mapping(uint256 => ProjectConfig) public projectConfig;
119
+
120
+ // minter-wide, admin-configurable parameters
121
+ // ----------------------------------------
122
+ // minimum inital auction length, in seconds; configurable by admin
123
+ // max uint32 ~= 4.3e9 sec ~= 136 years
124
+ // @dev enforced only when artist configures a project
125
+ // @dev default to 10 minutes
126
+ uint32 minAuctionDurationSeconds = 600;
127
+ // maximum inital auction length, in seconds; configurable by admin
128
+ // @dev enforced only when artist configures a project
129
+ // @dev default to 1 month (1/12 of a year)
130
+ uint32 maxAuctionDurationSeconds = 2_629_746;
131
+ // the minimum percent increase for new bids above the current bid
132
+ // configureable by admin
133
+ // max uint8 ~= 255, > 100 percent
134
+ // @dev used when determining the increment percentage for any new bid on
135
+ // the minter, across all projects
136
+ uint8 minterMinBidIncrementPercentage = 5;
137
+ // minimum time remaining in auction after a new bid is placed
138
+ // configureable by admin
139
+ // max uint32 ~= 4.3e9 sec ~= 136 years
140
+ // @dev used when determining the buffer time for any new bid on the
141
+ // minter, across all projects
142
+ uint32 minterTimeBufferSeconds = 120;
143
+ // gas limit for refunding ETH to bidders
144
+ // configurable by admin, default to 30,000
145
+ // max uint16 = 65,535 to ensure bid refund gas limit remains reasonable
146
+ uint16 minterRefundGasLimit = 30_000;
147
+
148
+ // modifier-like internal functions
149
+ // @dev we use internal functions instead of modifiers to reduce contract
150
+ // bytecode size
151
+ // ----------------------------------------
152
+ // function to restrict access to only AdminACL allowed calls
153
+ // @dev defers to the ACL contract used on the core contract
154
+ function _onlyCoreAdminACL(bytes4 _selector) internal {
155
+ require(_adminACLAllowed(_selector), "Only Core AdminACL allowed");
156
+ }
157
+
158
+ // function to restrict access to only the artist of a project
159
+ function _onlyArtist(uint256 _projectId) internal view {
160
+ require(_senderIsArtist(_projectId), "Only Artist");
161
+ }
162
+
163
+ // function to restrict access to only the artist of a project or
164
+ // AdminACL allowed calls
165
+ // @dev defers to the ACL contract used on the core contract
166
+ function _onlyCoreAdminACLOrArtist(
167
+ uint256 _projectId,
168
+ bytes4 _selector
169
+ ) internal {
170
+ require(
171
+ _senderIsArtist(_projectId) || _adminACLAllowed(_selector),
172
+ "Only Artist or Admin ACL"
173
+ );
174
+ }
175
+
176
+ // function to require that a value is non-zero
177
+ function _onlyNonZero(uint256 _value) internal pure {
178
+ require(_value != 0, "Only non-zero");
179
+ }
180
+
181
+ /**
182
+ * @notice Initializes contract to be a Filtered Minter for
183
+ * `_minterFilter`, integrated with Art Blocks core contract
184
+ * at address `_genArt721Address`.
185
+ * @param _genArt721Address Art Blocks core contract address for
186
+ * which this contract will be a minter.
187
+ * @param _minterFilter Minter filter for which
188
+ * this will a filtered minter.
189
+ * payment method when ETH transfers are failing during bidding process
190
+ */
191
+ constructor(
192
+ address _genArt721Address,
193
+ address _minterFilter
194
+ ) ReentrancyGuard() MinterBase(_genArt721Address) {
195
+ genArt721CoreAddress = _genArt721Address;
196
+ genArtCoreContract_Base = IGenArt721CoreContractV3_Base(
197
+ _genArt721Address
198
+ );
199
+ minterFilterAddress = _minterFilter;
200
+ minterFilter = IMinterFilterV0(_minterFilter);
201
+ require(
202
+ minterFilter.genArt721CoreAddress() == _genArt721Address,
203
+ "Illegal contract pairing"
204
+ );
205
+ // emit events indicating default minter configuration values
206
+ emit AuctionDurationSecondsRangeUpdated({
207
+ minAuctionDurationSeconds: minAuctionDurationSeconds,
208
+ maxAuctionDurationSeconds: maxAuctionDurationSeconds
209
+ });
210
+ emit MinterMinBidIncrementPercentageUpdated(
211
+ minterMinBidIncrementPercentage
212
+ );
213
+ emit MinterTimeBufferUpdated(minterTimeBufferSeconds);
214
+ emit MinterRefundGasLimitUpdated(minterRefundGasLimit);
215
+ }
216
+
217
+ /**
218
+ * @notice Syncs local maximum invocations of project `_projectId` based on
219
+ * the value currently defined in the core contract.
220
+ * @param _projectId Project ID to set the maximum invocations for.
221
+ * @dev this enables gas reduction after maxInvocations have been reached -
222
+ * core contracts shall still enforce a maxInvocation check during mint.
223
+ */
224
+ function setProjectMaxInvocations(uint256 _projectId) public {
225
+ _onlyArtist(_projectId);
226
+ uint256 maxInvocations;
227
+ uint256 invocations;
228
+ (invocations, maxInvocations, , , , ) = genArtCoreContract_Base
229
+ .projectStateData(_projectId);
230
+
231
+ // update storage with results
232
+ projectConfig[_projectId].maxInvocations = uint24(maxInvocations);
233
+
234
+ // must ensure maxHasBeenInvoked is correctly set after manually syncing the
235
+ // local maxInvocations value with the core contract's maxInvocations value.
236
+ // This synced value of maxInvocations from the core contract will always be greater
237
+ // than or equal to the previous value of maxInvocations stored locally.
238
+ projectConfig[_projectId].maxHasBeenInvoked =
239
+ invocations == maxInvocations;
240
+
241
+ emit ProjectMaxInvocationsLimitUpdated({
242
+ _projectId: _projectId,
243
+ _maxInvocations: maxInvocations
244
+ });
245
+
246
+ // for convenience, try to mint and assign a token to the project's
247
+ // next slot
248
+ _tryMintTokenToNextSlot(_projectId);
249
+ }
250
+
251
+ /**
252
+ * @notice Manually sets the local maximum invocations of project `_projectId`
253
+ * with the provided `_maxInvocations`, checking that `_maxInvocations` is less
254
+ * than or equal to the value of project `_project_id`'s maximum invocations that is
255
+ * set on the core contract.
256
+ * @dev Note that a `_maxInvocations` of 0 can only be set if the current `invocations`
257
+ * value is also 0 and this would also set `maxHasBeenInvoked` to true, correctly short-circuiting
258
+ * this minter's purchase function, avoiding extra gas costs from the core contract's maxInvocations check.
259
+ * @param _projectId Project ID to set the maximum invocations for.
260
+ * @param _maxInvocations Maximum invocations to set for the project.
261
+ */
262
+ function manuallyLimitProjectMaxInvocations(
263
+ uint256 _projectId,
264
+ uint256 _maxInvocations
265
+ ) external {
266
+ _onlyArtist(_projectId);
267
+ // CHECKS
268
+ // ensure that the manually set maxInvocations is not greater than what is set on the core contract
269
+ uint256 maxInvocations;
270
+ uint256 invocations;
271
+ (invocations, maxInvocations, , , , ) = genArtCoreContract_Base
272
+ .projectStateData(_projectId);
273
+ require(
274
+ _maxInvocations <= maxInvocations,
275
+ "Cannot increase project max invocations above core contract set project max invocations"
276
+ );
277
+ require(
278
+ _maxInvocations >= invocations,
279
+ "Cannot set project max invocations to less than current invocations"
280
+ );
281
+ // EFFECTS
282
+ // update storage with results
283
+ projectConfig[_projectId].maxInvocations = uint24(_maxInvocations);
284
+ // We need to ensure maxHasBeenInvoked is correctly set after manually
285
+ // setting the local maxInvocations value.
286
+ projectConfig[_projectId].maxHasBeenInvoked =
287
+ invocations == _maxInvocations;
288
+
289
+ emit ProjectMaxInvocationsLimitUpdated({
290
+ _projectId: _projectId,
291
+ _maxInvocations: _maxInvocations
292
+ });
293
+
294
+ // for convenience, try to mint and assign a token to the project's
295
+ // next slot
296
+ _tryMintTokenToNextSlot(_projectId);
297
+ }
298
+
299
+ /**
300
+ * @notice Sets the minimum and maximum values that are settable for
301
+ * `durationSeconds` for all project configurations.
302
+ * Note that the auction duration is the initial duration of the auction,
303
+ * and does not include any extensions that may occur due to new bids being
304
+ * placed near the end of an auction.
305
+ * @param _minAuctionDurationSeconds Minimum auction duration in seconds.
306
+ * @param _maxAuctionDurationSeconds Maximum auction duration in seconds.
307
+ */
308
+ function updateAllowableAuctionDurationSeconds(
309
+ uint32 _minAuctionDurationSeconds,
310
+ uint32 _maxAuctionDurationSeconds
311
+ ) external {
312
+ _onlyNonZero(_minAuctionDurationSeconds);
313
+ _onlyCoreAdminACL(this.updateAllowableAuctionDurationSeconds.selector);
314
+ // CHECKS
315
+ require(
316
+ _maxAuctionDurationSeconds > _minAuctionDurationSeconds,
317
+ "Only max gt min"
318
+ );
319
+ // EFFECTS
320
+ minAuctionDurationSeconds = _minAuctionDurationSeconds;
321
+ maxAuctionDurationSeconds = _maxAuctionDurationSeconds;
322
+ emit AuctionDurationSecondsRangeUpdated({
323
+ minAuctionDurationSeconds: _minAuctionDurationSeconds,
324
+ maxAuctionDurationSeconds: _maxAuctionDurationSeconds
325
+ });
326
+ }
327
+
328
+ /**
329
+ * @notice Sets the minter-wide minimum bid increment percentage. New bids
330
+ * must be this percent higher than the current top bid to be successful.
331
+ * This value should be configured by admin such that appropriate price
332
+ * discovery is able to be reached, but gas fees associated with bidding
333
+ * wars do not dominate the economics of an auction.
334
+ * @dev the input value is considered to be a percentage, so that a value
335
+ * of 5 represents 5%.
336
+ * @param _minterMinBidIncrementPercentage Minimum bid increment percentage
337
+ */
338
+ function updateMinterMinBidIncrementPercentage(
339
+ uint8 _minterMinBidIncrementPercentage
340
+ ) external {
341
+ _onlyNonZero(_minterMinBidIncrementPercentage);
342
+ _onlyCoreAdminACL(this.updateMinterMinBidIncrementPercentage.selector);
343
+ // CHECKS
344
+ // EFFECTS
345
+ minterMinBidIncrementPercentage = _minterMinBidIncrementPercentage;
346
+ emit MinterMinBidIncrementPercentageUpdated(
347
+ _minterMinBidIncrementPercentage
348
+ );
349
+ }
350
+
351
+ /**
352
+ * @notice Sets the minter-wide time buffer in seconds. The time buffer is
353
+ * the minimum amount of time that must pass between the final bid and the
354
+ * the end of an auction. Auctions are extended if a new bid is placed
355
+ * within this time buffer of the auction end time.
356
+ * @param _minterTimeBufferSeconds Time buffer in seconds.
357
+ */
358
+ function updateMinterTimeBufferSeconds(
359
+ uint32 _minterTimeBufferSeconds
360
+ ) external {
361
+ _onlyNonZero(_minterTimeBufferSeconds);
362
+ _onlyCoreAdminACL(this.updateMinterTimeBufferSeconds.selector);
363
+ // CHECKS
364
+ // EFFECTS
365
+ minterTimeBufferSeconds = _minterTimeBufferSeconds;
366
+ emit MinterTimeBufferUpdated(_minterTimeBufferSeconds);
367
+ }
368
+
369
+ /**
370
+ * @notice Sets the gas limit during ETH refunds when a collector is
371
+ * outbid. This value should be set to a value that is high enough to
372
+ * ensure that refunds are successful for commonly used wallets, but low
373
+ * enough to avoid excessive abuse of refund gas allowance during a new
374
+ * bid.
375
+ * @dev max gas limit is 63,535, which is considered a future-safe upper
376
+ * bound.
377
+ * @param _minterRefundGasLimit Gas limit to set for refunds. Must be between
378
+ * 5,000 and max uint16 (63,535).
379
+ */
380
+ function updateRefundGasLimit(uint16 _minterRefundGasLimit) external {
381
+ _onlyCoreAdminACL(this.updateRefundGasLimit.selector);
382
+ // CHECKS
383
+ // @dev max gas limit implicitly checked by using uint16 input arg
384
+ // @dev min gas limit is based on rounding up current cost to send ETH
385
+ // to a Gnosis Safe wallet, which accesses cold address and emits event
386
+ require(_minterRefundGasLimit >= 7_000, "Only gte 7_000");
387
+ // EFFECTS
388
+ minterRefundGasLimit = _minterRefundGasLimit;
389
+ emit MinterRefundGasLimitUpdated(_minterRefundGasLimit);
390
+ }
391
+
392
+ /**
393
+ * @notice Warning: Disabling purchaseTo is not supported on this minter.
394
+ * This method exists purely for interface-conformance purposes.
395
+ */
396
+ function togglePurchaseToDisabled(uint256 /*_projectId*/) external pure {
397
+ // @dev access control to _onlyArtist is required if this method is
398
+ // ever re-implemented
399
+ revert("Action not supported");
400
+ }
401
+
402
+ /**
403
+ * @notice Sets auction details for project `_projectId`.
404
+ * If project does not have a "next token" assigned, this function attempts
405
+ * to mint a token and assign it to the project's next token slot.
406
+ * @param _projectId Project ID to set future auction details for.
407
+ * @param _timestampStart Timestamp after which new auctions may be
408
+ * started. Note that this is not the timestamp of the auction start, but
409
+ * rather the timestamp after which a auction may be started. Also note
410
+ * that the passed value here must either be in the future, or `0` (which
411
+ * indicates that auctions are immediately startable).
412
+ * @param _auctionDurationSeconds Duration of new auctions, in seconds,
413
+ * before any extensions due to bids being placed inside buffer period near
414
+ * the end of an auction.
415
+ * @param _basePrice reserve price (minimum starting bid price), in wei.
416
+ * Must be greater than 0, but may be as low as 1 wei.
417
+ * @dev `_basePrice` of zero not allowed to prevent accidental
418
+ * misconfiguration of auctions
419
+ */
420
+ function configureFutureAuctions(
421
+ uint256 _projectId,
422
+ uint256 _timestampStart,
423
+ uint256 _auctionDurationSeconds,
424
+ uint256 _basePrice
425
+ ) external {
426
+ _onlyNonZero(_basePrice);
427
+ _onlyArtist(_projectId);
428
+ // CHECKS
429
+ ProjectConfig storage _projectConfig = projectConfig[_projectId];
430
+ require(
431
+ _timestampStart == 0 || block.timestamp < _timestampStart,
432
+ "Only future start times or 0"
433
+ );
434
+ require(
435
+ (_auctionDurationSeconds >= minAuctionDurationSeconds) &&
436
+ (_auctionDurationSeconds <= maxAuctionDurationSeconds),
437
+ "Auction duration out of range"
438
+ );
439
+ // EFFECTS
440
+ _projectConfig.timestampStart = _timestampStart.toUint64();
441
+ _projectConfig.auctionDurationSeconds = _auctionDurationSeconds
442
+ .toUint32();
443
+ _projectConfig.basePrice = _basePrice;
444
+
445
+ emit ConfiguredFutureAuctions({
446
+ projectId: _projectId,
447
+ timestampStart: _timestampStart.toUint64(),
448
+ auctionDurationSeconds: _auctionDurationSeconds.toUint32(),
449
+ basePrice: _basePrice
450
+ });
451
+
452
+ // sync local max invocations if not initially populated
453
+ // @dev if local max invocations and maxHasBeenInvoked are both
454
+ // initial values, we know they have not been populated.
455
+ if (
456
+ _projectConfig.maxInvocations == 0 &&
457
+ _projectConfig.maxHasBeenInvoked == false
458
+ ) {
459
+ setProjectMaxInvocations(_projectId);
460
+ // @dev setProjectMaxInvocations function calls
461
+ // _tryMintTokenToNextSlot, so we do not call it here.
462
+ } else {
463
+ // for convenience, try to mint to next token slot
464
+ _tryMintTokenToNextSlot(_projectId);
465
+ }
466
+ }
467
+
468
+ /**
469
+ * @notice Resets future auction configuration for project `_projectId`,
470
+ * zero-ing out all details having to do with future auction parameters.
471
+ * This is not intended to be used in normal operation, but rather only in
472
+ * case of the need to halt the creation of any future auctions.
473
+ * Does not affect any project max invocation details.
474
+ * Does not affect any project next token details (i.e. if a next token is
475
+ * assigned, it will remain assigned and held by the minter until auction
476
+ * details are reconfigured).
477
+ * @param _projectId Project ID to reset future auction configuration
478
+ * details for.
479
+ */
480
+ function resetAuctionDetails(uint256 _projectId) external {
481
+ _onlyCoreAdminACLOrArtist(
482
+ _projectId,
483
+ this.resetAuctionDetails.selector
484
+ );
485
+ ProjectConfig storage _projectConfig = projectConfig[_projectId];
486
+ // reset to initial values
487
+ _projectConfig.timestampStart = 0;
488
+ _projectConfig.auctionDurationSeconds = 0;
489
+ _projectConfig.basePrice = 0;
490
+ // @dev do not affect next token or max invocations
491
+
492
+ emit ResetAuctionDetails(_projectId);
493
+ }
494
+
495
+ /**
496
+ * @notice Admin-only function that ejects a project's "next token" from
497
+ * the minter and sends it to the input `_to` address.
498
+ * This function is only intended for use in the edge case where the minter
499
+ * has a "next token" assigned to a project, but the project has been reset
500
+ * via `resetAuctionDetails`, and the artist does not want an auction to be
501
+ * started for the "next token". This function also protects against the
502
+ * unforseen case where the minter is in an unexpected state where it has a
503
+ * "next token" assigned to a project, but for some reason the project is
504
+ * unable to begin a new auction due to a bug.
505
+ * @dev only a single token may be actively assigned to a project's "next
506
+ * token" slot at any given time. This function will eject the token, and
507
+ * no further tokens will be assigned to the project's "next token" slot,
508
+ * unless the project is subsequently reconfigured via an artist call to
509
+ * `configureFutureAuctions`.
510
+ * @param _projectId Project ID to eject next token for.
511
+ * @param _to Address to send the ejected token to.
512
+ */
513
+ function ejectNextTokenTo(uint256 _projectId, address _to) external {
514
+ _onlyCoreAdminACL(this.ejectNextTokenTo.selector);
515
+ ProjectConfig storage _projectConfig = projectConfig[_projectId];
516
+ // CHECKS
517
+ // only if project is not configured (i.e. artist called
518
+ // `resetAuctionDetails`)
519
+ require(
520
+ !_projectIsConfigured(_projectConfig),
521
+ "Only unconfigured projects"
522
+ );
523
+ // only if minter has a next token assigned
524
+ require(
525
+ _projectConfig.nextTokenNumberIsPopulated == true,
526
+ "No next token"
527
+ );
528
+ // EFFECTS
529
+ _projectConfig.nextTokenNumberIsPopulated = false;
530
+ // INTERACTIONS
531
+ // @dev overflow automatically handled by Sol ^0.8.0
532
+ uint256 nextTokenId = (_projectId * ONE_MILLION) +
533
+ _projectConfig.nextTokenNumber;
534
+ IERC721(genArt721CoreAddress).transferFrom({
535
+ from: address(this),
536
+ to: _to,
537
+ tokenId: nextTokenId
538
+ });
539
+ emit ProjectNextTokenEjected(_projectId);
540
+ }
541
+
542
+ /**
543
+ * @notice Emergency, Artist-only function that attempts to mint a new
544
+ * token and set it as the the next token to be auctioned for project
545
+ * `_projectId`.
546
+ * Note: This function is only included for emergency, unforseen use cases,
547
+ * and should not be used in normal operation. It is here only for
548
+ * redundant protection against an unforseen edge case where the minter
549
+ * does not have a populated "next token", but there are still invocations
550
+ * remaining on the project.
551
+ * This function reverts if the project is not configured on this minter.
552
+ * This function returns early and does not modify state when:
553
+ * - the minter already has a populated "next token" for the project
554
+ * - the project has reached its maximum invocations on the core contract
555
+ * or minter
556
+ * @dev This function is gated to only the project's artist to prevent
557
+ * early minting of tokens by other users.
558
+ * @param _projectId The project ID
559
+ */
560
+ function tryPopulateNextToken(uint256 _projectId) public nonReentrant {
561
+ _onlyArtist(_projectId);
562
+ // CHECKS
563
+ // revert if project is not configured on this minter
564
+ require(
565
+ _projectIsConfigured(projectConfig[_projectId]),
566
+ "Project not configured"
567
+ );
568
+ // INTERACTIONS
569
+ // attempt to mint new token to this minter contract, only if max
570
+ // invocations has not been reached
571
+ _tryMintTokenToNextSlot(_projectId);
572
+ }
573
+
574
+ /**
575
+ * @notice Settles any complete auction for token `_settleTokenId` (if
576
+ * applicable), then attempts to create a bid for token
577
+ * `_bidTokenId` with bid amount and bidder address equal to
578
+ * `msg.value` and `msg.sender`, respectively.
579
+ * Intended to gracefully handle the case where a user is front-run by
580
+ * one or more transactions to settle and/or initialize a new auction,
581
+ * potentially still placing a bid on the auction for the token ID if the
582
+ * bid value is sufficiently higher than the current highest bid.
583
+ * Note that the use of `_bidTokenId` is to prevent the possibility of
584
+ * transactions that are stuck in the pending pool for long periods of time
585
+ * from unintentionally bidding on auctions for future tokens.
586
+ * Note that calls to `settleAuction` and `createBid` are possible
587
+ * to be called in separate transactions, but this function is provided for
588
+ * convenience and executes both of those functions in a single
589
+ * transaction, while handling front-running as gracefully as possible.
590
+ * @param _settleTokenId Token ID to settle auction for.
591
+ * @param _bidTokenId Token ID to bid on.
592
+ * @dev this function is not non-reentrant, but the underlying calls are
593
+ * to non-reentrant functions.
594
+ */
595
+ function settleAuctionAndCreateBid(
596
+ uint256 _settleTokenId,
597
+ uint256 _bidTokenId
598
+ ) external payable {
599
+ // ensure tokens are in the same project
600
+ require(
601
+ _settleTokenId / ONE_MILLION == _bidTokenId / ONE_MILLION,
602
+ "Only tokens in same project"
603
+ );
604
+ // settle completed auction, if applicable
605
+ settleAuction(_settleTokenId);
606
+ // attempt to bid on next token
607
+ createBid_l34(_bidTokenId);
608
+ }
609
+
610
+ /**
611
+ * @notice Settles a completed auction for `_tokenId`, if it exists and is
612
+ * not yet settled.
613
+ * Returns early (does not modify state) if
614
+ * - there is no initialized auction for the project
615
+ * - there is an auction that has already been settled for the project
616
+ * - there is an auction for a different token ID on the project
617
+ * (likely due to a front-run)
618
+ * This function reverts if the auction for `_tokenId` exists, but has not
619
+ * yet ended.
620
+ * @param _tokenId Token ID to settle auction for.
621
+ */
622
+ function settleAuction(uint256 _tokenId) public nonReentrant {
623
+ uint256 _projectId = _tokenId / ONE_MILLION;
624
+ ProjectConfig storage _projectConfig = projectConfig[_projectId];
625
+ Auction storage _auction = _projectConfig.activeAuction;
626
+ // load from storage to memory for gas efficiency
627
+ address currentBidder = _auction.currentBidder;
628
+ uint256 currentBid = _auction.currentBid;
629
+ address genArt721CoreAddress_ = genArt721CoreAddress;
630
+ // CHECKS
631
+ // @dev this check is not strictly necessary, but is included for
632
+ // clear error messaging
633
+ require(_auctionIsInitialized(_auction), "Auction not initialized");
634
+ if (_auction.settled || (_auction.tokenId != _tokenId)) {
635
+ // auction already settled or is for a different token ID, so
636
+ // return early and do not modify state
637
+ return;
638
+ }
639
+ // @dev important that the following check is after the early return
640
+ // block above to maintain desired behavior
641
+ require(block.timestamp >= _auction.endTime, "Auction not yet ended");
642
+ // EFFECTS
643
+ _auction.settled = true;
644
+ // INTERACTIONS
645
+ // send token to the winning bidder
646
+ IERC721(genArt721CoreAddress_).transferFrom({
647
+ from: address(this),
648
+ to: currentBidder,
649
+ tokenId: _tokenId
650
+ });
651
+ // distribute revenues from auction
652
+ splitRevenuesETH(_projectId, currentBid, genArt721CoreAddress_);
653
+
654
+ emit AuctionSettled({
655
+ tokenId: _tokenId,
656
+ winner: currentBidder,
657
+ price: currentBid
658
+ });
659
+ }
660
+
661
+ /**
662
+ * @notice Enters a bid for token `_tokenId`.
663
+ * If an auction for token `_tokenId` does not exist, an auction will be
664
+ * initialized as long as any existing auction for the project has been
665
+ * settled.
666
+ * In order to successfully place the bid, the token bid must be:
667
+ * - greater than or equal to a project's minimum bid price if a new
668
+ * auction is initialized
669
+ * - sufficiently greater than the current highest bid, according to the
670
+ * minter's bid increment percentage `minterMinBidIncrementPercentage`,
671
+ * if an auction for the token already exists
672
+ * If the bid is unsuccessful, the transaction will revert.
673
+ * If the bid is successful, but outbid by another bid before the auction
674
+ * ends, the funds will be noncustodially returned to the bidder's address,
675
+ * `msg.sender`. A fallback method of sending funds back to the bidder via
676
+ * SELFDESTRUCT (SENDALL) prevents denial of service attacks, even if the
677
+ * original bidder reverts or runs out of gas during receive or fallback.
678
+ * ------------------------------------------------------------------------
679
+ * WARNING: bidders must be prepared to handle the case where their bid is
680
+ * outbid and their funds are returned to the original `msg.sender` address
681
+ * via SELFDESTRUCT (SENDALL).
682
+ * ------------------------------------------------------------------------
683
+ * Note that the use of `_tokenId` is to prevent the possibility of
684
+ * transactions that are stuck in the pending pool for long periods of time
685
+ * from unintentionally bidding on auctions for future tokens.
686
+ * If a new auction is initialized during this call, the project's next
687
+ * token will be attempted to be minted to this minter contract, preparing
688
+ * it for the next auction. If the project's next token cannot be minted
689
+ * due to e.g. reaching the maximum invocations on the core contract or
690
+ * minter, the project's next token will not be minted.
691
+ * @param _tokenId Token ID being bidded on
692
+ */
693
+ function createBid(uint256 _tokenId) external payable {
694
+ createBid_l34(_tokenId);
695
+ }
696
+
697
+ /**
698
+ * @notice gas-optimized version of createBid(uint256).
699
+ * @dev nonReentrant modifier is used to prevent reentrancy attacks, e.g.
700
+ * an an auto-bidder that would be able to atomically outbid a user's
701
+ * new bid via a reentrant call to createBid.
702
+ */
703
+ function createBid_l34(uint256 _tokenId) public payable nonReentrant {
704
+ uint256 _projectId = _tokenId / ONE_MILLION;
705
+ // CHECKS
706
+ ProjectConfig storage _projectConfig = projectConfig[_projectId];
707
+ Auction storage _auction = _projectConfig.activeAuction;
708
+ // load from storage to memory for gas efficiency
709
+ uint256 auctionEndTime = _auction.endTime;
710
+ uint256 previousBid = _auction.currentBid;
711
+
712
+ // if no auction exists, or current auction is already settled, attempt
713
+ // to initialize a new auction for the input token ID and immediately
714
+ // return
715
+ if ((!_auctionIsInitialized(_auction)) || _auction.settled) {
716
+ _initializeAuctionWithBid(_projectId, _tokenId);
717
+ return;
718
+ }
719
+ // @dev this branch is guaranteed to have an initialized auction that
720
+ // not settled, so no need to check for initialized or not settled
721
+
722
+ // ensure bids for a specific token ID are only applied to the auction
723
+ // for that token ID.
724
+ require(
725
+ _auction.tokenId == _tokenId,
726
+ "Token ID does not match auction"
727
+ );
728
+
729
+ // ensure auction is not already ended
730
+ require(auctionEndTime > block.timestamp, "Auction already ended");
731
+
732
+ // require bid to be sufficiently greater than current highest bid
733
+ // @dev no overflow enforced automatically by solidity ^0.8.0
734
+ require(
735
+ msg.value >=
736
+ (previousBid * (100 + minterMinBidIncrementPercentage)) / 100,
737
+ "Bid is too low"
738
+ );
739
+
740
+ // EFFECTS
741
+ // record previous highest bider for refunding
742
+ address payable previousBidder = _auction.currentBidder;
743
+
744
+ // update auction state
745
+ _auction.currentBid = msg.value;
746
+ _auction.currentBidder = payable(msg.sender);
747
+ uint256 minEndTime = block.timestamp + minterTimeBufferSeconds;
748
+ if (auctionEndTime < minEndTime) {
749
+ _auction.endTime = minEndTime.toUint64();
750
+ }
751
+
752
+ // INTERACTIONS
753
+ // refund previous highest bidder
754
+ _forceSafeTransferETH(previousBidder, previousBid);
755
+
756
+ emit AuctionBid({
757
+ tokenId: _tokenId,
758
+ bidder: msg.sender,
759
+ bidAmount: msg.value
760
+ });
761
+ }
762
+
763
+ /**
764
+ * @notice Inactive function - see `createBid` or
765
+ * `settleAuctionAndCreateBid`
766
+ */
767
+ function purchase(
768
+ uint256 /*_projectId*/
769
+ ) external payable returns (uint256 /*tokenId*/) {
770
+ revert("Inactive function");
771
+ }
772
+
773
+ /**
774
+ * @notice Inactive function - see `createBid` or
775
+ * `settleAuctionAndCreateBid`
776
+ */
777
+ function purchaseTo(
778
+ address /*_to*/,
779
+ uint256 /*_projectId*/
780
+ ) external payable returns (uint256 /*tokenId*/) {
781
+ revert("Inactive function");
782
+ }
783
+
784
+ /**
785
+ * @notice View function to return the current minter-level configuration
786
+ * details.
787
+ * @return minAuctionDurationSeconds_ Minimum auction duration in seconds
788
+ * @return maxAuctionDurationSeconds_ Maximum auction duration in seconds
789
+ * @return minterMinBidIncrementPercentage_ Minimum bid increment percentage
790
+ * @return minterTimeBufferSeconds_ Buffer time in seconds
791
+ * @return minterRefundGasLimit_ Gas limit for refunding ETH
792
+ */
793
+ function minterConfigurationDetails()
794
+ external
795
+ view
796
+ returns (
797
+ uint32 minAuctionDurationSeconds_,
798
+ uint32 maxAuctionDurationSeconds_,
799
+ uint8 minterMinBidIncrementPercentage_,
800
+ uint32 minterTimeBufferSeconds_,
801
+ uint16 minterRefundGasLimit_
802
+ )
803
+ {
804
+ minAuctionDurationSeconds_ = minAuctionDurationSeconds;
805
+ maxAuctionDurationSeconds_ = maxAuctionDurationSeconds;
806
+ minterMinBidIncrementPercentage_ = minterMinBidIncrementPercentage;
807
+ minterTimeBufferSeconds_ = minterTimeBufferSeconds;
808
+ minterRefundGasLimit_ = minterRefundGasLimit;
809
+ }
810
+
811
+ /**
812
+ * @notice projectId => has project reached its maximum number of
813
+ * invocations? Note that this returns a local cache of the core contract's
814
+ * state, and may be out of sync with the core contract. This is
815
+ * intentional, as it only enables gas optimization of mints after a
816
+ * project's maximum invocations has been reached. A false negative will
817
+ * only result in a gas cost increase, since the core contract will still
818
+ * enforce a maxInvocation check during minting. A false positive is not
819
+ * possible because the V3 core contract only allows maximum invocations
820
+ * to be reduced, not increased. Based on this rationale, we intentionally
821
+ * do not do input validation in this method as to whether or not the input
822
+ * `_projectId` is an existing project ID.
823
+ *
824
+ */
825
+ function projectMaxHasBeenInvoked(
826
+ uint256 _projectId
827
+ ) external view returns (bool) {
828
+ return projectConfig[_projectId].maxHasBeenInvoked;
829
+ }
830
+
831
+ /**
832
+ * @notice projectId => project's maximum number of invocations.
833
+ * Optionally synced with core contract value, for gas optimization.
834
+ * Note that this returns a local cache of the core contract's
835
+ * state, and may be out of sync with the core contract. This is
836
+ * intentional, as it only enables gas optimization of mints after a
837
+ * project's maximum invocations has been reached.
838
+ * @dev A number greater than the core contract's project max invocations
839
+ * will only result in a gas cost increase, since the core contract will
840
+ * still enforce a maxInvocation check during minting. A number less than
841
+ * the core contract's project max invocations is only possible when the
842
+ * project's max invocations have not been synced on this minter, since the
843
+ * V3 core contract only allows maximum invocations to be reduced, not
844
+ * increased. When this happens, the minter will enable minting, allowing
845
+ * the core contract to enforce the max invocations check. Based on this
846
+ * rationale, we intentionally do not do input validation in this method as
847
+ * to whether or not the input `_projectId` is an existing project ID.
848
+ */
849
+ function projectMaxInvocations(
850
+ uint256 _projectId
851
+ ) external view returns (uint256) {
852
+ return uint256(projectConfig[_projectId].maxInvocations);
853
+ }
854
+
855
+ /**
856
+ * @notice projectId => project configuration details.
857
+ * Note that in the case of no auction being initialized for the project,
858
+ * the returned `auction` will be the default struct.
859
+ * @param _projectId The project ID
860
+ * @return projectConfig_ The project configuration details
861
+ */
862
+ function projectConfigurationDetails(
863
+ uint256 _projectId
864
+ ) external view returns (ProjectConfig memory projectConfig_) {
865
+ projectConfig_ = projectConfig[_projectId];
866
+ // clean up next token number to handle case where it is stale
867
+ projectConfig_.nextTokenNumber = projectConfig_
868
+ .nextTokenNumberIsPopulated
869
+ ? projectConfig_.nextTokenNumber
870
+ : 0;
871
+ }
872
+
873
+ /**
874
+ * @notice projectId => active auction details.
875
+ * @dev reverts if no auction exists for the project.
876
+ */
877
+ function projectActiveAuctionDetails(
878
+ uint256 _projectId
879
+ ) external view returns (Auction memory auction) {
880
+ ProjectConfig storage _projectConfig = projectConfig[_projectId];
881
+ Auction storage _auction = _projectConfig.activeAuction;
882
+ // do not return uninitialized auctions (i.e. auctions that do not
883
+ // exist, where currentBidder is still the default value)
884
+ require(
885
+ _auctionIsInitialized(_auction),
886
+ "No auction exists on project"
887
+ );
888
+ // load entire auction into memory
889
+ auction = _projectConfig.activeAuction;
890
+ return auction;
891
+ }
892
+
893
+ /**
894
+ * @notice Convenience function that returns either the current token ID
895
+ * being auctioned, or the next expected token ID to be auction if no
896
+ * auction is currently initialized or if the current auction has concluded
897
+ * (block.timestamp > auction.endTime).
898
+ * This is intended to be useful for frontends or scripts that intend to
899
+ * call `createBid` or `settleAuctionAndCreateBid`, which requires a
900
+ * target bid token ID to be passed in as an argument.
901
+ * The function reverts if a project does not have an active auction and
902
+ * the next expected token ID has not been populated.
903
+ * @param _projectId The project ID being queried
904
+ * @return The current token ID being auctioned, or the next token ID to be
905
+ * auctioned if a new auction is ready to be created.
906
+ */
907
+ function getTokenToBid(uint256 _projectId) external view returns (uint256) {
908
+ ProjectConfig storage _projectConfig = projectConfig[_projectId];
909
+ Auction storage _auction = _projectConfig.activeAuction;
910
+ // if project has an active token auction that is not settled, return
911
+ // that token ID
912
+ if (
913
+ _auctionIsInitialized(_auction) &&
914
+ (_auction.endTime > block.timestamp)
915
+ ) {
916
+ return _auction.tokenId;
917
+ }
918
+ // otherwise, return the next expected token ID to be auctioned
919
+ return getNextTokenId(_projectId);
920
+ }
921
+
922
+ /**
923
+ * @notice View function that returns the next token ID to be auctioned
924
+ * by this minter for project `_projectId`.
925
+ * Reverts if the next token ID has not been populated for the project.
926
+ * @param _projectId The project ID being queried
927
+ * @return nextTokenId The next token ID to be auctioned by this minter
928
+ */
929
+ function getNextTokenId(
930
+ uint256 _projectId
931
+ ) public view returns (uint256 nextTokenId) {
932
+ ProjectConfig storage _projectConfig = projectConfig[_projectId];
933
+ if (!_projectConfig.nextTokenNumberIsPopulated) {
934
+ revert("Next token not populated");
935
+ }
936
+ // @dev overflow automatically checked in Solidity ^0.8.0
937
+ nextTokenId =
938
+ (_projectId * ONE_MILLION) +
939
+ _projectConfig.nextTokenNumber;
940
+ return nextTokenId;
941
+ }
942
+
943
+ /**
944
+ * @dev Internal function to initialize an auction for the next token ID
945
+ * on project `_projectId` with a bid of `msg.value` from `msg.sender`.
946
+ * This function reverts in any of the following cases:
947
+ * - project is not configured on this minter
948
+ * - project is configured but has not yet reached its start time
949
+ * - project has a current active auction that is not settled
950
+ * - insufficient bid amount (msg.value < basePrice)
951
+ * - no next token has been minted for the project (artist may need to
952
+ * call `tryPopulateNextToken`)
953
+ * - `_targetTokenId` does not match the next token ID for the project
954
+ * After initializing a new auction, this function attempts to mint a new
955
+ * token and assign it to the project's next token slot, in preparation for
956
+ * a future token auction. However, if the project has reached its maximum
957
+ * invocations on either the core contract or minter, the next token slot
958
+ * for the project will remain empty.
959
+ * @dev This should be executed in a nonReentrant context to provide redundant
960
+ * protection against reentrancy.
961
+ */
962
+ function _initializeAuctionWithBid(
963
+ uint256 _projectId,
964
+ uint256 _targetTokenId
965
+ ) internal {
966
+ ProjectConfig storage _projectConfig = projectConfig[_projectId];
967
+ Auction storage _auction = _projectConfig.activeAuction;
968
+ // CHECKS
969
+ // ensure project auctions are configured
970
+ // @dev base price of zero indicates auctions are not configured
971
+ // because only base price of gt zero is allowed when configuring
972
+ require(_projectIsConfigured(_projectConfig), "Project not configured");
973
+ // only initialize new auctions if they meet the start time
974
+ // requirement
975
+ require(
976
+ block.timestamp >= _projectConfig.timestampStart,
977
+ "Only gte project start time"
978
+ );
979
+ // the following require statement is redundant based on how this
980
+ // internal function is called, but it is included for protection
981
+ // against future changes that could easily introduce a bug if this
982
+ // check is not present
983
+ // @dev no cover else branch of next line because unreachable
984
+ require(
985
+ (!_auctionIsInitialized(_auction)) || _auction.settled,
986
+ "Existing auction not settled"
987
+ );
988
+ // require valid bid value
989
+ require(
990
+ msg.value >= _projectConfig.basePrice,
991
+ "Insufficient initial bid"
992
+ );
993
+ // require next token number is populated
994
+ // @dev this should only be encountered if the project has reached
995
+ // its maximum invocations on either the core contract or minter
996
+ require(
997
+ _projectConfig.nextTokenNumberIsPopulated,
998
+ "No next token, check max invocations"
999
+ );
1000
+ // require next token number is the target token ID
1001
+ require(
1002
+ _projectConfig.nextTokenNumber == _targetTokenId % ONE_MILLION,
1003
+ "Incorrect target token ID"
1004
+ );
1005
+
1006
+ // EFFECTS
1007
+ // create new auction, overwriting previous auction if it exists
1008
+ uint64 endTime = (block.timestamp +
1009
+ _projectConfig.auctionDurationSeconds).toUint64();
1010
+ _projectConfig.activeAuction = Auction({
1011
+ tokenId: _targetTokenId,
1012
+ currentBid: msg.value,
1013
+ currentBidder: payable(msg.sender),
1014
+ endTime: endTime,
1015
+ settled: false
1016
+ });
1017
+ // mark next token number as not populated
1018
+ // @dev intentionally not setting nextTokenNumber to zero to avoid
1019
+ // unnecessary gas costs
1020
+ _projectConfig.nextTokenNumberIsPopulated = false;
1021
+
1022
+ // @dev we intentionally emit event here due to potential of early
1023
+ // return in INTERACTIONS section
1024
+ emit AuctionInitialized({
1025
+ tokenId: _targetTokenId,
1026
+ bidder: msg.sender,
1027
+ bidAmount: msg.value,
1028
+ endTime: endTime
1029
+ });
1030
+
1031
+ // INTERACTIONS
1032
+ // attempt to mint new token to this minter contract, only if max
1033
+ // invocations has not been reached
1034
+ _tryMintTokenToNextSlot(_projectId);
1035
+ }
1036
+
1037
+ /**
1038
+ * @notice Internal function that attempts to mint a new token to the next
1039
+ * token slot for the project `_projectId`.
1040
+ * This function returns early and does not modify state if
1041
+ * - the project has reached its maximum invocations on either the core
1042
+ * contract or minter
1043
+ * - the project config's `nextTokenNumberIsPopulated` is already true
1044
+ * @param _projectId The ID of the project to mint a new token for.
1045
+ * @dev this calls mint with `msg.sender` as the sender, allowing artists
1046
+ * to mint tokens to the next token slot for their project while a project
1047
+ * is still paused. This happens when an artist is configuring their
1048
+ * project's auction parameters or minter max invocations.
1049
+ */
1050
+ function _tryMintTokenToNextSlot(uint256 _projectId) internal {
1051
+ ProjectConfig storage _projectConfig = projectConfig[_projectId];
1052
+ if (_projectConfig.nextTokenNumberIsPopulated) {
1053
+ return;
1054
+ }
1055
+ // INTERACTIONS
1056
+ // attempt to mint new token to this minter contract, only if max
1057
+ // invocations has not been reached
1058
+ // we require up-to-date invocation data to properly handle last token
1059
+ (
1060
+ uint256 coreInvocations,
1061
+ uint256 coreMaxInvocations,
1062
+ ,
1063
+ ,
1064
+ ,
1065
+
1066
+ ) = genArtCoreContract_Base.projectStateData(_projectId);
1067
+ uint256 localMaxInvocations = _projectConfig.maxInvocations;
1068
+ uint256 minMaxInvocations = Math.min(
1069
+ coreMaxInvocations,
1070
+ localMaxInvocations
1071
+ );
1072
+ if (coreInvocations >= minMaxInvocations) {
1073
+ // we have reached the max invocations, so we do not mint a new
1074
+ // token as the "next token", and leave the next token number as
1075
+ // not populated
1076
+ return;
1077
+ }
1078
+ // @dev this is an effect after a trusted contract interaction
1079
+ _projectConfig.nextTokenNumberIsPopulated = true;
1080
+ // mint a new token to this project's "next token" slot
1081
+ // @dev this is an interaction with a trusted contract
1082
+ uint256 nextTokenId = minterFilter.mint(
1083
+ address(this),
1084
+ _projectId,
1085
+ msg.sender
1086
+ );
1087
+ // update state to reflect new token number
1088
+ // @dev state changes after trusted contract interaction
1089
+ // @dev unchecked is safe because mod 1e6 is guaranteed to be less than
1090
+ // max uint24
1091
+ unchecked {
1092
+ _projectConfig.nextTokenNumber = uint24(nextTokenId % ONE_MILLION);
1093
+ }
1094
+ // update local maxHasBeenInvoked value if necessary
1095
+ uint256 tokenInvocation = (nextTokenId % ONE_MILLION) + 1;
1096
+ if (tokenInvocation == localMaxInvocations) {
1097
+ _projectConfig.maxHasBeenInvoked = true;
1098
+ }
1099
+ emit ProjectNextTokenUpdated({
1100
+ projectId: _projectId,
1101
+ tokenId: nextTokenId
1102
+ });
1103
+ }
1104
+
1105
+ /**
1106
+ * @notice Force sends `amount` (in wei) ETH to `to`, with a gas stipend
1107
+ * equal to `minterRefundGasLimit`.
1108
+ * If sending via the normal procedure fails, force sends the ETH by
1109
+ * creating a temporary contract which uses `SELFDESTRUCT` to force send
1110
+ * the ETH.
1111
+ * Reverts if the current contract has insufficient balance.
1112
+ * @param _to The address to send ETH to.
1113
+ * @param _amount The amount of ETH to send.
1114
+ * @dev This function is adapted from the `forceSafeTransferETH` function
1115
+ * in the `https://github.com/Vectorized/solady` repository, with
1116
+ * modifications to not check if the current contract has sufficient
1117
+ * balance.
1118
+ */
1119
+ function _forceSafeTransferETH(address _to, uint256 _amount) internal {
1120
+ // load state variable into memory for use in inline assembly
1121
+ uint256 minterRefundGasLimit_ = minterRefundGasLimit;
1122
+ // Manually inlined because the compiler doesn't inline functions with
1123
+ // branches.
1124
+ /// @solidity memory-safe-assembly
1125
+ assembly {
1126
+ // @dev intentionally do not check if this contract has sufficient
1127
+ // balance, because that is not intended to be a valid state.
1128
+
1129
+ // Transfer the ETH and check if it succeeded or not.
1130
+ if iszero(call(minterRefundGasLimit_, _to, _amount, 0, 0, 0, 0)) {
1131
+ // if the transfer failed, we create a temporary contract with
1132
+ // initialization code that uses `SELFDESTRUCT` to force send
1133
+ // the ETH.
1134
+ // note: Compatible with `SENDALL`:
1135
+ // https://eips.ethereum.org/EIPS/eip-4758
1136
+
1137
+ //---------------------------------------------------------------------------------------------------------------//
1138
+ // Opcode | Opcode + Arguments | Description | Stack View //
1139
+ //---------------------------------------------------------------------------------------------------------------//
1140
+ // Contract creation code that uses `SELFDESTRUCT` to force send ETH to a specified address. //
1141
+ // Creation code summary: 0x73<20-byte toAddress>0xff //
1142
+ //---------------------------------------------------------------------------------------------------------------//
1143
+ // 0x73 | 0x73_toAddress | PUSH20 toAddress | toAddress //
1144
+ // 0xFF | 0xFF | SELFDESTRUCT | //
1145
+ //---------------------------------------------------------------------------------------------------------------//
1146
+ // Store the address in scratch space, starting at 0x00, which begins the 20-byte address at 32-20=12 in memory
1147
+ // @dev use scratch space because we have enough space for simple creation code (less than 0x40 bytes)
1148
+ mstore(0x00, _to)
1149
+ // store opcode PUSH20 immediately before the address, starting at 0x0b (11) in memory
1150
+ mstore8(0x0b, 0x73)
1151
+ // store opcode SELFDESTRUCT immediately after the address, starting at 0x20 (32) in memory
1152
+ mstore8(0x20, 0xff)
1153
+ // this will always succeed because the contract creation code is
1154
+ // valid, and the address is valid because it is a 20-byte value
1155
+ if iszero(create(_amount, 0x0b, 0x16)) {
1156
+ // @dev For better gas estimation.
1157
+ if iszero(gt(gas(), 1000000)) {
1158
+ revert(0, 0)
1159
+ }
1160
+ }
1161
+ }
1162
+ }
1163
+ }
1164
+
1165
+ /**
1166
+ * @notice Determines if a project is configured or not on this minter.
1167
+ * Uses project config's `auctionDurationSeconds` to determine if project
1168
+ * is configured, because `auctionDurationSeconds` is required to be
1169
+ * non-zero when configured.
1170
+ * @param _projectConfig The project config to check.
1171
+ */
1172
+ function _projectIsConfigured(
1173
+ ProjectConfig storage _projectConfig
1174
+ ) internal view returns (bool) {
1175
+ return _projectConfig.auctionDurationSeconds != 0;
1176
+ }
1177
+
1178
+ /**
1179
+ * @notice Determines if an auction is initialized.
1180
+ * Uses auction's `currentBidder` address to determine if auction is
1181
+ * initialized, because `currentBidder` is always non-zero after an auction
1182
+ * has been initialized.
1183
+ * @param _auction The auction to check.
1184
+ */
1185
+ function _auctionIsInitialized(
1186
+ Auction storage _auction
1187
+ ) internal view returns (bool isInitialized) {
1188
+ // auction is initialized if currentBidder is non-zero
1189
+ return _auction.currentBidder != address(0);
1190
+ }
1191
+
1192
+ function _senderIsArtist(
1193
+ uint256 _projectId
1194
+ ) private view returns (bool senderIsArtist) {
1195
+ return
1196
+ msg.sender ==
1197
+ genArtCoreContract_Base.projectIdToArtistAddress(_projectId);
1198
+ }
1199
+
1200
+ function _adminACLAllowed(bytes4 _selector) private returns (bool) {
1201
+ return
1202
+ genArtCoreContract_Base.adminACLAllowed({
1203
+ _sender: msg.sender,
1204
+ _contract: address(this),
1205
+ _selector: _selector
1206
+ });
1207
+ }
1208
+
1209
+ /**
1210
+ * @notice Gets price info to become the leading bidder on a token auction.
1211
+ * If artist has not called `configureFutureAuctions` and there is no
1212
+ * active token auction accepting bids, `isConfigured` will be false, and a
1213
+ * dummy price of zero is assigned to `tokenPriceInWei`.
1214
+ * If there is an active auction accepting bids, `isConfigured` will be
1215
+ * true, and `tokenPriceInWei` will be the sum of the current bid value and
1216
+ * the minimum bid increment due to the minter's
1217
+ * `minterMinBidIncrementPercentage`.
1218
+ * If there is an auction that has ended (no longer accepting bids), but
1219
+ * the project is configured, `isConfigured` will be true, and
1220
+ * `tokenPriceInWei` will be the minimum initial bid price for the next
1221
+ * token auction.
1222
+ * Also returns currency symbol and address to be being used as payment,
1223
+ * which for this minter is ETH only.
1224
+ * @param _projectId Project ID to get price information for.
1225
+ * @return isConfigured true only if project auctions are configured.
1226
+ * @return tokenPriceInWei price in wei to become the leading bidder on a
1227
+ * token auction.
1228
+ * @return currencySymbol currency symbol for purchases of project on this
1229
+ * minter. This minter always returns "ETH"
1230
+ * @return currencyAddress currency address for purchases of project on
1231
+ * this minter. This minter always returns null address, reserved for ether
1232
+ */
1233
+ function getPriceInfo(
1234
+ uint256 _projectId
1235
+ )
1236
+ external
1237
+ view
1238
+ returns (
1239
+ bool isConfigured,
1240
+ uint256 tokenPriceInWei,
1241
+ string memory currencySymbol,
1242
+ address currencyAddress
1243
+ )
1244
+ {
1245
+ ProjectConfig storage _projectConfig = projectConfig[_projectId];
1246
+ Auction storage _auction = _projectConfig.activeAuction;
1247
+ // base price of zero not allowed when configuring auctions, so use it
1248
+ // as indicator of whether auctions are configured for the project
1249
+ bool projectIsConfigured = _projectIsConfigured(_projectConfig);
1250
+ bool auctionIsAcceptingBids = (_auctionIsInitialized(_auction) &&
1251
+ block.timestamp < _auction.endTime);
1252
+ isConfigured = projectIsConfigured || auctionIsAcceptingBids;
1253
+ // only return non-zero price if auction is configured
1254
+ if (isConfigured) {
1255
+ if (auctionIsAcceptingBids) {
1256
+ // return current bid plus minimum bid increment
1257
+ // @dev overflow automatically checked in Solidity ^0.8.0
1258
+ tokenPriceInWei =
1259
+ (_auction.currentBid *
1260
+ (100 + minterMinBidIncrementPercentage)) /
1261
+ 100;
1262
+ } else {
1263
+ // return base (starting) price if if current auction is not
1264
+ // accepting bids (i.e. the minimum initial bid price for the
1265
+ // next token auction)
1266
+ tokenPriceInWei = _projectConfig.basePrice;
1267
+ }
1268
+ }
1269
+ // else leave tokenPriceInWei as default value of zero
1270
+ currencySymbol = "ETH";
1271
+ currencyAddress = address(0);
1272
+ }
1273
+ }