@artblocks/contracts 1.0.0 → 1.0.2
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.
- package/.env.example +8 -1
- package/README.md +44 -165
- package/artifacts/contracts/AdminACLV1.sol/AdminACLV1.json +2 -2
- package/artifacts/contracts/DependencyRegistryV0.sol/DependencyRegistryV0.json +2 -2
- package/artifacts/contracts/GenArt721CoreV3.sol/GenArt721CoreV3.json +2 -2
- package/artifacts/contracts/GenArt721CoreV3_Engine.sol/GenArt721CoreV3_Engine.json +2 -2
- package/artifacts/contracts/GenArt721CoreV3_Engine_Flex.sol/GenArt721CoreV3_Engine_Flex.json +2229 -0
- package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExp/MinterDAExpV0.sol/MinterDAExpV0.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExp/MinterDAExpV1.sol/MinterDAExpV1.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExp/MinterDAExpV2.sol/MinterDAExpV2.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExp/MinterDAExpV3.sol/MinterDAExpV3.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExpSettlement/MinterDAExpSettlementV0.sol/MinterDAExpSettlementV0.json +2 -2
- package/artifacts/contracts/{minter-suite/Minters → archive/minter-suite/Minters/MinterDAExpSettlement}/MinterDAExpSettlementV1.sol/MinterDAExpSettlementV1.json +3 -3
- package/artifacts/contracts/archive/minter-suite/Minters/MinterDALin/MinterDALinV0.sol/MinterDALinV0.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterDALin/MinterDALinV1.sol/MinterDALinV1.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterDALin/MinterDALinV2.sol/MinterDALinV2.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterDALin/MinterDALinV3.sol/MinterDALinV3.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterHolder/MinterHolderV0.sol/MinterHolderV0.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterHolder/MinterHolderV1.sol/MinterHolderV1.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterHolder/MinterHolderV2.sol/MinterHolderV2.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterHolder/MinterHolderV3.sol/MinterHolderV3.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV0.sol/MinterMerkleV0.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV1.sol/MinterMerkleV1.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV2.sol/MinterMerkleV2.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV3.sol/MinterMerkleV3.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV4.sol/MinterMerkleV4.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPrice/MinterSetPriceV0.sol/MinterSetPriceV0.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPrice/MinterSetPriceV1.sol/MinterSetPriceV1.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPrice/MinterSetPriceV2.sol/MinterSetPriceV2.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPrice/MinterSetPriceV3.sol/MinterSetPriceV3.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPriceERC20/MinterSetPriceERC20V0.sol/MinterSetPriceERC20V0.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPriceERC20/MinterSetPriceERC20V1.sol/MinterSetPriceERC20V1.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPriceERC20/MinterSetPriceERC20V2.sol/MinterSetPriceERC20V2.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPriceERC20/MinterSetPriceERC20V3.sol/MinterSetPriceERC20V3.json +2 -2
- package/artifacts/contracts/explorations/GenArt721CoreV3_Explorations.sol/GenArt721CoreV3_Explorations.json +2 -2
- package/artifacts/contracts/interfaces/0.8.x/IFilteredMinterDAExpSettlementV1.sol/IFilteredMinterDAExpSettlementV1.json +767 -0
- package/artifacts/contracts/interfaces/0.8.x/IFilteredMinterSEAV0.sol/IFilteredMinterSEAV0.json +1032 -0
- package/artifacts/contracts/interfaces/0.8.x/IGenArt721CoreContractV3.sol/IGenArt721CoreContractV3.json +149 -0
- package/artifacts/contracts/interfaces/0.8.x/IGenArt721CoreContractV3_Base.sol/IGenArt721CoreContractV3_Base.json +149 -0
- package/artifacts/contracts/interfaces/0.8.x/IGenArt721CoreContractV3_Engine.sol/IGenArt721CoreContractV3_Engine.json +130 -0
- package/artifacts/contracts/interfaces/0.8.x/IGenArt721CoreContractV3_Engine_Flex.sol/IGenArt721CoreContractV3_Engine_Flex.json +1066 -0
- package/artifacts/contracts/interfaces/0.8.x/IMinterFilterV0.sol/IMinterFilterV0.json +6 -0
- package/artifacts/contracts/interfaces/0.8.x/IRandomizerPolyptychV0.sol/IRandomizerPolyptychV0.json +87 -0
- package/artifacts/contracts/interfaces/0.8.x/IRandomizerV2.sol/IRandomizerV2.json +1 -1
- package/artifacts/contracts/interfaces/0.8.x/IWETH.sol/IWETH.json +55 -0
- package/artifacts/contracts/libs/integration-refs/weth9/weth9.sol/WETH9_.json +295 -0
- package/artifacts/contracts/minter-suite/MinterFilter/MinterFilterV0.sol/MinterFilterV0.json +8 -2
- package/artifacts/contracts/minter-suite/MinterFilter/MinterFilterV1.sol/MinterFilterV1.json +34 -2
- package/artifacts/contracts/minter-suite/Minters/MinterDAExpSettlementV2.sol/MinterDAExpSettlementV2.json +1127 -0
- package/artifacts/contracts/minter-suite/Minters/MinterDAExpV4.sol/MinterDAExpV4.json +15 -2
- package/artifacts/contracts/minter-suite/Minters/MinterDALinV4.sol/MinterDALinV4.json +15 -2
- package/artifacts/contracts/minter-suite/Minters/MinterHolderV4.sol/MinterHolderV4.json +15 -2
- package/artifacts/contracts/minter-suite/Minters/MinterMerkleV5.sol/MinterMerkleV5.json +15 -2
- package/artifacts/contracts/minter-suite/Minters/MinterPolyptychV0.sol/IGenArt721CoreContractV3WithRandomizer.json +792 -0
- package/artifacts/contracts/minter-suite/Minters/MinterPolyptychV0.sol/MinterPolyptychV0.json +1268 -0
- package/artifacts/contracts/minter-suite/Minters/MinterSEAV0.sol/MinterSEAV0.json +1310 -0
- package/artifacts/contracts/minter-suite/Minters/MinterSetPriceERC20V4.sol/MinterSetPriceERC20V4.json +15 -2
- package/artifacts/contracts/minter-suite/Minters/MinterSetPriceV4.sol/MinterSetPriceV4.json +15 -2
- package/artifacts/contracts/mock/DeadReceiverBidderMock.sol/DeadReceiverBidderMock.json +33 -0
- package/artifacts/contracts/mock/GasLimitReceiverBidderMock.sol/GasLimitReceiverBidderMock.json +46 -0
- package/artifacts/contracts/mock/GasLimitReceiverMock.sol/GasLimitReceiverMock.json +28 -0
- package/artifacts/contracts/mock/GenArt721CoreV3_Engine_IncorrectCoreType.sol/GenArt721CoreV3_Engine_IncorrectCoreType.json +2 -2
- package/artifacts/contracts/mock/RandomizerV2_NoAssignMock.sol/RandomizerV2_NoAssignMock.json +3 -3
- package/artifacts/contracts/mock/ReentrancySEAMock.sol/ReentrancySEAAutoBidderMock.json +51 -0
- package/artifacts/contracts/{BasicRandomizer.sol → randomizer/BasicRandomizer.sol}/BasicRandomizer.json +3 -3
- package/artifacts/contracts/randomizer/BasicRandomizerBase_v0_0_0.sol/RandomizerBase.json +10 -0
- package/artifacts/contracts/randomizer/PolyptychRandomizerV0.sol/BasicPolyptychRandomizerV0.json +229 -0
- package/artifacts/contracts/randomizer/RandomizerV2.sol/BasicRandomizerV2.json +102 -0
- package/artifacts/contracts/royalty-registry/GenArt721RoyaltyOverride.sol/GenArt721RoyaltyOverride.json +2 -2
- package/contracts/DependencyRegistryV0.sol +74 -113
- package/contracts/GenArt721CoreV3.sol +124 -171
- package/contracts/GenArt721CoreV3_Engine.sol +136 -198
- package/contracts/GenArt721CoreV3_Engine_Flex.sol +2274 -0
- package/contracts/{minter-suite/Minters → archive/minter-suite/Minters/MinterDAExpSettlement}/MinterDAExpSettlementV1.sol +4 -4
- package/contracts/explorations/GenArt721CoreV3_Explorations.sol +147 -176
- package/contracts/interfaces/0.8.x/IFilteredMinterDAExpSettlementV1.sol +21 -0
- package/contracts/interfaces/0.8.x/IFilteredMinterSEAV0.sol +145 -0
- package/contracts/interfaces/0.8.x/IGenArt721CoreContractV3_Base.sol +39 -0
- package/contracts/interfaces/0.8.x/IGenArt721CoreContractV3_Engine.sol +0 -3
- package/contracts/interfaces/0.8.x/IGenArt721CoreContractV3_Engine_Flex.sol +132 -0
- package/contracts/interfaces/0.8.x/IMinterFilterV0.sol +6 -0
- package/contracts/interfaces/0.8.x/IRandomizerPolyptychV0.sol +31 -0
- package/contracts/interfaces/0.8.x/IRandomizerV2.sol +5 -2
- package/contracts/interfaces/0.8.x/IWETH.sol +11 -0
- package/contracts/libs/integration-refs/weth9/weth9.sol +763 -0
- package/contracts/minter-suite/MinterFilter/MinterFilterV1.sol +53 -47
- package/contracts/minter-suite/Minters/MinterDAExpSettlementV2.sol +1304 -0
- package/contracts/minter-suite/Minters/MinterDAExpV4.sol +47 -24
- package/contracts/minter-suite/Minters/MinterDALinV4.sol +46 -21
- package/contracts/minter-suite/Minters/MinterHolderV4.sol +54 -25
- package/contracts/minter-suite/Minters/MinterMerkleV5.sol +47 -20
- package/contracts/minter-suite/Minters/MinterPolyptychV0.sol +998 -0
- package/contracts/minter-suite/Minters/MinterSEAV0.sol +1224 -0
- package/contracts/minter-suite/Minters/MinterSetPriceERC20V4.sol +45 -16
- package/contracts/minter-suite/Minters/MinterSetPriceV4.sol +40 -13
- package/contracts/mock/DeadReceiverBidderMock.sol +23 -0
- package/contracts/mock/GasLimitReceiverBidderMock.sol +23 -0
- package/contracts/mock/GasLimitReceiverMock.sol +19 -0
- package/contracts/mock/RandomizerV2_NoAssignMock.sol +2 -11
- package/contracts/mock/ReentrancySEAMock.sol +36 -0
- package/contracts/{BasicRandomizer.sol → randomizer/BasicRandomizer.sol} +1 -1
- package/contracts/randomizer/BasicRandomizerBase_v0_0_0.sol +23 -0
- package/contracts/randomizer/PolyptychRandomizerV0.sol +117 -0
- package/contracts/{BasicRandomizerV2.sol → randomizer/RandomizerV2.sol} +7 -15
- package/package.json +32 -13
- package/artifacts/contracts/BasicRandomizerV2.sol/BasicRandomizerV2.json +0 -102
|
@@ -67,6 +67,9 @@ contract MinterDAExpV4 is ReentrancyGuard, MinterBase, IFilteredMinterDAExpV1 {
|
|
|
67
67
|
/// minterType for this minter
|
|
68
68
|
string public constant minterType = "MinterDAExpV4";
|
|
69
69
|
|
|
70
|
+
/// minter version for this minter
|
|
71
|
+
string public constant minterVersion = "v4.1.0";
|
|
72
|
+
|
|
70
73
|
uint256 constant ONE_MILLION = 1_000_000;
|
|
71
74
|
|
|
72
75
|
struct ProjectConfig {
|
|
@@ -88,9 +91,9 @@ contract MinterDAExpV4 is ReentrancyGuard, MinterBase, IFilteredMinterDAExpV1 {
|
|
|
88
91
|
/// more than this amount (may cut in half at no more than every N seconds).
|
|
89
92
|
uint256 public maximumPriceDecayHalfLifeSeconds = 3600; // 60 minutes
|
|
90
93
|
|
|
91
|
-
//
|
|
94
|
+
// function to restrict access to only AdminACL allowed calls
|
|
92
95
|
// @dev defers which ACL contract is used to the core contract
|
|
93
|
-
|
|
96
|
+
function _onlyCoreAdminACL(bytes4 _selector) internal {
|
|
94
97
|
require(
|
|
95
98
|
genArtCoreContract_Base.adminACLAllowed(
|
|
96
99
|
msg.sender,
|
|
@@ -99,16 +102,14 @@ contract MinterDAExpV4 is ReentrancyGuard, MinterBase, IFilteredMinterDAExpV1 {
|
|
|
99
102
|
),
|
|
100
103
|
"Only Core AdminACL allowed"
|
|
101
104
|
);
|
|
102
|
-
_;
|
|
103
105
|
}
|
|
104
106
|
|
|
105
|
-
|
|
107
|
+
function _onlyArtist(uint256 _projectId) internal view {
|
|
106
108
|
require(
|
|
107
109
|
(msg.sender ==
|
|
108
110
|
genArtCoreContract_Base.projectIdToArtistAddress(_projectId)),
|
|
109
111
|
"Only Artist"
|
|
110
112
|
);
|
|
111
|
-
_;
|
|
112
113
|
}
|
|
113
114
|
|
|
114
115
|
/**
|
|
@@ -145,9 +146,8 @@ contract MinterDAExpV4 is ReentrancyGuard, MinterBase, IFilteredMinterDAExpV1 {
|
|
|
145
146
|
* @dev this enables gas reduction after maxInvocations have been reached -
|
|
146
147
|
* core contracts shall still enforce a maxInvocation check during mint.
|
|
147
148
|
*/
|
|
148
|
-
function setProjectMaxInvocations(
|
|
149
|
-
|
|
150
|
-
) external onlyArtist(_projectId) {
|
|
149
|
+
function setProjectMaxInvocations(uint256 _projectId) public {
|
|
150
|
+
_onlyArtist(_projectId);
|
|
151
151
|
uint256 maxInvocations;
|
|
152
152
|
uint256 invocations;
|
|
153
153
|
(invocations, maxInvocations, , , , ) = genArtCoreContract_Base
|
|
@@ -180,7 +180,8 @@ contract MinterDAExpV4 is ReentrancyGuard, MinterBase, IFilteredMinterDAExpV1 {
|
|
|
180
180
|
function manuallyLimitProjectMaxInvocations(
|
|
181
181
|
uint256 _projectId,
|
|
182
182
|
uint256 _maxInvocations
|
|
183
|
-
) external
|
|
183
|
+
) external {
|
|
184
|
+
_onlyArtist(_projectId);
|
|
184
185
|
// CHECKS
|
|
185
186
|
// ensure that the manually set maxInvocations is not greater than what is set on the core contract
|
|
186
187
|
uint256 maxInvocations;
|
|
@@ -210,9 +211,8 @@ contract MinterDAExpV4 is ReentrancyGuard, MinterBase, IFilteredMinterDAExpV1 {
|
|
|
210
211
|
* @notice Warning: Disabling purchaseTo is not supported on this minter.
|
|
211
212
|
* This method exists purely for interface-conformance purposes.
|
|
212
213
|
*/
|
|
213
|
-
function togglePurchaseToDisabled(
|
|
214
|
-
|
|
215
|
-
) external view onlyArtist(_projectId) {
|
|
214
|
+
function togglePurchaseToDisabled(uint256 _projectId) external view {
|
|
215
|
+
_onlyArtist(_projectId);
|
|
216
216
|
revert("Action not supported");
|
|
217
217
|
}
|
|
218
218
|
|
|
@@ -295,12 +295,10 @@ contract MinterDAExpV4 is ReentrancyGuard, MinterBase, IFilteredMinterDAExpV1 {
|
|
|
295
295
|
function setAllowablePriceDecayHalfLifeRangeSeconds(
|
|
296
296
|
uint256 _minimumPriceDecayHalfLifeSeconds,
|
|
297
297
|
uint256 _maximumPriceDecayHalfLifeSeconds
|
|
298
|
-
)
|
|
299
|
-
|
|
300
|
-
onlyCoreAdminACL(
|
|
298
|
+
) external {
|
|
299
|
+
_onlyCoreAdminACL(
|
|
301
300
|
this.setAllowablePriceDecayHalfLifeRangeSeconds.selector
|
|
302
|
-
)
|
|
303
|
-
{
|
|
301
|
+
);
|
|
304
302
|
require(
|
|
305
303
|
_maximumPriceDecayHalfLifeSeconds >
|
|
306
304
|
_minimumPriceDecayHalfLifeSeconds,
|
|
@@ -336,7 +334,8 @@ contract MinterDAExpV4 is ReentrancyGuard, MinterBase, IFilteredMinterDAExpV1 {
|
|
|
336
334
|
uint256 _priceDecayHalfLifeSeconds,
|
|
337
335
|
uint256 _startPrice,
|
|
338
336
|
uint256 _basePrice
|
|
339
|
-
) external
|
|
337
|
+
) external {
|
|
338
|
+
_onlyArtist(_projectId);
|
|
340
339
|
// CHECKS
|
|
341
340
|
ProjectConfig storage _projectConfig = projectConfig[_projectId];
|
|
342
341
|
require(
|
|
@@ -372,6 +371,16 @@ contract MinterDAExpV4 is ReentrancyGuard, MinterBase, IFilteredMinterDAExpV1 {
|
|
|
372
371
|
_startPrice,
|
|
373
372
|
_basePrice
|
|
374
373
|
);
|
|
374
|
+
|
|
375
|
+
// sync local max invocations if not initially populated
|
|
376
|
+
// @dev if local max invocations and maxHasBeenInvoked are both
|
|
377
|
+
// initial values, we know they have not been populated.
|
|
378
|
+
if (
|
|
379
|
+
_projectConfig.maxInvocations == 0 &&
|
|
380
|
+
_projectConfig.maxHasBeenInvoked == false
|
|
381
|
+
) {
|
|
382
|
+
setProjectMaxInvocations(_projectId);
|
|
383
|
+
}
|
|
375
384
|
}
|
|
376
385
|
|
|
377
386
|
/**
|
|
@@ -380,9 +389,8 @@ contract MinterDAExpV4 is ReentrancyGuard, MinterBase, IFilteredMinterDAExpV1 {
|
|
|
380
389
|
* operation, but rather only in case of the need to halt an auction.
|
|
381
390
|
* @param _projectId Project ID to set auction details for.
|
|
382
391
|
*/
|
|
383
|
-
function resetAuctionDetails(
|
|
384
|
-
|
|
385
|
-
) external onlyCoreAdminACL(this.resetAuctionDetails.selector) {
|
|
392
|
+
function resetAuctionDetails(uint256 _projectId) external {
|
|
393
|
+
_onlyCoreAdminACL(this.resetAuctionDetails.selector);
|
|
386
394
|
ProjectConfig storage _projectConfig = projectConfig[_projectId];
|
|
387
395
|
// reset to initial values
|
|
388
396
|
_projectConfig.timestampStart = 0;
|
|
@@ -460,10 +468,25 @@ contract MinterDAExpV4 is ReentrancyGuard, MinterBase, IFilteredMinterDAExpV1 {
|
|
|
460
468
|
// EFFECTS
|
|
461
469
|
tokenId = minterFilter.mint(_to, _projectId, msg.sender);
|
|
462
470
|
|
|
463
|
-
//
|
|
464
|
-
//
|
|
471
|
+
// invocation is token number plus one, and will never overflow due to
|
|
472
|
+
// limit of 1e6 invocations per project. block scope for gas efficiency
|
|
473
|
+
// (i.e. avoid an unnecessary var initialization to 0).
|
|
465
474
|
unchecked {
|
|
466
|
-
|
|
475
|
+
uint256 tokenInvocation = (tokenId % ONE_MILLION) + 1;
|
|
476
|
+
uint256 localMaxInvocations = _projectConfig.maxInvocations;
|
|
477
|
+
// handle the case where the token invocation == minter local max
|
|
478
|
+
// invocations occurred on a different minter, and we have a stale
|
|
479
|
+
// local maxHasBeenInvoked value returning a false negative.
|
|
480
|
+
// @dev this is a CHECK after EFFECTS, so security was considered
|
|
481
|
+
// in detail here.
|
|
482
|
+
require(
|
|
483
|
+
tokenInvocation <= localMaxInvocations,
|
|
484
|
+
"Maximum invocations reached"
|
|
485
|
+
);
|
|
486
|
+
// in typical case, update the local maxHasBeenInvoked value
|
|
487
|
+
// to true if the token invocation == minter local max invocations
|
|
488
|
+
// (enables gas efficient reverts after sellout)
|
|
489
|
+
if (tokenInvocation == localMaxInvocations) {
|
|
467
490
|
_projectConfig.maxHasBeenInvoked = true;
|
|
468
491
|
}
|
|
469
492
|
}
|
|
@@ -67,6 +67,9 @@ contract MinterDALinV4 is ReentrancyGuard, MinterBase, IFilteredMinterDALinV1 {
|
|
|
67
67
|
/// minterType for this minter
|
|
68
68
|
string public constant minterType = "MinterDALinV4";
|
|
69
69
|
|
|
70
|
+
/// minter version for this minter
|
|
71
|
+
string public constant minterVersion = "v4.1.0";
|
|
72
|
+
|
|
70
73
|
uint256 constant ONE_MILLION = 1_000_000;
|
|
71
74
|
|
|
72
75
|
struct ProjectConfig {
|
|
@@ -84,9 +87,9 @@ contract MinterDALinV4 is ReentrancyGuard, MinterBase, IFilteredMinterDALinV1 {
|
|
|
84
87
|
/// Minimum auction length in seconds
|
|
85
88
|
uint256 public minimumAuctionLengthSeconds = 3600;
|
|
86
89
|
|
|
87
|
-
//
|
|
90
|
+
// function to restrict access to only AdminACL allowed calls
|
|
88
91
|
// @dev defers which ACL contract is used to the core contract
|
|
89
|
-
|
|
92
|
+
function _onlyCoreAdminACL(bytes4 _selector) internal {
|
|
90
93
|
require(
|
|
91
94
|
genArtCoreContract_Base.adminACLAllowed(
|
|
92
95
|
msg.sender,
|
|
@@ -95,16 +98,14 @@ contract MinterDALinV4 is ReentrancyGuard, MinterBase, IFilteredMinterDALinV1 {
|
|
|
95
98
|
),
|
|
96
99
|
"Only Core AdminACL allowed"
|
|
97
100
|
);
|
|
98
|
-
_;
|
|
99
101
|
}
|
|
100
102
|
|
|
101
|
-
|
|
103
|
+
function _onlyArtist(uint256 _projectId) internal view {
|
|
102
104
|
require(
|
|
103
105
|
(msg.sender ==
|
|
104
106
|
genArtCoreContract_Base.projectIdToArtistAddress(_projectId)),
|
|
105
107
|
"Only Artist"
|
|
106
108
|
);
|
|
107
|
-
_;
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
/**
|
|
@@ -141,9 +142,8 @@ contract MinterDALinV4 is ReentrancyGuard, MinterBase, IFilteredMinterDALinV1 {
|
|
|
141
142
|
* @dev this enables gas reduction after maxInvocations have been reached -
|
|
142
143
|
* core contracts shall still enforce a maxInvocation check during mint.
|
|
143
144
|
*/
|
|
144
|
-
function setProjectMaxInvocations(
|
|
145
|
-
|
|
146
|
-
) external onlyArtist(_projectId) {
|
|
145
|
+
function setProjectMaxInvocations(uint256 _projectId) public {
|
|
146
|
+
_onlyArtist(_projectId);
|
|
147
147
|
uint256 maxInvocations;
|
|
148
148
|
uint256 invocations;
|
|
149
149
|
(invocations, maxInvocations, , , , ) = genArtCoreContract_Base
|
|
@@ -175,7 +175,8 @@ contract MinterDALinV4 is ReentrancyGuard, MinterBase, IFilteredMinterDALinV1 {
|
|
|
175
175
|
function manuallyLimitProjectMaxInvocations(
|
|
176
176
|
uint256 _projectId,
|
|
177
177
|
uint256 _maxInvocations
|
|
178
|
-
) external
|
|
178
|
+
) external {
|
|
179
|
+
_onlyArtist(_projectId);
|
|
179
180
|
// CHECKS
|
|
180
181
|
// ensure that the manually set maxInvocations is not greater than what is set on the core contract
|
|
181
182
|
uint256 maxInvocations;
|
|
@@ -204,9 +205,8 @@ contract MinterDALinV4 is ReentrancyGuard, MinterBase, IFilteredMinterDALinV1 {
|
|
|
204
205
|
* @notice Warning: Disabling purchaseTo is not supported on this minter.
|
|
205
206
|
* This method exists purely for interface-conformance purposes.
|
|
206
207
|
*/
|
|
207
|
-
function togglePurchaseToDisabled(
|
|
208
|
-
|
|
209
|
-
) external view onlyArtist(_projectId) {
|
|
208
|
+
function togglePurchaseToDisabled(uint256 _projectId) external view {
|
|
209
|
+
_onlyArtist(_projectId);
|
|
210
210
|
revert("Action not supported");
|
|
211
211
|
}
|
|
212
212
|
|
|
@@ -284,7 +284,8 @@ contract MinterDALinV4 is ReentrancyGuard, MinterBase, IFilteredMinterDALinV1 {
|
|
|
284
284
|
*/
|
|
285
285
|
function setMinimumAuctionLengthSeconds(
|
|
286
286
|
uint256 _minimumAuctionLengthSeconds
|
|
287
|
-
) external
|
|
287
|
+
) external {
|
|
288
|
+
_onlyCoreAdminACL(this.setMinimumAuctionLengthSeconds.selector);
|
|
288
289
|
minimumAuctionLengthSeconds = _minimumAuctionLengthSeconds;
|
|
289
290
|
emit MinimumAuctionLengthSecondsUpdated(_minimumAuctionLengthSeconds);
|
|
290
291
|
}
|
|
@@ -306,7 +307,8 @@ contract MinterDALinV4 is ReentrancyGuard, MinterBase, IFilteredMinterDALinV1 {
|
|
|
306
307
|
uint256 _auctionTimestampEnd,
|
|
307
308
|
uint256 _startPrice,
|
|
308
309
|
uint256 _basePrice
|
|
309
|
-
) external
|
|
310
|
+
) external {
|
|
311
|
+
_onlyArtist(_projectId);
|
|
310
312
|
// CHECKS
|
|
311
313
|
ProjectConfig storage _projectConfig = projectConfig[_projectId];
|
|
312
314
|
require(
|
|
@@ -343,6 +345,16 @@ contract MinterDALinV4 is ReentrancyGuard, MinterBase, IFilteredMinterDALinV1 {
|
|
|
343
345
|
_startPrice,
|
|
344
346
|
_basePrice
|
|
345
347
|
);
|
|
348
|
+
|
|
349
|
+
// sync local max invocations if not initially populated
|
|
350
|
+
// @dev if local max invocations and maxHasBeenInvoked are both
|
|
351
|
+
// initial values, we know they have not been populated.
|
|
352
|
+
if (
|
|
353
|
+
_projectConfig.maxInvocations == 0 &&
|
|
354
|
+
_projectConfig.maxHasBeenInvoked == false
|
|
355
|
+
) {
|
|
356
|
+
setProjectMaxInvocations(_projectId);
|
|
357
|
+
}
|
|
346
358
|
}
|
|
347
359
|
|
|
348
360
|
/**
|
|
@@ -351,9 +363,8 @@ contract MinterDALinV4 is ReentrancyGuard, MinterBase, IFilteredMinterDALinV1 {
|
|
|
351
363
|
* operation, but rather only in case of the need to halt an auction.
|
|
352
364
|
* @param _projectId Project ID to set auction details for.
|
|
353
365
|
*/
|
|
354
|
-
function resetAuctionDetails(
|
|
355
|
-
|
|
356
|
-
) external onlyCoreAdminACL(this.resetAuctionDetails.selector) {
|
|
366
|
+
function resetAuctionDetails(uint256 _projectId) external {
|
|
367
|
+
_onlyCoreAdminACL(this.resetAuctionDetails.selector);
|
|
357
368
|
ProjectConfig storage _projectConfig = projectConfig[_projectId];
|
|
358
369
|
// reset to initial values
|
|
359
370
|
_projectConfig.timestampStart = 0;
|
|
@@ -430,11 +441,25 @@ contract MinterDALinV4 is ReentrancyGuard, MinterBase, IFilteredMinterDALinV1 {
|
|
|
430
441
|
|
|
431
442
|
// EFFECTS
|
|
432
443
|
tokenId = minterFilter.mint(_to, _projectId, msg.sender);
|
|
433
|
-
|
|
434
|
-
//
|
|
435
|
-
//
|
|
444
|
+
// invocation is token number plus one, and will never overflow due to
|
|
445
|
+
// limit of 1e6 invocations per project. block scope for gas efficiency
|
|
446
|
+
// (i.e. avoid an unnecessary var initialization to 0).
|
|
436
447
|
unchecked {
|
|
437
|
-
|
|
448
|
+
uint256 tokenInvocation = (tokenId % ONE_MILLION) + 1;
|
|
449
|
+
uint256 localMaxInvocations = _projectConfig.maxInvocations;
|
|
450
|
+
// handle the case where the token invocation == minter local max
|
|
451
|
+
// invocations occurred on a different minter, and we have a stale
|
|
452
|
+
// local maxHasBeenInvoked value returning a false negative.
|
|
453
|
+
// @dev this is a CHECK after EFFECTS, so security was considered
|
|
454
|
+
// in detail here.
|
|
455
|
+
require(
|
|
456
|
+
tokenInvocation <= localMaxInvocations,
|
|
457
|
+
"Maximum invocations reached"
|
|
458
|
+
);
|
|
459
|
+
// in typical case, update the local maxHasBeenInvoked value
|
|
460
|
+
// to true if the token invocation == minter local max invocations
|
|
461
|
+
// (enables gas efficient reverts after sellout)
|
|
462
|
+
if (tokenInvocation == localMaxInvocations) {
|
|
438
463
|
_projectConfig.maxHasBeenInvoked = true;
|
|
439
464
|
}
|
|
440
465
|
}
|
|
@@ -89,6 +89,9 @@ contract MinterHolderV4 is
|
|
|
89
89
|
/// minterType for this minter
|
|
90
90
|
string public constant minterType = "MinterHolderV4";
|
|
91
91
|
|
|
92
|
+
/// minter version for this minter
|
|
93
|
+
string public constant minterVersion = "v4.1.0";
|
|
94
|
+
|
|
92
95
|
uint256 constant ONE_MILLION = 1_000_000;
|
|
93
96
|
|
|
94
97
|
struct ProjectConfig {
|
|
@@ -110,9 +113,9 @@ contract MinterHolderV4 is
|
|
|
110
113
|
mapping(uint256 => mapping(address => mapping(uint256 => bool)))
|
|
111
114
|
public allowedProjectHolders;
|
|
112
115
|
|
|
113
|
-
//
|
|
116
|
+
// function to restrict access to only AdminACL allowed calls
|
|
114
117
|
// @dev defers which ACL contract is used to the core contract
|
|
115
|
-
|
|
118
|
+
function _onlyCoreAdminACL(bytes4 _selector) internal {
|
|
116
119
|
require(
|
|
117
120
|
genArtCoreContract_Base.adminACLAllowed(
|
|
118
121
|
msg.sender,
|
|
@@ -121,16 +124,14 @@ contract MinterHolderV4 is
|
|
|
121
124
|
),
|
|
122
125
|
"Only Core AdminACL allowed"
|
|
123
126
|
);
|
|
124
|
-
_;
|
|
125
127
|
}
|
|
126
128
|
|
|
127
|
-
|
|
129
|
+
function _onlyArtist(uint256 _projectId) internal view {
|
|
128
130
|
require(
|
|
129
131
|
msg.sender ==
|
|
130
132
|
genArtCoreContract_Base.projectIdToArtistAddress(_projectId),
|
|
131
133
|
"Only Artist"
|
|
132
134
|
);
|
|
133
|
-
_;
|
|
134
135
|
}
|
|
135
136
|
|
|
136
137
|
/**
|
|
@@ -174,9 +175,8 @@ contract MinterHolderV4 is
|
|
|
174
175
|
* `projectId = tokenId / 1_000_000`
|
|
175
176
|
* @param _NFTAddress NFT core address to be registered.
|
|
176
177
|
*/
|
|
177
|
-
function registerNFTAddress(
|
|
178
|
-
|
|
179
|
-
) external onlyCoreAdminACL(this.registerNFTAddress.selector) {
|
|
178
|
+
function registerNFTAddress(address _NFTAddress) external {
|
|
179
|
+
_onlyCoreAdminACL(this.registerNFTAddress.selector);
|
|
180
180
|
_registeredNFTAddresses.add(_NFTAddress);
|
|
181
181
|
emit RegisteredNFTAddress(_NFTAddress);
|
|
182
182
|
}
|
|
@@ -187,9 +187,8 @@ contract MinterHolderV4 is
|
|
|
187
187
|
* considered for adding to future allowlists.
|
|
188
188
|
* @param _NFTAddress NFT core address to be unregistered.
|
|
189
189
|
*/
|
|
190
|
-
function unregisterNFTAddress(
|
|
191
|
-
|
|
192
|
-
) external onlyCoreAdminACL(this.unregisterNFTAddress.selector) {
|
|
190
|
+
function unregisterNFTAddress(address _NFTAddress) external {
|
|
191
|
+
_onlyCoreAdminACL(this.unregisterNFTAddress.selector);
|
|
193
192
|
_registeredNFTAddresses.remove(_NFTAddress);
|
|
194
193
|
emit UnregisteredNFTAddress(_NFTAddress);
|
|
195
194
|
}
|
|
@@ -211,7 +210,8 @@ contract MinterHolderV4 is
|
|
|
211
210
|
uint256 _projectId,
|
|
212
211
|
address[] memory _ownedNFTAddresses,
|
|
213
212
|
uint256[] memory _ownedNFTProjectIds
|
|
214
|
-
) public
|
|
213
|
+
) public {
|
|
214
|
+
_onlyArtist(_projectId);
|
|
215
215
|
// require same length arrays
|
|
216
216
|
require(
|
|
217
217
|
_ownedNFTAddresses.length == _ownedNFTProjectIds.length,
|
|
@@ -256,7 +256,8 @@ contract MinterHolderV4 is
|
|
|
256
256
|
uint256 _projectId,
|
|
257
257
|
address[] memory _ownedNFTAddresses,
|
|
258
258
|
uint256[] memory _ownedNFTProjectIds
|
|
259
|
-
) public
|
|
259
|
+
) public {
|
|
260
|
+
_onlyArtist(_projectId);
|
|
260
261
|
// require same length arrays
|
|
261
262
|
require(
|
|
262
263
|
_ownedNFTAddresses.length == _ownedNFTProjectIds.length,
|
|
@@ -311,7 +312,8 @@ contract MinterHolderV4 is
|
|
|
311
312
|
uint256[] memory _ownedNFTProjectIdsAdd,
|
|
312
313
|
address[] memory _ownedNFTAddressesRemove,
|
|
313
314
|
uint256[] memory _ownedNFTProjectIdsRemove
|
|
314
|
-
) external
|
|
315
|
+
) external {
|
|
316
|
+
_onlyArtist(_projectId);
|
|
315
317
|
allowHoldersOfProjects(
|
|
316
318
|
_projectId,
|
|
317
319
|
_ownedNFTAddressesAdd,
|
|
@@ -352,7 +354,7 @@ contract MinterHolderV4 is
|
|
|
352
354
|
* @dev this enables gas reduction after maxInvocations have been reached -
|
|
353
355
|
* core contracts shall still enforce a maxInvocation check during mint.
|
|
354
356
|
*/
|
|
355
|
-
function setProjectMaxInvocations(uint256 _projectId)
|
|
357
|
+
function setProjectMaxInvocations(uint256 _projectId) public {
|
|
356
358
|
uint256 maxInvocations;
|
|
357
359
|
uint256 invocations;
|
|
358
360
|
(invocations, maxInvocations, , , , ) = genArtCoreContract_Base
|
|
@@ -384,7 +386,8 @@ contract MinterHolderV4 is
|
|
|
384
386
|
function manuallyLimitProjectMaxInvocations(
|
|
385
387
|
uint256 _projectId,
|
|
386
388
|
uint256 _maxInvocations
|
|
387
|
-
) external
|
|
389
|
+
) external {
|
|
390
|
+
_onlyArtist(_projectId);
|
|
388
391
|
// CHECKS
|
|
389
392
|
// ensure that the manually set maxInvocations is not greater than what is set on the core contract
|
|
390
393
|
uint256 maxInvocations;
|
|
@@ -415,9 +418,8 @@ contract MinterHolderV4 is
|
|
|
415
418
|
* @notice Warning: Disabling purchaseTo is not supported on this minter.
|
|
416
419
|
* This method exists purely for interface-conformance purposes.
|
|
417
420
|
*/
|
|
418
|
-
function togglePurchaseToDisabled(
|
|
419
|
-
|
|
420
|
-
) external view onlyArtist(_projectId) {
|
|
421
|
+
function togglePurchaseToDisabled(uint256 _projectId) external view {
|
|
422
|
+
_onlyArtist(_projectId);
|
|
421
423
|
revert("Action not supported");
|
|
422
424
|
}
|
|
423
425
|
|
|
@@ -474,10 +476,22 @@ contract MinterHolderV4 is
|
|
|
474
476
|
function updatePricePerTokenInWei(
|
|
475
477
|
uint256 _projectId,
|
|
476
478
|
uint256 _pricePerTokenInWei
|
|
477
|
-
) external
|
|
478
|
-
|
|
479
|
-
projectConfig[_projectId]
|
|
479
|
+
) external {
|
|
480
|
+
_onlyArtist(_projectId);
|
|
481
|
+
ProjectConfig storage _projectConfig = projectConfig[_projectId];
|
|
482
|
+
_projectConfig.pricePerTokenInWei = _pricePerTokenInWei;
|
|
483
|
+
_projectConfig.priceIsConfigured = true;
|
|
480
484
|
emit PricePerTokenInWeiUpdated(_projectId, _pricePerTokenInWei);
|
|
485
|
+
|
|
486
|
+
// sync local max invocations if not initially populated
|
|
487
|
+
// @dev if local max invocations and maxHasBeenInvoked are both
|
|
488
|
+
// initial values, we know they have not been populated.
|
|
489
|
+
if (
|
|
490
|
+
_projectConfig.maxInvocations == 0 &&
|
|
491
|
+
_projectConfig.maxHasBeenInvoked == false
|
|
492
|
+
) {
|
|
493
|
+
setProjectMaxInvocations(_projectId);
|
|
494
|
+
}
|
|
481
495
|
}
|
|
482
496
|
|
|
483
497
|
/**
|
|
@@ -669,10 +683,25 @@ contract MinterHolderV4 is
|
|
|
669
683
|
|
|
670
684
|
// NOTE: delegate-vault handling **ends here**.
|
|
671
685
|
|
|
672
|
-
//
|
|
673
|
-
//
|
|
686
|
+
// invocation is token number plus one, and will never overflow due to
|
|
687
|
+
// limit of 1e6 invocations per project. block scope for gas efficiency
|
|
688
|
+
// (i.e. avoid an unnecessary var initialization to 0).
|
|
674
689
|
unchecked {
|
|
675
|
-
|
|
690
|
+
uint256 tokenInvocation = (tokenId % ONE_MILLION) + 1;
|
|
691
|
+
uint256 localMaxInvocations = _projectConfig.maxInvocations;
|
|
692
|
+
// handle the case where the token invocation == minter local max
|
|
693
|
+
// invocations occurred on a different minter, and we have a stale
|
|
694
|
+
// local maxHasBeenInvoked value returning a false negative.
|
|
695
|
+
// @dev this is a CHECK after EFFECTS, so security was considered
|
|
696
|
+
// in detail here.
|
|
697
|
+
require(
|
|
698
|
+
tokenInvocation <= localMaxInvocations,
|
|
699
|
+
"Maximum invocations reached"
|
|
700
|
+
);
|
|
701
|
+
// in typical case, update the local maxHasBeenInvoked value
|
|
702
|
+
// to true if the token invocation == minter local max invocations
|
|
703
|
+
// (enables gas efficient reverts after sellout)
|
|
704
|
+
if (tokenInvocation == localMaxInvocations) {
|
|
676
705
|
_projectConfig.maxHasBeenInvoked = true;
|
|
677
706
|
}
|
|
678
707
|
}
|
|
@@ -79,6 +79,9 @@ contract MinterMerkleV5 is
|
|
|
79
79
|
/// minterType for this minter
|
|
80
80
|
string public constant minterType = "MinterMerkleV5";
|
|
81
81
|
|
|
82
|
+
/// minter version for this minter
|
|
83
|
+
string public constant minterVersion = "v5.1.0";
|
|
84
|
+
|
|
82
85
|
/// project minter configuration keys used by this minter
|
|
83
86
|
bytes32 private constant CONFIG_MERKLE_ROOT = "merkleRoot";
|
|
84
87
|
bytes32 private constant CONFIG_USE_MAX_INVOCATIONS_PER_ADDRESS_OVERRIDE =
|
|
@@ -112,13 +115,12 @@ contract MinterMerkleV5 is
|
|
|
112
115
|
mapping(uint256 => mapping(address => uint256))
|
|
113
116
|
public projectUserMintInvocations;
|
|
114
117
|
|
|
115
|
-
|
|
118
|
+
function _onlyArtist(uint256 _projectId) internal view {
|
|
116
119
|
require(
|
|
117
120
|
msg.sender ==
|
|
118
121
|
genArtCoreContract_Base.projectIdToArtistAddress(_projectId),
|
|
119
122
|
"Only Artist"
|
|
120
123
|
);
|
|
121
|
-
_;
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
/**
|
|
@@ -166,10 +168,8 @@ contract MinterMerkleV5 is
|
|
|
166
168
|
* @param _root root of Merkle tree defining addresses allowed to mint
|
|
167
169
|
* on project `_projectId`.
|
|
168
170
|
*/
|
|
169
|
-
function updateMerkleRoot(
|
|
170
|
-
|
|
171
|
-
bytes32 _root
|
|
172
|
-
) external onlyArtist(_projectId) {
|
|
171
|
+
function updateMerkleRoot(uint256 _projectId, bytes32 _root) external {
|
|
172
|
+
_onlyArtist(_projectId);
|
|
173
173
|
require(_root != bytes32(0), "Root must be provided");
|
|
174
174
|
projectMerkleRoot[_projectId] = _root;
|
|
175
175
|
emit ConfigValueSet(_projectId, CONFIG_MERKLE_ROOT, _root);
|
|
@@ -221,7 +221,8 @@ contract MinterMerkleV5 is
|
|
|
221
221
|
function setProjectInvocationsPerAddress(
|
|
222
222
|
uint256 _projectId,
|
|
223
223
|
uint24 _maxInvocationsPerAddress
|
|
224
|
-
) external
|
|
224
|
+
) external {
|
|
225
|
+
_onlyArtist(_projectId);
|
|
225
226
|
ProjectConfig storage _projectConfig = projectConfig[_projectId];
|
|
226
227
|
// use override value instead of the contract's default
|
|
227
228
|
// @dev this never changes from true to false; default value is only
|
|
@@ -250,9 +251,8 @@ contract MinterMerkleV5 is
|
|
|
250
251
|
* @dev this enables gas reduction after maxInvocations have been reached -
|
|
251
252
|
* core contracts shall still enforce a maxInvocation check during mint.
|
|
252
253
|
*/
|
|
253
|
-
function setProjectMaxInvocations(
|
|
254
|
-
|
|
255
|
-
) external onlyArtist(_projectId) {
|
|
254
|
+
function setProjectMaxInvocations(uint256 _projectId) public {
|
|
255
|
+
_onlyArtist(_projectId);
|
|
256
256
|
uint256 maxInvocations;
|
|
257
257
|
uint256 invocations;
|
|
258
258
|
(invocations, maxInvocations, , , , ) = genArtCoreContract_Base
|
|
@@ -284,7 +284,8 @@ contract MinterMerkleV5 is
|
|
|
284
284
|
function manuallyLimitProjectMaxInvocations(
|
|
285
285
|
uint256 _projectId,
|
|
286
286
|
uint256 _maxInvocations
|
|
287
|
-
) external
|
|
287
|
+
) external {
|
|
288
|
+
_onlyArtist(_projectId);
|
|
288
289
|
// CHECKS
|
|
289
290
|
// ensure that the manually set maxInvocations is not greater than what is set on the core contract
|
|
290
291
|
uint256 maxInvocations;
|
|
@@ -315,9 +316,8 @@ contract MinterMerkleV5 is
|
|
|
315
316
|
* @notice Warning: Disabling purchaseTo is not supported on this minter.
|
|
316
317
|
* This method exists purely for interface-conformance purposes.
|
|
317
318
|
*/
|
|
318
|
-
function togglePurchaseToDisabled(
|
|
319
|
-
|
|
320
|
-
) external view onlyArtist(_projectId) {
|
|
319
|
+
function togglePurchaseToDisabled(uint256 _projectId) external view {
|
|
320
|
+
_onlyArtist(_projectId);
|
|
321
321
|
revert("Action not supported");
|
|
322
322
|
}
|
|
323
323
|
|
|
@@ -374,10 +374,22 @@ contract MinterMerkleV5 is
|
|
|
374
374
|
function updatePricePerTokenInWei(
|
|
375
375
|
uint256 _projectId,
|
|
376
376
|
uint256 _pricePerTokenInWei
|
|
377
|
-
) external
|
|
378
|
-
|
|
379
|
-
projectConfig[_projectId]
|
|
377
|
+
) external {
|
|
378
|
+
_onlyArtist(_projectId);
|
|
379
|
+
ProjectConfig storage _projectConfig = projectConfig[_projectId];
|
|
380
|
+
_projectConfig.pricePerTokenInWei = _pricePerTokenInWei;
|
|
381
|
+
_projectConfig.priceIsConfigured = true;
|
|
380
382
|
emit PricePerTokenInWeiUpdated(_projectId, _pricePerTokenInWei);
|
|
383
|
+
|
|
384
|
+
// sync local max invocations if not initially populated
|
|
385
|
+
// @dev if local max invocations and maxHasBeenInvoked are both
|
|
386
|
+
// initial values, we know they have not been populated.
|
|
387
|
+
if (
|
|
388
|
+
_projectConfig.maxInvocations == 0 &&
|
|
389
|
+
_projectConfig.maxHasBeenInvoked == false
|
|
390
|
+
) {
|
|
391
|
+
setProjectMaxInvocations(_projectId);
|
|
392
|
+
}
|
|
381
393
|
}
|
|
382
394
|
|
|
383
395
|
/**
|
|
@@ -551,10 +563,25 @@ contract MinterMerkleV5 is
|
|
|
551
563
|
|
|
552
564
|
// NOTE: delegate-vault handling **ends here**.
|
|
553
565
|
|
|
554
|
-
//
|
|
555
|
-
//
|
|
566
|
+
// invocation is token number plus one, and will never overflow due to
|
|
567
|
+
// limit of 1e6 invocations per project. block scope for gas efficiency
|
|
568
|
+
// (i.e. avoid an unnecessary var initialization to 0).
|
|
556
569
|
unchecked {
|
|
557
|
-
|
|
570
|
+
uint256 tokenInvocation = (tokenId % ONE_MILLION) + 1;
|
|
571
|
+
uint256 localMaxInvocations = _projectConfig.maxInvocations;
|
|
572
|
+
// handle the case where the token invocation == minter local max
|
|
573
|
+
// invocations occurred on a different minter, and we have a stale
|
|
574
|
+
// local maxHasBeenInvoked value returning a false negative.
|
|
575
|
+
// @dev this is a CHECK after EFFECTS, so security was considered
|
|
576
|
+
// in detail here.
|
|
577
|
+
require(
|
|
578
|
+
tokenInvocation <= localMaxInvocations,
|
|
579
|
+
"Maximum invocations reached"
|
|
580
|
+
);
|
|
581
|
+
// in typical case, update the local maxHasBeenInvoked value
|
|
582
|
+
// to true if the token invocation == minter local max invocations
|
|
583
|
+
// (enables gas efficient reverts after sellout)
|
|
584
|
+
if (tokenInvocation == localMaxInvocations) {
|
|
558
585
|
_projectConfig.maxHasBeenInvoked = true;
|
|
559
586
|
}
|
|
560
587
|
}
|