@artblocks/contracts 1.0.4 → 1.1.0
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/README.md +2 -2
- package/artifacts/contracts/AdminACLV1.sol/AdminACLV1.json +2 -2
- package/artifacts/contracts/DependencyRegistryV0.sol/DependencyRegistryV0.json +97 -10
- package/artifacts/contracts/GenArt721CoreV3.sol/GenArt721CoreV3.json +4 -4
- package/artifacts/contracts/engine/V3/GenArt721CoreV3_Engine.sol/GenArt721CoreV3_Engine.json +4 -9
- package/artifacts/contracts/engine/V3/GenArt721CoreV3_Engine_Flex.sol/GenArt721CoreV3_Engine_Flex.json +4 -9
- package/artifacts/contracts/engine/V3/forks/GenArt721CoreV3_Engine_Flex_PROOF.sol/GenArt721CoreV3_Engine_Flex_PROOF.json +4 -9
- package/artifacts/contracts/engine/V3/forks/PROHIBITION/GenArt721CoreV3_Engine_Flex_PROHIBITION.sol/GenArt721CoreV3_Engine_Flex_PROHIBITION.json +4 -9
- package/artifacts/contracts/engine-registry/CoreRegistryV1.sol/CoreRegistryV1.json +12 -12
- package/artifacts/contracts/explorations/GenArt721CoreV3_Explorations.sol/GenArt721CoreV3_Explorations.json +4 -4
- package/artifacts/contracts/interfaces/v0.8.x/ICoreRegistryV1.sol/ICoreRegistryV1.json +6 -6
- package/artifacts/contracts/interfaces/v0.8.x/IDependencyRegistryV0.sol/IDependencyRegistryV0.json +19 -0
- package/artifacts/contracts/interfaces/v0.8.x/IMinterFilterV1.sol/IMinterFilterV1.json +22 -22
- package/artifacts/contracts/interfaces/v0.8.x/ISharedMinterDAExpSettlementV0.sol/ISharedMinterDAExpSettlementV0.json +8 -101
- package/artifacts/contracts/interfaces/v0.8.x/ISharedMinterDAExpV0.sol/ISharedMinterDAExpV0.json +1 -57
- package/artifacts/contracts/interfaces/v0.8.x/ISharedMinterDALinV0.sol/ISharedMinterDALinV0.json +1 -57
- package/artifacts/contracts/interfaces/v0.8.x/ISharedMinterDAV0.sol/ISharedMinterDAV0.json +2 -21
- package/artifacts/contracts/interfaces/v0.8.x/ISharedMinterHolderERC20V0.sol/ISharedMinterHolderERC20V0.json +158 -0
- package/artifacts/contracts/interfaces/v0.8.x/ISharedMinterHolderV0.sol/ISharedMinterHolderV0.json +15 -90
- package/artifacts/contracts/interfaces/v0.8.x/ISharedMinterMerkleV0.sol/ISharedMinterMerkleV0.json +10 -36
- package/artifacts/contracts/interfaces/v0.8.x/ISharedMinterSEAV0.sol/ISharedMinterSEAV0.json +4 -236
- package/artifacts/contracts/interfaces/v0.8.x/ISharedMinterSimplePurchaseV0.sol/ISharedMinterSimplePurchaseV0.json +5 -5
- package/artifacts/contracts/interfaces/v0.8.x/ISharedMinterV0.sol/ISharedMinterV0.json +7 -423
- package/artifacts/contracts/interfaces/v0.8.x/ISharedRandomizerV0.sol/ISharedRandomizerV0.json +17 -17
- package/artifacts/contracts/libs/v0.8.x/ABHelpers.sol/ABHelpers.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/AuthLib.sol/AuthLib.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/Bytes32Strings.sol/Bytes32Strings.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/minter-libs/DAExpLib.sol/DAExpLib.json +60 -3
- package/artifacts/contracts/libs/v0.8.x/minter-libs/DALib.sol/DALib.json +30 -0
- package/artifacts/contracts/libs/v0.8.x/minter-libs/DALinLib.sol/DALinLib.json +60 -3
- package/artifacts/contracts/libs/v0.8.x/minter-libs/GenericMinterEventsLib.sol/GenericMinterEventsLib.json +346 -0
- package/artifacts/contracts/libs/v0.8.x/minter-libs/MaxInvocationsLib.sol/MaxInvocationsLib.json +29 -3
- package/artifacts/contracts/libs/v0.8.x/minter-libs/MerkleLib.sol/MerkleLib.json +30 -3
- package/artifacts/contracts/libs/v0.8.x/minter-libs/PolyptychLib.sol/PolyptychLib.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/minter-libs/SEALib.sol/SEALib.json +254 -3
- package/artifacts/contracts/libs/v0.8.x/minter-libs/SetPriceLib.sol/SetPriceLib.json +48 -3
- package/artifacts/contracts/libs/v0.8.x/minter-libs/SettlementExpLib.sol/SettlementExpLib.json +41 -3
- package/artifacts/contracts/libs/v0.8.x/minter-libs/SplitFundsLib.sol/SplitFundsLib.json +35 -3
- package/artifacts/contracts/libs/v0.8.x/minter-libs/TokenHolderLib.sol/TokenHolderLib.json +79 -3
- package/artifacts/contracts/minter-suite/MinterFilter/MinterFilterV1.sol/MinterFilterV1.json +2 -2
- package/artifacts/contracts/minter-suite/MinterFilter/MinterFilterV2.sol/MinterFilterV2.json +41 -41
- package/artifacts/contracts/minter-suite/Minters/MinterDAExpHolderV5.sol/MinterDAExpHolderV5.json +66 -632
- package/artifacts/contracts/minter-suite/Minters/MinterDAExpSettlementV2.sol/MinterDAExpSettlementV2.json +2 -20
- package/artifacts/contracts/minter-suite/Minters/MinterDAExpSettlementV3.sol/MinterDAExpSettlementV3.json +67 -594
- package/artifacts/contracts/minter-suite/Minters/MinterDAExpV5.sol/MinterDAExpV5.json +33 -524
- package/artifacts/contracts/minter-suite/Minters/MinterDALinHolderV5.sol/MinterDALinHolderV5.json +66 -632
- package/artifacts/contracts/minter-suite/Minters/MinterDALinV5.sol/MinterDALinV5.json +33 -524
- package/artifacts/contracts/minter-suite/Minters/MinterSEAV1.sol/MinterSEAV1.json +51 -717
- package/artifacts/contracts/minter-suite/Minters/MinterSetPriceERC20V5.sol/MinterSetPriceERC20V5.json +58 -454
- package/artifacts/contracts/minter-suite/Minters/MinterSetPriceHolderV5.sol/MinterSetPriceHolderV5.json +61 -552
- package/artifacts/contracts/minter-suite/Minters/MinterSetPriceMerkleV5.sol/MinterSetPriceMerkleV5.json +55 -497
- package/artifacts/contracts/minter-suite/Minters/MinterSetPricePolyptychERC20V5.sol/MinterSetPricePolyptychERC20V5.json +110 -571
- package/artifacts/contracts/minter-suite/Minters/MinterSetPricePolyptychV5.sol/MinterSetPricePolyptychV5.json +69 -560
- package/artifacts/contracts/minter-suite/Minters/MinterSetPriceV5.sol/MinterSetPriceV5.json +28 -444
- package/artifacts/contracts/mock/DummySharedMinter.sol/DummySharedMinter.json +2 -2
- package/artifacts/contracts/mock/GenArt721CoreV3_Engine_IncorrectCoreType.sol/GenArt721CoreV3_Engine_IncorrectCoreType.json +4 -9
- package/artifacts/contracts/mock/OriginRegisterMock.sol/OriginRegisterMock.json +2 -2
- package/artifacts/contracts/mock/ReentrancyHolderMockShared.sol/ReentrancyHolderMockShared.json +136 -0
- package/artifacts/contracts/mock/ReentrancyMerkleMockShared.sol/ReentrancyMerkleMockShared.json +105 -0
- package/artifacts/contracts/mock/ReentrancyMockShared.sol/ReentrancyMockShared.json +100 -0
- package/artifacts/contracts/mock/ReentrancySEAMockShared.sol/ReentrancySEAAutoBidderMockShared.json +69 -0
- package/artifacts/contracts/randomizer/shared/SharedRandomizerV0.sol/SharedRandomizerV0.json +19 -19
- package/contracts/DependencyRegistryV0.sol +84 -16
- package/contracts/archive/readme.md +16 -0
- package/contracts/engine/README.md +21 -0
- package/contracts/engine/V3/GenArt721CoreV3_Engine.sol +4 -10
- package/contracts/engine/V3/GenArt721CoreV3_Engine_Flex.sol +4 -10
- package/contracts/engine/V3/forks/GenArt721CoreV3_Engine_Flex_PROOF.sol +4 -10
- package/contracts/engine/V3/forks/PROHIBITION/GenArt721CoreV3_Engine_Flex_PROHIBITION.sol +4 -10
- package/contracts/engine-registry/CoreRegistryV1.sol +58 -65
- package/contracts/interfaces/v0.8.x/ICoreRegistryV1.sol +6 -8
- package/contracts/interfaces/v0.8.x/IDependencyRegistryV0.sol +3 -0
- package/contracts/interfaces/v0.8.x/IMinterFilterV1.sol +25 -25
- package/contracts/interfaces/v0.8.x/ISharedMinterDAExpSettlementV0.sol +11 -20
- package/contracts/interfaces/v0.8.x/ISharedMinterDAExpV0.sol +1 -14
- package/contracts/interfaces/v0.8.x/ISharedMinterDALinV0.sol +1 -15
- package/contracts/interfaces/v0.8.x/ISharedMinterDAV0.sol +2 -8
- package/contracts/interfaces/v0.8.x/ISharedMinterHolderERC20V0.sol +47 -0
- package/contracts/interfaces/v0.8.x/ISharedMinterHolderV0.sol +15 -43
- package/contracts/interfaces/v0.8.x/ISharedMinterMerkleV0.sol +10 -20
- package/contracts/interfaces/v0.8.x/ISharedMinterSEAV0.sol +4 -67
- package/contracts/interfaces/v0.8.x/ISharedMinterSimplePurchaseV0.sol +5 -5
- package/contracts/interfaces/v0.8.x/ISharedMinterV0.sol +7 -155
- package/contracts/interfaces/v0.8.x/ISharedRandomizerV0.sol +37 -37
- package/contracts/libs/v0.8.x/ABHelpers.sol +14 -14
- package/contracts/libs/v0.8.x/AuthLib.sol +101 -102
- package/contracts/libs/v0.8.x/Bytes32Strings.sol +5 -5
- package/contracts/libs/v0.8.x/minter-libs/DAExpLib.sol +163 -38
- package/contracts/libs/v0.8.x/minter-libs/DALib.sol +26 -0
- package/contracts/libs/v0.8.x/minter-libs/DALinLib.sol +144 -37
- package/contracts/libs/v0.8.x/minter-libs/GenericMinterEventsLib.sol +171 -0
- package/contracts/libs/v0.8.x/minter-libs/MaxInvocationsLib.sol +250 -110
- package/contracts/libs/v0.8.x/minter-libs/MerkleLib.sol +257 -48
- package/contracts/libs/v0.8.x/minter-libs/PolyptychLib.sol +138 -58
- package/contracts/libs/v0.8.x/minter-libs/SEALib.sol +778 -103
- package/contracts/libs/v0.8.x/minter-libs/SetPriceLib.sol +135 -13
- package/contracts/libs/v0.8.x/minter-libs/SettlementExpLib.sol +567 -187
- package/contracts/libs/v0.8.x/minter-libs/SplitFundsLib.sol +480 -322
- package/contracts/libs/v0.8.x/minter-libs/TokenHolderLib.sol +214 -76
- package/contracts/minter-suite/MinterFilter/MinterFilterV2.sol +347 -304
- package/contracts/minter-suite/Minters/MinterDAExpHolderV5.sol +391 -491
- package/contracts/minter-suite/Minters/MinterDAExpSettlementV2.sol +1 -54
- package/contracts/minter-suite/Minters/MinterDAExpSettlementV3.sol +388 -628
- package/contracts/minter-suite/Minters/MinterDAExpV5.sol +212 -273
- package/contracts/minter-suite/Minters/MinterDALinHolderV5.sol +393 -488
- package/contracts/minter-suite/Minters/MinterDALinV5.sol +220 -277
- package/contracts/minter-suite/Minters/MinterSEAV1.sol +327 -664
- package/contracts/minter-suite/Minters/MinterSetPriceERC20V5.sol +278 -303
- package/contracts/minter-suite/Minters/MinterSetPriceHolderV5.sol +355 -446
- package/contracts/minter-suite/Minters/MinterSetPriceMerkleV5.sol +328 -416
- package/contracts/minter-suite/Minters/MinterSetPricePolyptychERC20V5.sol +538 -622
- package/contracts/minter-suite/Minters/MinterSetPricePolyptychV5.sol +429 -553
- package/contracts/minter-suite/Minters/MinterSetPriceV5.sol +180 -227
- package/contracts/mock/GenArt721CoreV3_Engine_IncorrectCoreType.sol +3 -10
- package/contracts/mock/ReentrancyHolderMockShared.sol +59 -0
- package/contracts/mock/ReentrancyMerkleMockShared.sol +58 -0
- package/contracts/mock/ReentrancyMockShared.sol +48 -0
- package/contracts/mock/ReentrancySEAMockShared.sol +40 -0
- package/contracts/randomizer/shared/SharedRandomizerV0.sol +78 -70
- package/package.json +39 -33
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
2
2
|
// Created By: Art Blocks Inc.
|
|
3
3
|
|
|
4
|
+
// @dev fixed to specific solidity version for clarity and for more clear
|
|
5
|
+
// source code verification purposes.
|
|
4
6
|
pragma solidity 0.8.19;
|
|
5
7
|
|
|
6
|
-
import "../../interfaces/v0.8.x/ISharedMinterV0.sol";
|
|
7
|
-
import "../../interfaces/v0.8.x/ISharedMinterSEAV0.sol";
|
|
8
|
-
import "../../interfaces/v0.8.x/IMinterFilterV1.sol";
|
|
8
|
+
import {ISharedMinterV0} from "../../interfaces/v0.8.x/ISharedMinterV0.sol";
|
|
9
|
+
import {ISharedMinterSEAV0} from "../../interfaces/v0.8.x/ISharedMinterSEAV0.sol";
|
|
10
|
+
import {IMinterFilterV1} from "../../interfaces/v0.8.x/IMinterFilterV1.sol";
|
|
9
11
|
|
|
10
|
-
import "../../libs/v0.8.x/ABHelpers.sol";
|
|
11
|
-
import "../../libs/v0.8.x/AuthLib.sol";
|
|
12
|
-
import "../../libs/v0.8.x/minter-libs/SEALib.sol";
|
|
13
|
-
import "../../libs/v0.8.x/minter-libs/SplitFundsLib.sol";
|
|
14
|
-
import "../../libs/v0.8.x/minter-libs/MaxInvocationsLib.sol";
|
|
12
|
+
import {ABHelpers} from "../../libs/v0.8.x/ABHelpers.sol";
|
|
13
|
+
import {AuthLib} from "../../libs/v0.8.x/AuthLib.sol";
|
|
14
|
+
import {SEALib} from "../../libs/v0.8.x/minter-libs/SEALib.sol";
|
|
15
|
+
import {SplitFundsLib} from "../../libs/v0.8.x/minter-libs/SplitFundsLib.sol";
|
|
16
|
+
import {MaxInvocationsLib} from "../../libs/v0.8.x/minter-libs/MaxInvocationsLib.sol";
|
|
15
17
|
|
|
16
|
-
import "@openzeppelin-4.7/contracts/
|
|
17
|
-
import "@openzeppelin-4.7/contracts/
|
|
18
|
-
import "@openzeppelin-4.7/contracts/utils/math/
|
|
19
|
-
import "@openzeppelin-4.7/contracts/utils/math/Math.sol";
|
|
18
|
+
import {ReentrancyGuard} from "@openzeppelin-4.7/contracts/security/ReentrancyGuard.sol";
|
|
19
|
+
import {SafeCast} from "@openzeppelin-4.7/contracts/utils/math/SafeCast.sol";
|
|
20
|
+
import {Math} from "@openzeppelin-4.7/contracts/utils/math/Math.sol";
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* @title Filtered Minter contract that allows tokens to be minted with ETH.
|
|
@@ -90,6 +91,13 @@ import "@openzeppelin-4.7/contracts/utils/math/Math.sol";
|
|
|
90
91
|
* ----------------------------------------------------------------------------
|
|
91
92
|
* Additional admin and artist privileged roles may be described on other
|
|
92
93
|
* contracts that this minter integrates with.
|
|
94
|
+
* ----------------------------------------------------------------------------
|
|
95
|
+
* @notice Caution: While Engine projects must be registered on the Art Blocks
|
|
96
|
+
* Core Registry to assign this minter, this minter does not enforce that a
|
|
97
|
+
* project is registered when configured or queried. This is primarily for gas
|
|
98
|
+
* optimization purposes. It is, therefore, possible that fake projects may be
|
|
99
|
+
* configured on this minter, but they will not be able to mint tokens due to
|
|
100
|
+
* checks performed by this minter's Minter Filter.
|
|
93
101
|
*
|
|
94
102
|
* @dev Note that while this minter makes use of `block.timestamp` and it is
|
|
95
103
|
* technically possible that this value is manipulated by block producers, such
|
|
@@ -102,73 +110,39 @@ import "@openzeppelin-4.7/contracts/utils/math/Math.sol";
|
|
|
102
110
|
contract MinterSEAV1 is ReentrancyGuard, ISharedMinterV0, ISharedMinterSEAV0 {
|
|
103
111
|
using SafeCast for uint256;
|
|
104
112
|
|
|
105
|
-
/// Minter filter address this minter interacts with
|
|
113
|
+
/// @notice Minter filter address this minter interacts with
|
|
106
114
|
address public immutable minterFilterAddress;
|
|
107
115
|
|
|
108
|
-
/// Minter filter this minter may interact with.
|
|
109
|
-
IMinterFilterV1 private immutable
|
|
116
|
+
/// @notice Minter filter this minter may interact with.
|
|
117
|
+
IMinterFilterV1 private immutable _minterFilter;
|
|
110
118
|
|
|
111
|
-
/// minterType for this minter
|
|
119
|
+
/// @notice minterType for this minter
|
|
112
120
|
string public constant minterType = "MinterSEAV1";
|
|
113
121
|
|
|
114
|
-
/// minter version for this minter
|
|
122
|
+
/// @notice minter version for this minter
|
|
115
123
|
string public constant minterVersion = "v1.0.0";
|
|
116
124
|
|
|
125
|
+
/// @notice Minimum auction duration
|
|
117
126
|
uint256 public constant MIN_AUCTION_DURATION_SECONDS = 60; // seconds
|
|
118
127
|
|
|
119
128
|
// minter-wide, AdminACL-configurable parameters, where AdminACL is the
|
|
120
129
|
// admin of this minter's MinterFilter.
|
|
121
130
|
// ----------------------------------------
|
|
122
|
-
// minimum time remaining in auction after a new bid is placed
|
|
123
|
-
// configureable by admin, default to 120 seconds
|
|
124
|
-
// max uint32 ~= 4.3e9 sec ~= 136 years
|
|
125
|
-
// @dev used when determining the buffer time for any new bid on the
|
|
126
|
-
// minter, across all projects
|
|
127
|
-
uint32 minterTimeBufferSeconds = 120;
|
|
128
|
-
// gas limit for refunding ETH to bidders
|
|
129
|
-
// configurable by admin, default to 30,000
|
|
130
|
-
// max uint24 ~= 16 million gas, more than enough for a refund
|
|
131
|
-
// @dev SENDALL fallback is used to refund ETH if this limit is exceeded
|
|
132
|
-
uint24 minterRefundGasLimit = 30_000;
|
|
133
|
-
|
|
134
|
-
// storage mappings for project and contract configs
|
|
135
|
-
// @dev base minter project config is not used on this minter, therefore no
|
|
136
|
-
// mapping is declared here to ProjectConfig structs
|
|
137
|
-
|
|
138
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
139
|
-
// STATE VARIABLES FOR SplitFundsLib begin here
|
|
140
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
141
|
-
|
|
142
|
-
// contractAddress => IsEngineCache
|
|
143
|
-
mapping(address => SplitFundsLib.IsEngineCache) private _isEngineCaches;
|
|
144
|
-
|
|
145
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
146
|
-
// STATE VARIABLES FOR SplitFundsLib end here
|
|
147
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
148
|
-
|
|
149
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
150
|
-
// STATE VARIABLES FOR MaxInvocationsLib begin here
|
|
151
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
152
|
-
|
|
153
|
-
// contractAddress => projectId => max invocations specific project config
|
|
154
|
-
mapping(address => mapping(uint256 => MaxInvocationsLib.MaxInvocationsProjectConfig))
|
|
155
|
-
private _maxInvocationsProjectConfigMapping;
|
|
156
|
-
|
|
157
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
158
|
-
// STATE VARIABLES FOR MaxInvocationsLib end here
|
|
159
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
160
131
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
132
|
+
/** @notice minimum time remaining in auction after a new bid is placed
|
|
133
|
+
* configureable by admin, default to 120 seconds
|
|
134
|
+
* max uint32 ~= 4.3e9 sec ~= 136 years
|
|
135
|
+
* @dev used when determining the buffer time for any new bid on the
|
|
136
|
+
* minter, across all projects
|
|
137
|
+
*/
|
|
138
|
+
uint32 internal _minterTimeBufferSeconds = 120;
|
|
168
139
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
140
|
+
/** @notice Gas limit for refunding ETH to bidders
|
|
141
|
+
* configurable by admin, default to 30,000
|
|
142
|
+
* max uint24 ~= 16 million gas, more than enough for a refund
|
|
143
|
+
* @dev SENDALL fallback is used to refund ETH if this limit is exceeded
|
|
144
|
+
*/
|
|
145
|
+
uint24 internal _minterRefundGasLimit = 30_000;
|
|
172
146
|
|
|
173
147
|
// MODIFIERS
|
|
174
148
|
// @dev contract uses modifier-like internal functions instead of modifiers
|
|
@@ -182,56 +156,56 @@ contract MinterSEAV1 is ReentrancyGuard, ISharedMinterV0, ISharedMinterSEAV0 {
|
|
|
182
156
|
|
|
183
157
|
/**
|
|
184
158
|
* @notice Initializes contract to be a shared, filtered minter for
|
|
185
|
-
* minter filter `
|
|
186
|
-
* @param
|
|
159
|
+
* minter filter `minterFilter`
|
|
160
|
+
* @param minterFilter Minter filter for which this will be a minter
|
|
187
161
|
*/
|
|
188
|
-
constructor(address
|
|
189
|
-
minterFilterAddress =
|
|
190
|
-
|
|
162
|
+
constructor(address minterFilter) ReentrancyGuard() {
|
|
163
|
+
minterFilterAddress = minterFilter;
|
|
164
|
+
_minterFilter = IMinterFilterV1(minterFilter);
|
|
191
165
|
// emit events indicating default minter configuration values
|
|
192
|
-
emit MinAuctionDurationSecondsUpdated(
|
|
193
|
-
|
|
194
|
-
|
|
166
|
+
emit SEALib.MinAuctionDurationSecondsUpdated(
|
|
167
|
+
MIN_AUCTION_DURATION_SECONDS
|
|
168
|
+
);
|
|
169
|
+
emit SEALib.MinterTimeBufferUpdated(_minterTimeBufferSeconds);
|
|
170
|
+
emit SEALib.MinterRefundGasLimitUpdated(_minterRefundGasLimit);
|
|
195
171
|
}
|
|
196
172
|
|
|
197
173
|
/**
|
|
198
|
-
* @notice Manually sets the local maximum invocations of project `
|
|
199
|
-
* with the provided `
|
|
200
|
-
* than or equal to the value of project `
|
|
174
|
+
* @notice Manually sets the local maximum invocations of project `projectId`
|
|
175
|
+
* with the provided `maxInvocations`, checking that `maxInvocations` is less
|
|
176
|
+
* than or equal to the value of project `project_id`'s maximum invocations that is
|
|
201
177
|
* set on the core contract.
|
|
202
|
-
* @dev Note that a `
|
|
178
|
+
* @dev Note that a `maxInvocations` of 0 can only be set if the current `invocations`
|
|
203
179
|
* value is also 0 and this would also set `maxHasBeenInvoked` to true, correctly short-circuiting
|
|
204
180
|
* this minter's purchase function, avoiding extra gas costs from the core contract's maxInvocations check.
|
|
205
|
-
* @param
|
|
206
|
-
* @param
|
|
207
|
-
* @param
|
|
181
|
+
* @param projectId Project ID to set the maximum invocations for.
|
|
182
|
+
* @param coreContract Core contract address for the given project.
|
|
183
|
+
* @param maxInvocations Maximum invocations to set for the project.
|
|
208
184
|
*/
|
|
209
185
|
function manuallyLimitProjectMaxInvocations(
|
|
210
|
-
uint256
|
|
211
|
-
address
|
|
212
|
-
uint24
|
|
186
|
+
uint256 projectId,
|
|
187
|
+
address coreContract,
|
|
188
|
+
uint24 maxInvocations
|
|
213
189
|
) external {
|
|
214
190
|
AuthLib.onlyArtist({
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
191
|
+
projectId: projectId,
|
|
192
|
+
coreContract: coreContract,
|
|
193
|
+
sender: msg.sender
|
|
194
|
+
});
|
|
195
|
+
MaxInvocationsLib.manuallyLimitProjectMaxInvocations({
|
|
196
|
+
projectId: projectId,
|
|
197
|
+
coreContract: coreContract,
|
|
198
|
+
maxInvocations: maxInvocations
|
|
218
199
|
});
|
|
219
|
-
MaxInvocationsLib.manuallyLimitProjectMaxInvocations(
|
|
220
|
-
_projectId,
|
|
221
|
-
_coreContract,
|
|
222
|
-
_maxInvocations,
|
|
223
|
-
_maxInvocationsProjectConfigMapping[_coreContract][_projectId]
|
|
224
|
-
);
|
|
225
|
-
emit ProjectMaxInvocationsLimitUpdated(
|
|
226
|
-
_projectId,
|
|
227
|
-
_coreContract,
|
|
228
|
-
_maxInvocations
|
|
229
|
-
);
|
|
230
200
|
|
|
231
201
|
// @dev the following is unique behavior to this minter
|
|
232
202
|
// for convenience, try to mint and assign a token to the project's
|
|
233
203
|
// next slot
|
|
234
|
-
|
|
204
|
+
SEALib.tryMintTokenToNextSlot({
|
|
205
|
+
projectId: projectId,
|
|
206
|
+
coreContract: coreContract,
|
|
207
|
+
minterFilter: _minterFilter
|
|
208
|
+
});
|
|
235
209
|
}
|
|
236
210
|
|
|
237
211
|
/**
|
|
@@ -239,22 +213,22 @@ contract MinterSEAV1 is ReentrancyGuard, ISharedMinterV0, ISharedMinterSEAV0 {
|
|
|
239
213
|
* the minimum amount of time that must pass between the final bid and the
|
|
240
214
|
* the end of an auction. Auctions are extended if a new bid is placed
|
|
241
215
|
* within this time buffer of the auction end time.
|
|
242
|
-
* @param
|
|
216
|
+
* @param minterTimeBufferSeconds Time buffer in seconds.
|
|
243
217
|
*/
|
|
244
218
|
function updateMinterTimeBufferSeconds(
|
|
245
|
-
uint32
|
|
219
|
+
uint32 minterTimeBufferSeconds
|
|
246
220
|
) external {
|
|
247
221
|
// CHECKS
|
|
248
|
-
_onlyNonZero(
|
|
222
|
+
_onlyNonZero(minterTimeBufferSeconds);
|
|
249
223
|
AuthLib.onlyMinterFilterAdminACL({
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
224
|
+
minterFilterAddress: minterFilterAddress,
|
|
225
|
+
sender: msg.sender,
|
|
226
|
+
contract_: address(this),
|
|
227
|
+
selector: this.updateMinterTimeBufferSeconds.selector
|
|
254
228
|
});
|
|
255
229
|
// EFFECTS
|
|
256
|
-
|
|
257
|
-
emit MinterTimeBufferUpdated(
|
|
230
|
+
_minterTimeBufferSeconds = minterTimeBufferSeconds;
|
|
231
|
+
emit SEALib.MinterTimeBufferUpdated(minterTimeBufferSeconds);
|
|
258
232
|
}
|
|
259
233
|
|
|
260
234
|
/**
|
|
@@ -265,95 +239,76 @@ contract MinterSEAV1 is ReentrancyGuard, ISharedMinterV0, ISharedMinterSEAV0 {
|
|
|
265
239
|
* bid.
|
|
266
240
|
* @dev max gas limit is ~16M, which is considered well over a future-safe
|
|
267
241
|
* upper bound.
|
|
268
|
-
* @param
|
|
242
|
+
* @param minterRefundGasLimit Gas limit to set for refunds. Must be
|
|
269
243
|
* between 7,000 and max uint24 (~16M).
|
|
270
244
|
*/
|
|
271
|
-
function updateRefundGasLimit(uint24
|
|
245
|
+
function updateRefundGasLimit(uint24 minterRefundGasLimit) external {
|
|
272
246
|
// CHECKS
|
|
273
247
|
AuthLib.onlyMinterFilterAdminACL({
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
248
|
+
minterFilterAddress: minterFilterAddress,
|
|
249
|
+
sender: msg.sender,
|
|
250
|
+
contract_: address(this),
|
|
251
|
+
selector: this.updateRefundGasLimit.selector
|
|
278
252
|
});
|
|
279
|
-
// @dev max gas limit implicitly checked by using
|
|
253
|
+
// @dev max gas limit implicitly checked by using uint24 input arg
|
|
280
254
|
// @dev min gas limit is based on rounding up current cost to send ETH
|
|
281
255
|
// to a Gnosis Safe wallet, which accesses cold address and emits event
|
|
282
|
-
require(
|
|
256
|
+
require(minterRefundGasLimit >= 7_000, "Only gte 7_000");
|
|
283
257
|
// EFFECTS
|
|
284
|
-
|
|
285
|
-
emit MinterRefundGasLimitUpdated(
|
|
258
|
+
_minterRefundGasLimit = minterRefundGasLimit;
|
|
259
|
+
emit SEALib.MinterRefundGasLimitUpdated(minterRefundGasLimit);
|
|
286
260
|
}
|
|
287
261
|
|
|
288
262
|
/**
|
|
289
|
-
* @notice Sets auction details for project `
|
|
263
|
+
* @notice Sets auction details for project `projectId`.
|
|
290
264
|
* If project does not have a "next token" assigned, this function attempts
|
|
291
265
|
* to mint a token and assign it to the project's next token slot.
|
|
292
|
-
* @param
|
|
293
|
-
* @param
|
|
294
|
-
* @param
|
|
266
|
+
* @param projectId Project ID to set future auction details for.
|
|
267
|
+
* @param coreContract Core contract address for the given project.
|
|
268
|
+
* @param timestampStart Timestamp after which new auctions may be
|
|
295
269
|
* started. Note that this is not the timestamp of the auction start, but
|
|
296
270
|
* rather the timestamp after which a auction may be started. Also note
|
|
297
271
|
* that the passed value here must either be in the future, or `0` (which
|
|
298
272
|
* indicates that auctions are immediately startable).
|
|
299
|
-
* @param
|
|
273
|
+
* @param auctionDurationSeconds Duration of new auctions, in seconds,
|
|
300
274
|
* before any extensions due to bids being placed inside buffer period near
|
|
301
275
|
* the end of an auction.
|
|
302
|
-
* @param
|
|
276
|
+
* @param basePrice reserve price (minimum starting bid price), in wei.
|
|
303
277
|
* Must be greater than 0, but may be as low as 1 wei.
|
|
304
|
-
* @param
|
|
278
|
+
* @param minBidIncrementPercentage Minimum percentage amount that a new
|
|
305
279
|
* bid must be over the previous bid. Must be greater than 0, and may be as
|
|
306
280
|
* high as 255. Recommended value is 5%. Values represent whole
|
|
307
281
|
* percentages, so a value of 5 represents 5%.
|
|
308
|
-
* @dev `
|
|
282
|
+
* @dev `basePrice` of zero not allowed to prevent accidental
|
|
309
283
|
* misconfiguration of auctions
|
|
310
284
|
*/
|
|
311
285
|
function configureFutureAuctions(
|
|
312
|
-
uint256
|
|
313
|
-
address
|
|
314
|
-
uint256
|
|
315
|
-
uint256
|
|
316
|
-
uint256
|
|
317
|
-
uint8
|
|
286
|
+
uint256 projectId,
|
|
287
|
+
address coreContract,
|
|
288
|
+
uint256 timestampStart,
|
|
289
|
+
uint256 auctionDurationSeconds,
|
|
290
|
+
uint256 basePrice,
|
|
291
|
+
uint8 minBidIncrementPercentage
|
|
318
292
|
) external {
|
|
319
293
|
// CHECKS
|
|
320
|
-
_onlyNonZero(
|
|
321
|
-
_onlyNonZero(
|
|
294
|
+
_onlyNonZero(basePrice);
|
|
295
|
+
_onlyNonZero(minBidIncrementPercentage);
|
|
322
296
|
AuthLib.onlyArtist({
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
297
|
+
projectId: projectId,
|
|
298
|
+
coreContract: coreContract,
|
|
299
|
+
sender: msg.sender
|
|
326
300
|
});
|
|
327
|
-
SEALib.SEAProjectConfig storage _SEAProjectConfig = _SEAProjectConfigs[
|
|
328
|
-
_coreContract
|
|
329
|
-
][_projectId];
|
|
330
|
-
MaxInvocationsLib.MaxInvocationsProjectConfig
|
|
331
|
-
storage _maxInvocationsProjectConfig = _maxInvocationsProjectConfigMapping[
|
|
332
|
-
_coreContract
|
|
333
|
-
][_projectId];
|
|
334
301
|
require(
|
|
335
|
-
|
|
336
|
-
"Only future start times or 0"
|
|
337
|
-
);
|
|
338
|
-
require(
|
|
339
|
-
_auctionDurationSeconds >= MIN_AUCTION_DURATION_SECONDS,
|
|
302
|
+
auctionDurationSeconds >= MIN_AUCTION_DURATION_SECONDS,
|
|
340
303
|
"Auction duration below minimum"
|
|
341
304
|
);
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
emit ConfiguredFutureAuctions({
|
|
351
|
-
projectId: _projectId,
|
|
352
|
-
coreContract: _coreContract,
|
|
353
|
-
timestampStart: _timestampStart.toUint64(),
|
|
354
|
-
auctionDurationSeconds: _auctionDurationSeconds.toUint32(),
|
|
355
|
-
basePrice: _basePrice,
|
|
356
|
-
minBidIncrementPercentage: _minBidIncrementPercentage
|
|
305
|
+
SEALib.configureFutureAuctions({
|
|
306
|
+
projectId: projectId,
|
|
307
|
+
coreContract: coreContract,
|
|
308
|
+
timestampStart: timestampStart,
|
|
309
|
+
auctionDurationSeconds: auctionDurationSeconds,
|
|
310
|
+
basePrice: basePrice,
|
|
311
|
+
minBidIncrementPercentage: minBidIncrementPercentage
|
|
357
312
|
});
|
|
358
313
|
|
|
359
314
|
// for convenience, sync local max invocations to the core contract if
|
|
@@ -363,22 +318,30 @@ contract MinterSEAV1 is ReentrancyGuard, ISharedMinterV0, ISharedMinterSEAV0 {
|
|
|
363
318
|
// intentionally less than the core contract's max invocations.
|
|
364
319
|
// sync local max invocations if not initially populated
|
|
365
320
|
if (
|
|
366
|
-
MaxInvocationsLib.maxInvocationsIsUnconfigured(
|
|
367
|
-
|
|
368
|
-
|
|
321
|
+
MaxInvocationsLib.maxInvocationsIsUnconfigured({
|
|
322
|
+
projectId: projectId,
|
|
323
|
+
coreContract: coreContract
|
|
324
|
+
})
|
|
369
325
|
) {
|
|
370
|
-
syncProjectMaxInvocationsToCore(
|
|
326
|
+
syncProjectMaxInvocationsToCore({
|
|
327
|
+
projectId: projectId,
|
|
328
|
+
coreContract: coreContract
|
|
329
|
+
});
|
|
371
330
|
// @dev syncProjectMaxInvocationsToCore function calls
|
|
372
|
-
//
|
|
331
|
+
// SEALib.tryMintTokenToNextSlot, so we do not call it here.
|
|
373
332
|
} else {
|
|
374
333
|
// for convenience, try to mint to next token slot
|
|
375
|
-
|
|
334
|
+
SEALib.tryMintTokenToNextSlot({
|
|
335
|
+
projectId: projectId,
|
|
336
|
+
coreContract: coreContract,
|
|
337
|
+
minterFilter: _minterFilter
|
|
338
|
+
});
|
|
376
339
|
}
|
|
377
340
|
}
|
|
378
341
|
|
|
379
342
|
/**
|
|
380
|
-
* @notice Resets future auction configuration for project `
|
|
381
|
-
* core contract `
|
|
343
|
+
* @notice Resets future auction configuration for project `projectId` on
|
|
344
|
+
* core contract `coreContract`, zero-ing out all details having to do
|
|
382
345
|
* with future auction parameters.
|
|
383
346
|
* This is not intended to be used in normal operation, but rather only in
|
|
384
347
|
* case of the need to halt the creation of any future auctions.
|
|
@@ -386,36 +349,35 @@ contract MinterSEAV1 is ReentrancyGuard, ISharedMinterV0, ISharedMinterSEAV0 {
|
|
|
386
349
|
* Does not affect any project next token details (i.e. if a next token is
|
|
387
350
|
* assigned, it will remain assigned and held by the minter until auction
|
|
388
351
|
* details are reconfigured).
|
|
389
|
-
* @param
|
|
352
|
+
* @param projectId Project ID to reset future auction configuration
|
|
390
353
|
* details for.
|
|
391
|
-
* @param
|
|
354
|
+
* @param coreContract Core contract address for the given project.
|
|
392
355
|
*/
|
|
393
356
|
function resetFutureAuctionDetails(
|
|
394
|
-
uint256
|
|
395
|
-
address
|
|
357
|
+
uint256 projectId,
|
|
358
|
+
address coreContract
|
|
396
359
|
) external {
|
|
397
360
|
AuthLib.onlyCoreAdminACLOrArtist({
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
361
|
+
projectId: projectId,
|
|
362
|
+
coreContract: coreContract,
|
|
363
|
+
sender: msg.sender,
|
|
364
|
+
contract_: address(this),
|
|
365
|
+
selector: this.resetFutureAuctionDetails.selector
|
|
403
366
|
});
|
|
404
|
-
SEALib.SEAProjectConfig storage _SEAProjectConfig = _SEAProjectConfigs[
|
|
405
|
-
_coreContract
|
|
406
|
-
][_projectId];
|
|
407
367
|
// reset to initial values
|
|
408
|
-
SEALib.resetFutureAuctionDetails(
|
|
368
|
+
SEALib.resetFutureAuctionDetails({
|
|
369
|
+
projectId: projectId,
|
|
370
|
+
coreContract: coreContract
|
|
371
|
+
});
|
|
409
372
|
// @dev do not affect next token or max invocations
|
|
410
|
-
emit ResetAuctionDetails(_projectId, _coreContract);
|
|
411
373
|
}
|
|
412
374
|
|
|
413
375
|
/**
|
|
414
376
|
* @notice Admin-only function that ejects a project's "next token" from
|
|
415
|
-
* the minter and sends it to the input `
|
|
377
|
+
* the minter and sends it to the input `to` address.
|
|
416
378
|
* This function is only intended for use in the edge case where the minter
|
|
417
379
|
* has a "next token" assigned to a project, but the project has been reset
|
|
418
|
-
* via `
|
|
380
|
+
* via `resetFutureAuctionDetails`, and the artist does not want an auction to be
|
|
419
381
|
* started for the "next token". This function also protects against the
|
|
420
382
|
* unforseen case where the minter is in an unexpected state where it has a
|
|
421
383
|
* "next token" assigned to a project, but for some reason the project is
|
|
@@ -425,129 +387,109 @@ contract MinterSEAV1 is ReentrancyGuard, ISharedMinterV0, ISharedMinterSEAV0 {
|
|
|
425
387
|
* no further tokens will be assigned to the project's "next token" slot,
|
|
426
388
|
* unless the project is subsequently reconfigured via an artist call to
|
|
427
389
|
* `configureFutureAuctions`.
|
|
428
|
-
* @param
|
|
429
|
-
* @param
|
|
430
|
-
* @param
|
|
390
|
+
* @param projectId Project ID to eject next token for.
|
|
391
|
+
* @param coreContract Core contract address for the given project.
|
|
392
|
+
* @param to Address to send the ejected token to.
|
|
431
393
|
*/
|
|
432
394
|
function ejectNextTokenTo(
|
|
433
|
-
uint256
|
|
434
|
-
address
|
|
435
|
-
address
|
|
395
|
+
uint256 projectId,
|
|
396
|
+
address coreContract,
|
|
397
|
+
address to
|
|
436
398
|
) external {
|
|
437
399
|
AuthLib.onlyCoreAdminACL({
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
400
|
+
coreContract: coreContract,
|
|
401
|
+
sender: msg.sender,
|
|
402
|
+
contract_: address(this),
|
|
403
|
+
selector: this.ejectNextTokenTo.selector
|
|
442
404
|
});
|
|
443
|
-
SEALib.
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
// only if project is not configured (i.e. artist called
|
|
448
|
-
// `resetAuctionDetails`)
|
|
449
|
-
require(
|
|
450
|
-
!SEALib.projectIsConfigured(_SEAProjectConfig),
|
|
451
|
-
"Only unconfigured projects"
|
|
452
|
-
);
|
|
453
|
-
// only if project has a next token assigned
|
|
454
|
-
require(
|
|
455
|
-
_SEAProjectConfig.nextTokenNumberIsPopulated == true,
|
|
456
|
-
"No next token"
|
|
457
|
-
);
|
|
458
|
-
// EFFECTS
|
|
459
|
-
_SEAProjectConfig.nextTokenNumberIsPopulated = false;
|
|
460
|
-
// INTERACTIONS
|
|
461
|
-
// @dev overflow automatically handled by Sol ^0.8.0
|
|
462
|
-
uint256 nextTokenId = ABHelpers.tokenIdFromProjectIdAndTokenNumber({
|
|
463
|
-
_projectId: _projectId,
|
|
464
|
-
_tokenNumber: _SEAProjectConfig.nextTokenNumber
|
|
465
|
-
});
|
|
466
|
-
IERC721(_coreContract).transferFrom({
|
|
467
|
-
from: address(this),
|
|
468
|
-
to: _to,
|
|
469
|
-
tokenId: nextTokenId
|
|
405
|
+
SEALib.ejectNextTokenTo({
|
|
406
|
+
projectId: projectId,
|
|
407
|
+
coreContract: coreContract,
|
|
408
|
+
to: to
|
|
470
409
|
});
|
|
471
|
-
emit ProjectNextTokenEjected(_projectId, _coreContract);
|
|
472
410
|
}
|
|
473
411
|
|
|
474
412
|
/**
|
|
475
|
-
* @notice Settles any complete auction for token `
|
|
413
|
+
* @notice Settles any complete auction for token `settleTokenId` (if
|
|
476
414
|
* applicable), then attempts to create a bid for token
|
|
477
|
-
* `
|
|
415
|
+
* `bidTokenId` with bid amount and bidder address equal to
|
|
478
416
|
* `msg.value` and `msg.sender`, respectively.
|
|
479
417
|
* Intended to gracefully handle the case where a user is front-run by
|
|
480
418
|
* one or more transactions to settle and/or initialize a new auction,
|
|
481
419
|
* potentially still placing a bid on the auction for the token ID if the
|
|
482
420
|
* bid value is sufficiently higher than the current highest bid.
|
|
483
|
-
* Note that the use of `
|
|
421
|
+
* Note that the use of `bidTokenId` is to prevent the possibility of
|
|
484
422
|
* transactions that are stuck in the pending pool for long periods of time
|
|
485
423
|
* from unintentionally bidding on auctions for future tokens.
|
|
486
424
|
* Note that calls to `settleAuction` and `createBid` are possible
|
|
487
425
|
* to be called in separate transactions, but this function is provided for
|
|
488
426
|
* convenience and executes both of those functions in a single
|
|
489
427
|
* transaction, while handling front-running as gracefully as possible.
|
|
490
|
-
* @param
|
|
491
|
-
* @param
|
|
492
|
-
* @param
|
|
428
|
+
* @param settleTokenId Token ID to settle auction for.
|
|
429
|
+
* @param bidTokenId Token ID to bid on.
|
|
430
|
+
* @param coreContract Core contract address for the given project.
|
|
493
431
|
* @dev this function is not non-reentrant, but the underlying calls are
|
|
494
432
|
* to non-reentrant functions.
|
|
495
433
|
*/
|
|
496
434
|
function settleAuctionAndCreateBid(
|
|
497
|
-
uint256
|
|
498
|
-
uint256
|
|
499
|
-
address
|
|
435
|
+
uint256 settleTokenId,
|
|
436
|
+
uint256 bidTokenId,
|
|
437
|
+
address coreContract
|
|
500
438
|
) external payable {
|
|
501
439
|
// ensure tokens are in the same project
|
|
502
440
|
require(
|
|
503
|
-
ABHelpers.tokenIdToProjectId(
|
|
504
|
-
ABHelpers.tokenIdToProjectId(
|
|
441
|
+
ABHelpers.tokenIdToProjectId(settleTokenId) ==
|
|
442
|
+
ABHelpers.tokenIdToProjectId(bidTokenId),
|
|
505
443
|
"Only tokens in same project"
|
|
506
444
|
);
|
|
507
445
|
// settle completed auction, if applicable
|
|
508
|
-
settleAuction(
|
|
446
|
+
settleAuction({tokenId: settleTokenId, coreContract: coreContract});
|
|
509
447
|
// attempt to bid on next token
|
|
510
|
-
createBid(
|
|
448
|
+
createBid({tokenId: bidTokenId, coreContract: coreContract});
|
|
511
449
|
}
|
|
512
450
|
|
|
513
451
|
/**
|
|
514
452
|
* @notice View function to return the current minter-level configuration
|
|
515
453
|
* details.
|
|
516
|
-
* @return
|
|
454
|
+
* @return minAuctionDurationSeconds Minimum auction duration in seconds.
|
|
517
455
|
* Note that this value is a constant on this version of the minter.
|
|
518
|
-
* @return
|
|
519
|
-
* @return
|
|
456
|
+
* @return minterTimeBufferSeconds Buffer time in seconds
|
|
457
|
+
* @return minterRefundGasLimit Gas limit for refunding ETH
|
|
520
458
|
*/
|
|
521
459
|
function minterConfigurationDetails()
|
|
522
460
|
external
|
|
523
461
|
view
|
|
524
462
|
returns (
|
|
525
|
-
uint256
|
|
526
|
-
uint32
|
|
527
|
-
uint24
|
|
463
|
+
uint256 minAuctionDurationSeconds,
|
|
464
|
+
uint32 minterTimeBufferSeconds,
|
|
465
|
+
uint24 minterRefundGasLimit
|
|
528
466
|
)
|
|
529
467
|
{
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
468
|
+
minAuctionDurationSeconds = MIN_AUCTION_DURATION_SECONDS;
|
|
469
|
+
minterTimeBufferSeconds = _minterTimeBufferSeconds;
|
|
470
|
+
minterRefundGasLimit = _minterRefundGasLimit;
|
|
533
471
|
}
|
|
534
472
|
|
|
535
473
|
/**
|
|
536
474
|
* @notice Gets the maximum invocations project configuration.
|
|
537
|
-
* @param
|
|
538
|
-
* @param
|
|
475
|
+
* @param projectId The ID of the project whose data needs to be fetched.
|
|
476
|
+
* @param coreContract The address of the core contract.
|
|
539
477
|
* @return MaxInvocationsLib.MaxInvocationsProjectConfig instance with the
|
|
540
478
|
* configuration data.
|
|
541
479
|
*/
|
|
542
480
|
function maxInvocationsProjectConfig(
|
|
543
|
-
uint256
|
|
544
|
-
address
|
|
481
|
+
uint256 projectId,
|
|
482
|
+
address coreContract
|
|
545
483
|
)
|
|
546
484
|
external
|
|
547
485
|
view
|
|
548
486
|
returns (MaxInvocationsLib.MaxInvocationsProjectConfig memory)
|
|
549
487
|
{
|
|
550
|
-
return
|
|
488
|
+
return
|
|
489
|
+
MaxInvocationsLib.getMaxInvocationsProjectConfig({
|
|
490
|
+
projectId: projectId,
|
|
491
|
+
coreContract: coreContract
|
|
492
|
+
});
|
|
551
493
|
}
|
|
552
494
|
|
|
553
495
|
/**
|
|
@@ -561,17 +503,18 @@ contract MinterSEAV1 is ReentrancyGuard, ISharedMinterV0, ISharedMinterSEAV0 {
|
|
|
561
503
|
* possible because the V3 core contract only allows maximum invocations
|
|
562
504
|
* to be reduced, not increased. Based on this rationale, we intentionally
|
|
563
505
|
* do not do input validation in this method as to whether or not the input
|
|
564
|
-
* @param
|
|
565
|
-
* @param
|
|
506
|
+
* @param projectId is an existing project ID.
|
|
507
|
+
* @param coreContract is an existing core contract address.
|
|
566
508
|
*/
|
|
567
509
|
function projectMaxHasBeenInvoked(
|
|
568
|
-
uint256
|
|
569
|
-
address
|
|
510
|
+
uint256 projectId,
|
|
511
|
+
address coreContract
|
|
570
512
|
) external view returns (bool) {
|
|
571
513
|
return
|
|
572
|
-
MaxInvocationsLib.getMaxHasBeenInvoked(
|
|
573
|
-
|
|
574
|
-
|
|
514
|
+
MaxInvocationsLib.getMaxHasBeenInvoked({
|
|
515
|
+
projectId: projectId,
|
|
516
|
+
coreContract: coreContract
|
|
517
|
+
});
|
|
575
518
|
}
|
|
576
519
|
|
|
577
520
|
/**
|
|
@@ -590,41 +533,41 @@ contract MinterSEAV1 is ReentrancyGuard, ISharedMinterV0, ISharedMinterSEAV0 {
|
|
|
590
533
|
* increased. When this happens, the minter will enable minting, allowing
|
|
591
534
|
* the core contract to enforce the max invocations check. Based on this
|
|
592
535
|
* rationale, we intentionally do not do input validation in this method as
|
|
593
|
-
* to whether or not the input `
|
|
594
|
-
* @param
|
|
595
|
-
* @param
|
|
536
|
+
* to whether or not the input `projectId` is an existing project ID.
|
|
537
|
+
* @param projectId is an existing project ID.
|
|
538
|
+
* @param coreContract is an existing core contract address.
|
|
596
539
|
*/
|
|
597
540
|
function projectMaxInvocations(
|
|
598
|
-
uint256
|
|
599
|
-
address
|
|
541
|
+
uint256 projectId,
|
|
542
|
+
address coreContract
|
|
600
543
|
) external view returns (uint256) {
|
|
601
544
|
return
|
|
602
|
-
MaxInvocationsLib.getMaxInvocations(
|
|
603
|
-
|
|
604
|
-
|
|
545
|
+
MaxInvocationsLib.getMaxInvocations({
|
|
546
|
+
projectId: projectId,
|
|
547
|
+
coreContract: coreContract
|
|
548
|
+
});
|
|
605
549
|
}
|
|
606
550
|
|
|
607
551
|
/**
|
|
608
|
-
* @notice Checks if the specified `
|
|
609
|
-
* @dev This function retrieves the cached value of `
|
|
552
|
+
* @notice Checks if the specified `coreContract` is a valid engine contract.
|
|
553
|
+
* @dev This function retrieves the cached value of `isEngine` from
|
|
610
554
|
* the `isEngineCache` mapping. If the cached value is already set, it
|
|
611
|
-
* returns the cached value. Otherwise, it calls the `
|
|
612
|
-
* function from the `SplitFundsLib` library to check if `
|
|
555
|
+
* returns the cached value. Otherwise, it calls the `getV3CoreIsEngineView`
|
|
556
|
+
* function from the `SplitFundsLib` library to check if `coreContract`
|
|
613
557
|
* is a valid engine contract.
|
|
614
|
-
* @dev This function will revert if the provided `
|
|
558
|
+
* @dev This function will revert if the provided `coreContract` is not
|
|
615
559
|
* a valid Engine or V3 Flagship contract.
|
|
616
|
-
* @param
|
|
617
|
-
* @return bool indicating if `
|
|
560
|
+
* @param coreContract The address of the contract to check.
|
|
561
|
+
* @return bool indicating if `coreContract` is a valid engine contract.
|
|
618
562
|
*/
|
|
619
|
-
function isEngineView(address
|
|
620
|
-
SplitFundsLib.IsEngineCache storage isEngineCache =
|
|
621
|
-
|
|
622
|
-
];
|
|
563
|
+
function isEngineView(address coreContract) external view returns (bool) {
|
|
564
|
+
SplitFundsLib.IsEngineCache storage isEngineCache = SplitFundsLib
|
|
565
|
+
.getIsEngineCacheConfig(coreContract);
|
|
623
566
|
if (isEngineCache.isCached) {
|
|
624
567
|
return isEngineCache.isEngine;
|
|
625
568
|
} else {
|
|
626
|
-
// @dev this calls the non-modifying variant of
|
|
627
|
-
return SplitFundsLib.getV3CoreIsEngineView(
|
|
569
|
+
// @dev this calls the non-state-modifying variant of isEngine
|
|
570
|
+
return SplitFundsLib.getV3CoreIsEngineView(coreContract);
|
|
628
571
|
}
|
|
629
572
|
}
|
|
630
573
|
|
|
@@ -632,36 +575,40 @@ contract MinterSEAV1 is ReentrancyGuard, ISharedMinterV0, ISharedMinterSEAV0 {
|
|
|
632
575
|
* @notice projectId => SEA project configuration details.
|
|
633
576
|
* Note that in the case of no auction being initialized for the project,
|
|
634
577
|
* the returned `auction` will be the default struct.
|
|
635
|
-
* @param
|
|
636
|
-
* @param
|
|
637
|
-
* @return
|
|
578
|
+
* @param projectId The project ID
|
|
579
|
+
* @param coreContract The core contract address
|
|
580
|
+
* @return SEAProjectConfig_ The SEA project configuration details
|
|
638
581
|
*/
|
|
639
582
|
function SEAProjectConfigurationDetails(
|
|
640
|
-
uint256
|
|
641
|
-
address
|
|
642
|
-
) external view returns (SEALib.SEAProjectConfig memory
|
|
643
|
-
|
|
583
|
+
uint256 projectId,
|
|
584
|
+
address coreContract
|
|
585
|
+
) external view returns (SEALib.SEAProjectConfig memory SEAProjectConfig_) {
|
|
586
|
+
SEAProjectConfig_ = SEALib.getSEAProjectConfig({
|
|
587
|
+
projectId: projectId,
|
|
588
|
+
coreContract: coreContract
|
|
589
|
+
});
|
|
644
590
|
// clean up next token number to handle case where it is stale
|
|
645
|
-
|
|
591
|
+
SEAProjectConfig_.nextTokenNumber = SEAProjectConfig_
|
|
646
592
|
.nextTokenNumberIsPopulated
|
|
647
|
-
?
|
|
593
|
+
? SEAProjectConfig_.nextTokenNumber
|
|
648
594
|
: 0;
|
|
649
595
|
}
|
|
650
596
|
|
|
651
597
|
/**
|
|
652
598
|
* @notice projectId => active auction details.
|
|
653
599
|
* @dev reverts if no auction exists for the project.
|
|
654
|
-
* @param
|
|
655
|
-
* @param
|
|
600
|
+
* @param projectId The project ID
|
|
601
|
+
* @param coreContract The core contract address
|
|
656
602
|
*/
|
|
657
603
|
function projectActiveAuctionDetails(
|
|
658
|
-
uint256
|
|
659
|
-
address
|
|
604
|
+
uint256 projectId,
|
|
605
|
+
address coreContract
|
|
660
606
|
) external view returns (SEALib.Auction memory auction) {
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
607
|
+
return
|
|
608
|
+
SEALib.projectActiveAuctionDetails({
|
|
609
|
+
projectId: projectId,
|
|
610
|
+
coreContract: coreContract
|
|
611
|
+
});
|
|
665
612
|
}
|
|
666
613
|
|
|
667
614
|
/**
|
|
@@ -674,37 +621,39 @@ contract MinterSEAV1 is ReentrancyGuard, ISharedMinterV0, ISharedMinterSEAV0 {
|
|
|
674
621
|
* target bid token ID to be passed in as an argument.
|
|
675
622
|
* The function reverts if a project does not have an active auction and
|
|
676
623
|
* the next expected token ID has not been populated.
|
|
677
|
-
* @param
|
|
678
|
-
* @param
|
|
624
|
+
* @param projectId The project ID being queried
|
|
625
|
+
* @param coreContract The core contract address
|
|
679
626
|
* @return The current token ID being auctioned, or the next token ID to be
|
|
680
627
|
* auctioned if a new auction is ready to be created.
|
|
681
628
|
*/
|
|
682
629
|
function getTokenToBid(
|
|
683
|
-
uint256
|
|
684
|
-
address
|
|
630
|
+
uint256 projectId,
|
|
631
|
+
address coreContract
|
|
685
632
|
) external view returns (uint256) {
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
633
|
+
return
|
|
634
|
+
SEALib.getTokenToBid({
|
|
635
|
+
projectId: projectId,
|
|
636
|
+
coreContract: coreContract
|
|
637
|
+
});
|
|
690
638
|
}
|
|
691
639
|
|
|
692
640
|
/**
|
|
693
641
|
* @notice View function that returns the next token ID to be auctioned
|
|
694
|
-
* by this minter for project `
|
|
642
|
+
* by this minter for project `projectId`.
|
|
695
643
|
* Reverts if the next token ID has not been populated for the project.
|
|
696
|
-
* @param
|
|
697
|
-
* @param
|
|
644
|
+
* @param projectId The project ID being queried
|
|
645
|
+
* @param coreContract The core contract address
|
|
698
646
|
* @return nextTokenId The next token ID to be auctioned by this minter
|
|
699
647
|
*/
|
|
700
648
|
function getNextTokenId(
|
|
701
|
-
uint256
|
|
702
|
-
address
|
|
649
|
+
uint256 projectId,
|
|
650
|
+
address coreContract
|
|
703
651
|
) external view returns (uint256 nextTokenId) {
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
652
|
+
return
|
|
653
|
+
SEALib.getNextTokenId({
|
|
654
|
+
projectId: projectId,
|
|
655
|
+
coreContract: coreContract
|
|
656
|
+
});
|
|
708
657
|
}
|
|
709
658
|
|
|
710
659
|
/**
|
|
@@ -722,8 +671,8 @@ contract MinterSEAV1 is ReentrancyGuard, ISharedMinterV0, ISharedMinterSEAV0 {
|
|
|
722
671
|
* token auction.
|
|
723
672
|
* Also returns currency symbol and address to be being used as payment,
|
|
724
673
|
* which for this minter is ETH only.
|
|
725
|
-
* @param
|
|
726
|
-
* @param
|
|
674
|
+
* @param projectId Project ID to get price information for.
|
|
675
|
+
* @param coreContract Core contract to get price information for.
|
|
727
676
|
* @return isConfigured true only if project auctions are configured.
|
|
728
677
|
* @return tokenPriceInWei price in wei to become the leading bidder on a
|
|
729
678
|
* token auction.
|
|
@@ -733,8 +682,8 @@ contract MinterSEAV1 is ReentrancyGuard, ISharedMinterV0, ISharedMinterSEAV0 {
|
|
|
733
682
|
* this minter. This minter always returns null address, reserved for ether
|
|
734
683
|
*/
|
|
735
684
|
function getPriceInfo(
|
|
736
|
-
uint256
|
|
737
|
-
address
|
|
685
|
+
uint256 projectId,
|
|
686
|
+
address coreContract
|
|
738
687
|
)
|
|
739
688
|
external
|
|
740
689
|
view
|
|
@@ -745,55 +694,51 @@ contract MinterSEAV1 is ReentrancyGuard, ISharedMinterV0, ISharedMinterSEAV0 {
|
|
|
745
694
|
address currencyAddress
|
|
746
695
|
)
|
|
747
696
|
{
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
.getPriceInfoFromSEAProjectConfig(_SEAProjectConfig);
|
|
697
|
+
(isConfigured, tokenPriceInWei) = SEALib.getPriceInfo({
|
|
698
|
+
projectId: projectId,
|
|
699
|
+
coreContract: coreContract
|
|
700
|
+
});
|
|
753
701
|
// currency is always ETH
|
|
754
702
|
currencySymbol = "ETH";
|
|
755
703
|
currencyAddress = address(0);
|
|
756
704
|
}
|
|
757
705
|
|
|
758
706
|
/**
|
|
759
|
-
* @notice Syncs local maximum invocations of project `
|
|
707
|
+
* @notice Syncs local maximum invocations of project `projectId` based on
|
|
760
708
|
* the value currently defined in the core contract.
|
|
761
|
-
* @param
|
|
762
|
-
* @param
|
|
709
|
+
* @param projectId Project ID to set the maximum invocations for.
|
|
710
|
+
* @param coreContract Core contract address for the given project.
|
|
763
711
|
* @dev this enables gas reduction after maxInvocations have been reached -
|
|
764
712
|
* core contracts shall still enforce a maxInvocation check during mint.
|
|
765
713
|
*/
|
|
766
714
|
function syncProjectMaxInvocationsToCore(
|
|
767
|
-
uint256
|
|
768
|
-
address
|
|
715
|
+
uint256 projectId,
|
|
716
|
+
address coreContract
|
|
769
717
|
) public {
|
|
770
718
|
AuthLib.onlyArtist({
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
719
|
+
projectId: projectId,
|
|
720
|
+
coreContract: coreContract,
|
|
721
|
+
sender: msg.sender
|
|
774
722
|
});
|
|
775
723
|
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
_maxInvocationsProjectConfigMapping[_coreContract][_projectId]
|
|
781
|
-
);
|
|
782
|
-
emit ProjectMaxInvocationsLimitUpdated(
|
|
783
|
-
_projectId,
|
|
784
|
-
_coreContract,
|
|
785
|
-
maxInvocations
|
|
786
|
-
);
|
|
724
|
+
MaxInvocationsLib.syncProjectMaxInvocationsToCore({
|
|
725
|
+
projectId: projectId,
|
|
726
|
+
coreContract: coreContract
|
|
727
|
+
});
|
|
787
728
|
|
|
788
729
|
// for convenience, try to mint and assign a token to the project's
|
|
789
730
|
// next slot
|
|
790
|
-
|
|
731
|
+
SEALib.tryMintTokenToNextSlot({
|
|
732
|
+
projectId: projectId,
|
|
733
|
+
coreContract: coreContract,
|
|
734
|
+
minterFilter: _minterFilter
|
|
735
|
+
});
|
|
791
736
|
}
|
|
792
737
|
|
|
793
738
|
/**
|
|
794
739
|
* @notice Emergency, Artist-only function that attempts to mint a new
|
|
795
740
|
* token and set it as the the next token to be auctioned for project
|
|
796
|
-
* `
|
|
741
|
+
* `projectId`.
|
|
797
742
|
* Note: This function is only included for emergency, unforseen use cases,
|
|
798
743
|
* and should not be used in normal operation. It is here only for
|
|
799
744
|
* redundant protection against an unforseen edge case where the minter
|
|
@@ -806,105 +751,60 @@ contract MinterSEAV1 is ReentrancyGuard, ISharedMinterV0, ISharedMinterSEAV0 {
|
|
|
806
751
|
* or minter
|
|
807
752
|
* @dev This function is gated to only the project's artist to prevent
|
|
808
753
|
* early minting of tokens by other users.
|
|
809
|
-
* @param
|
|
810
|
-
* @param
|
|
754
|
+
* @param projectId The project ID
|
|
755
|
+
* @param coreContract The core contract address for the given project.
|
|
811
756
|
*/
|
|
812
757
|
function tryPopulateNextToken(
|
|
813
|
-
uint256
|
|
814
|
-
address
|
|
758
|
+
uint256 projectId,
|
|
759
|
+
address coreContract
|
|
815
760
|
) public nonReentrant {
|
|
816
761
|
AuthLib.onlyArtist({
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
762
|
+
projectId: projectId,
|
|
763
|
+
coreContract: coreContract,
|
|
764
|
+
sender: msg.sender
|
|
820
765
|
});
|
|
821
766
|
// CHECKS
|
|
822
767
|
// revert if project is not configured on this minter
|
|
823
|
-
SEALib.SEAProjectConfig storage _SEAProjectConfig = _SEAProjectConfigs[
|
|
824
|
-
_coreContract
|
|
825
|
-
][_projectId];
|
|
826
768
|
require(
|
|
827
|
-
SEALib.projectIsConfigured(
|
|
769
|
+
SEALib.projectIsConfigured({
|
|
770
|
+
projectId: projectId,
|
|
771
|
+
coreContract: coreContract
|
|
772
|
+
}),
|
|
828
773
|
"Project not configured"
|
|
829
774
|
);
|
|
830
775
|
// INTERACTIONS
|
|
831
776
|
// attempt to mint new token to this minter contract, only if max
|
|
832
777
|
// invocations has not been reached
|
|
833
|
-
|
|
778
|
+
SEALib.tryMintTokenToNextSlot({
|
|
779
|
+
projectId: projectId,
|
|
780
|
+
coreContract: coreContract,
|
|
781
|
+
minterFilter: _minterFilter
|
|
782
|
+
});
|
|
834
783
|
}
|
|
835
784
|
|
|
836
785
|
/**
|
|
837
|
-
* @notice Settles a completed auction for `
|
|
786
|
+
* @notice Settles a completed auction for `tokenId`, if it exists and is
|
|
838
787
|
* not yet settled.
|
|
839
|
-
*
|
|
840
|
-
*
|
|
788
|
+
* Function reverts if there is no initialized auction for the project.
|
|
789
|
+
* Function returns early (does not modify state) if
|
|
841
790
|
* - there is an auction that has already been settled for the project
|
|
842
791
|
* - there is an auction for a different token ID on the project
|
|
843
792
|
* (likely due to a front-run)
|
|
844
|
-
* This function reverts if the auction for `
|
|
793
|
+
* This function reverts if the auction for `tokenId` exists, but has not
|
|
845
794
|
* yet ended.
|
|
846
|
-
* @param
|
|
847
|
-
* @param
|
|
795
|
+
* @param tokenId Token ID to settle auction for.
|
|
796
|
+
* @param coreContract Core contract address for the given token.
|
|
848
797
|
*/
|
|
849
798
|
function settleAuction(
|
|
850
|
-
uint256
|
|
851
|
-
address
|
|
799
|
+
uint256 tokenId,
|
|
800
|
+
address coreContract
|
|
852
801
|
) public nonReentrant {
|
|
853
|
-
|
|
854
|
-
SEALib.SEAProjectConfig storage _SEAProjectConfig = _SEAProjectConfigs[
|
|
855
|
-
_coreContract
|
|
856
|
-
][_projectId];
|
|
857
|
-
SEALib.Auction storage _auction = _SEAProjectConfig.activeAuction;
|
|
858
|
-
// load from storage to memory for gas efficiency
|
|
859
|
-
address currentBidder = _auction.currentBidder;
|
|
860
|
-
uint256 currentBid = _auction.currentBid;
|
|
861
|
-
// CHECKS
|
|
862
|
-
// @dev this check is not strictly necessary, but is included for
|
|
863
|
-
// clear error messaging
|
|
864
|
-
require(
|
|
865
|
-
SEALib.auctionIsInitialized(_auction),
|
|
866
|
-
"Auction not initialized"
|
|
867
|
-
);
|
|
868
|
-
if (_auction.settled || (_auction.tokenId != _tokenId)) {
|
|
869
|
-
// auction already settled or is for a different token ID, so
|
|
870
|
-
// return early and do not modify state
|
|
871
|
-
return;
|
|
872
|
-
}
|
|
873
|
-
// @dev important that the following check is after the early return
|
|
874
|
-
// block above to maintain desired behavior
|
|
875
|
-
require(block.timestamp >= _auction.endTime, "Auction not yet ended");
|
|
876
|
-
// EFFECTS
|
|
877
|
-
_auction.settled = true;
|
|
878
|
-
// INTERACTIONS
|
|
879
|
-
// send token to the winning bidder
|
|
880
|
-
IERC721(_coreContract).transferFrom({
|
|
881
|
-
from: address(this),
|
|
882
|
-
to: currentBidder,
|
|
883
|
-
tokenId: _tokenId
|
|
884
|
-
});
|
|
885
|
-
// distribute revenues from auction
|
|
886
|
-
bool isEngine = SplitFundsLib.isEngine(
|
|
887
|
-
_coreContract,
|
|
888
|
-
_isEngineCaches[_coreContract]
|
|
889
|
-
);
|
|
890
|
-
SplitFundsLib.splitRevenuesETH({
|
|
891
|
-
_projectId: _projectId,
|
|
892
|
-
_valueInWei: currentBid,
|
|
893
|
-
_coreContract: _coreContract,
|
|
894
|
-
_isEngine: isEngine
|
|
895
|
-
});
|
|
896
|
-
|
|
897
|
-
emit AuctionSettled({
|
|
898
|
-
tokenId: _tokenId,
|
|
899
|
-
coreContract: _coreContract,
|
|
900
|
-
winner: currentBidder,
|
|
901
|
-
price: currentBid
|
|
902
|
-
});
|
|
802
|
+
SEALib.settleAuction({tokenId: tokenId, coreContract: coreContract});
|
|
903
803
|
}
|
|
904
804
|
|
|
905
805
|
/**
|
|
906
|
-
* @notice Enters a bid for token `
|
|
907
|
-
* If an auction for token `
|
|
806
|
+
* @notice Enters a bid for token `tokenId`.
|
|
807
|
+
* If an auction for token `tokenId` does not exist, an auction will be
|
|
908
808
|
* initialized as long as any existing auction for the project has been
|
|
909
809
|
* settled.
|
|
910
810
|
* In order to successfully place the bid, the token bid must be:
|
|
@@ -924,7 +824,7 @@ contract MinterSEAV1 is ReentrancyGuard, ISharedMinterV0, ISharedMinterSEAV0 {
|
|
|
924
824
|
* outbid and their funds are returned to the original `msg.sender` address
|
|
925
825
|
* via SELFDESTRUCT (SENDALL).
|
|
926
826
|
* ------------------------------------------------------------------------
|
|
927
|
-
* Note that the use of `
|
|
827
|
+
* Note that the use of `tokenId` is to prevent the possibility of
|
|
928
828
|
* transactions that are stuck in the pending pool for long periods of time
|
|
929
829
|
* from unintentionally bidding on auctions for future tokens.
|
|
930
830
|
* If a new auction is initialized during this call, the project's next
|
|
@@ -932,259 +832,22 @@ contract MinterSEAV1 is ReentrancyGuard, ISharedMinterV0, ISharedMinterSEAV0 {
|
|
|
932
832
|
* it for the next auction. If the project's next token cannot be minted
|
|
933
833
|
* due to e.g. reaching the maximum invocations on the core contract or
|
|
934
834
|
* minter, the project's next token will not be minted.
|
|
935
|
-
* @param
|
|
936
|
-
* @param
|
|
835
|
+
* @param tokenId Token ID being bid on.
|
|
836
|
+
* @param coreContract Core contract address for the given project.
|
|
937
837
|
* @dev nonReentrant modifier is used to prevent reentrancy attacks, e.g.
|
|
938
838
|
* an an auto-bidder that would be able to atomically outbid a user's
|
|
939
839
|
* new bid via a reentrant call to createBid.
|
|
940
840
|
*/
|
|
941
841
|
function createBid(
|
|
942
|
-
uint256
|
|
943
|
-
address
|
|
842
|
+
uint256 tokenId,
|
|
843
|
+
address coreContract
|
|
944
844
|
) public payable nonReentrant {
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
// ProjectConfig storage _projectConfig = projectConfig[_projectId];
|
|
952
|
-
// load from storage to memory for gas efficiency
|
|
953
|
-
uint256 auctionEndTime = _auction.endTime;
|
|
954
|
-
uint256 previousBid = _auction.currentBid;
|
|
955
|
-
|
|
956
|
-
// if no auction exists, or current auction is already settled, attempt
|
|
957
|
-
// to initialize a new auction for the input token ID and immediately
|
|
958
|
-
// return
|
|
959
|
-
if ((!SEALib.auctionIsInitialized(_auction)) || _auction.settled) {
|
|
960
|
-
_initializeAuctionWithBid(_projectId, _coreContract, _tokenId);
|
|
961
|
-
return;
|
|
962
|
-
}
|
|
963
|
-
// @dev this branch is guaranteed to have an initialized auction that
|
|
964
|
-
// not settled, so no need to check for initialized or not settled
|
|
965
|
-
|
|
966
|
-
// ensure bids for a specific token ID are only applied to the auction
|
|
967
|
-
// for that token ID.
|
|
968
|
-
require(
|
|
969
|
-
_auction.tokenId == _tokenId,
|
|
970
|
-
"Token ID does not match auction"
|
|
971
|
-
);
|
|
972
|
-
|
|
973
|
-
// ensure auction is not already ended
|
|
974
|
-
require(auctionEndTime > block.timestamp, "Auction already ended");
|
|
975
|
-
|
|
976
|
-
// require bid to be sufficiently greater than current highest bid
|
|
977
|
-
// @dev no overflow enforced automatically by solidity ^0.8.0
|
|
978
|
-
require(
|
|
979
|
-
msg.value >= SEALib.getMinimumNextBid(_auction),
|
|
980
|
-
"Bid is too low"
|
|
981
|
-
);
|
|
982
|
-
|
|
983
|
-
// EFFECTS
|
|
984
|
-
// record previous highest bider for refunding
|
|
985
|
-
address payable previousBidder = _auction.currentBidder;
|
|
986
|
-
|
|
987
|
-
// update auction bid state
|
|
988
|
-
SEALib.auctionUpdateBid({
|
|
989
|
-
_auction: _auction,
|
|
990
|
-
_timeBufferSeconds: minterTimeBufferSeconds,
|
|
991
|
-
_bidAmount: msg.value,
|
|
992
|
-
_bidder: payable(msg.sender)
|
|
993
|
-
});
|
|
994
|
-
|
|
995
|
-
// INTERACTIONS
|
|
996
|
-
// refund previous highest bidder
|
|
997
|
-
SplitFundsLib.forceSafeTransferETH({
|
|
998
|
-
_to: previousBidder,
|
|
999
|
-
_amount: previousBid,
|
|
1000
|
-
_minterRefundGasLimit: minterRefundGasLimit
|
|
1001
|
-
});
|
|
1002
|
-
|
|
1003
|
-
emit AuctionBid({
|
|
1004
|
-
tokenId: _tokenId,
|
|
1005
|
-
coreContract: _coreContract,
|
|
1006
|
-
bidder: msg.sender,
|
|
1007
|
-
bidAmount: msg.value
|
|
1008
|
-
});
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
/**
|
|
1012
|
-
* @dev Internal function to initialize an auction for the next token ID
|
|
1013
|
-
* on project `_projectId` with a bid of `msg.value` from `msg.sender`.
|
|
1014
|
-
* This function reverts in any of the following cases:
|
|
1015
|
-
* - project is not configured on this minter
|
|
1016
|
-
* - project is configured but has not yet reached its start time
|
|
1017
|
-
* - project has a current active auction that is not settled
|
|
1018
|
-
* - insufficient bid amount (msg.value < basePrice)
|
|
1019
|
-
* - no next token has been minted for the project (artist may need to
|
|
1020
|
-
* call `tryPopulateNextToken`)
|
|
1021
|
-
* - `_targetTokenId` does not match the next token ID for the project
|
|
1022
|
-
* After initializing a new auction, this function attempts to mint a new
|
|
1023
|
-
* token and assign it to the project's next token slot, in preparation for
|
|
1024
|
-
* a future token auction. However, if the project has reached its maximum
|
|
1025
|
-
* invocations on either the core contract or minter, the next token slot
|
|
1026
|
-
* for the project will remain empty.
|
|
1027
|
-
* @dev This should be executed in a nonReentrant context to provide redundant
|
|
1028
|
-
* protection against reentrancy.
|
|
1029
|
-
*/
|
|
1030
|
-
function _initializeAuctionWithBid(
|
|
1031
|
-
uint256 _projectId,
|
|
1032
|
-
address _coreContract,
|
|
1033
|
-
uint256 _targetTokenId
|
|
1034
|
-
) internal {
|
|
1035
|
-
SEALib.SEAProjectConfig storage _SEAProjectConfig = _SEAProjectConfigs[
|
|
1036
|
-
_coreContract
|
|
1037
|
-
][_projectId];
|
|
1038
|
-
SEALib.Auction storage _auction = _SEAProjectConfig.activeAuction;
|
|
1039
|
-
// CHECKS
|
|
1040
|
-
// ensure project auctions are configured
|
|
1041
|
-
// @dev base price of zero indicates auctions are not configured
|
|
1042
|
-
// because only base price of gt zero is allowed when configuring
|
|
1043
|
-
require(
|
|
1044
|
-
SEALib.projectIsConfigured(_SEAProjectConfig),
|
|
1045
|
-
"Project not configured"
|
|
1046
|
-
);
|
|
1047
|
-
// only initialize new auctions if they meet the start time
|
|
1048
|
-
// requirement
|
|
1049
|
-
require(
|
|
1050
|
-
block.timestamp >= _SEAProjectConfig.timestampStart,
|
|
1051
|
-
"Only gte project start time"
|
|
1052
|
-
);
|
|
1053
|
-
// the following require statement is redundant based on how this
|
|
1054
|
-
// internal function is called, but it is included for protection
|
|
1055
|
-
// against future changes that could easily introduce a bug if this
|
|
1056
|
-
// check is not present
|
|
1057
|
-
// @dev no cover else branch of next line because unreachable
|
|
1058
|
-
require(
|
|
1059
|
-
(!SEALib.auctionIsInitialized(_auction)) || _auction.settled,
|
|
1060
|
-
"Existing auction not settled"
|
|
1061
|
-
);
|
|
1062
|
-
// require valid bid value
|
|
1063
|
-
require(
|
|
1064
|
-
msg.value >= _SEAProjectConfig.basePrice,
|
|
1065
|
-
"Insufficient initial bid"
|
|
1066
|
-
);
|
|
1067
|
-
// require next token number is populated
|
|
1068
|
-
// @dev this should only be encountered if the project has reached
|
|
1069
|
-
// its maximum invocations on either the core contract or minter
|
|
1070
|
-
require(
|
|
1071
|
-
_SEAProjectConfig.nextTokenNumberIsPopulated,
|
|
1072
|
-
"No next token, check max invocations"
|
|
1073
|
-
);
|
|
1074
|
-
// require next token number is the target token ID
|
|
1075
|
-
require(
|
|
1076
|
-
_SEAProjectConfig.nextTokenNumber ==
|
|
1077
|
-
ABHelpers.tokenIdToTokenNumber(_targetTokenId),
|
|
1078
|
-
"Incorrect target token ID"
|
|
1079
|
-
);
|
|
1080
|
-
|
|
1081
|
-
// EFFECTS
|
|
1082
|
-
// create new auction, overwriting previous auction if it exists
|
|
1083
|
-
uint64 endTime = SEALib.overwriteProjectActiveAuction({
|
|
1084
|
-
_SEAProjectConfig: _SEAProjectConfig,
|
|
1085
|
-
_targetTokenId: _targetTokenId,
|
|
1086
|
-
_bidAmount: msg.value,
|
|
1087
|
-
_bidder: payable(msg.sender)
|
|
1088
|
-
});
|
|
1089
|
-
// mark next token number as not populated
|
|
1090
|
-
// @dev intentionally not setting nextTokenNumber to zero to avoid
|
|
1091
|
-
// unnecessary gas costs
|
|
1092
|
-
_SEAProjectConfig.nextTokenNumberIsPopulated = false;
|
|
1093
|
-
|
|
1094
|
-
// @dev we intentionally emit event here due to potential of early
|
|
1095
|
-
// return in INTERACTIONS section
|
|
1096
|
-
emit AuctionInitialized({
|
|
1097
|
-
tokenId: _targetTokenId,
|
|
1098
|
-
coreContract: _coreContract,
|
|
1099
|
-
bidder: msg.sender,
|
|
1100
|
-
bidAmount: msg.value,
|
|
1101
|
-
endTime: endTime,
|
|
1102
|
-
minBidIncrementPercentage: _SEAProjectConfig
|
|
1103
|
-
.activeAuction
|
|
1104
|
-
.minBidIncrementPercentage
|
|
1105
|
-
});
|
|
1106
|
-
|
|
1107
|
-
// INTERACTIONS
|
|
1108
|
-
// attempt to mint new token to this minter contract, only if max
|
|
1109
|
-
// invocations has not been reached
|
|
1110
|
-
_tryMintTokenToNextSlot(_projectId, _coreContract);
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
/**
|
|
1114
|
-
* @notice Internal function that attempts to mint a new token to the next
|
|
1115
|
-
* token slot for the project `_projectId`.
|
|
1116
|
-
* This function returns early and does not modify state if
|
|
1117
|
-
* - the project has reached its maximum invocations on either the core
|
|
1118
|
-
* contract or minter
|
|
1119
|
-
* - the project config's `nextTokenNumberIsPopulated` is already true
|
|
1120
|
-
* @param _projectId The ID of the project to mint a new token for.
|
|
1121
|
-
* @param _coreContract The core contract address
|
|
1122
|
-
* @dev this calls mint with `msg.sender` as the sender, allowing artists
|
|
1123
|
-
* to mint tokens to the next token slot for their project while a project
|
|
1124
|
-
* is still paused. This happens when an artist is configuring their
|
|
1125
|
-
* project's auction parameters or minter max invocations.
|
|
1126
|
-
*/
|
|
1127
|
-
function _tryMintTokenToNextSlot(
|
|
1128
|
-
uint256 _projectId,
|
|
1129
|
-
address _coreContract
|
|
1130
|
-
) internal {
|
|
1131
|
-
SEALib.SEAProjectConfig storage _SEAProjectConfig = _SEAProjectConfigs[
|
|
1132
|
-
_coreContract
|
|
1133
|
-
][_projectId];
|
|
1134
|
-
MaxInvocationsLib.MaxInvocationsProjectConfig
|
|
1135
|
-
storage _maxInvocationProjectConfig = _maxInvocationsProjectConfigMapping[
|
|
1136
|
-
_coreContract
|
|
1137
|
-
][_projectId];
|
|
1138
|
-
if (_SEAProjectConfig.nextTokenNumberIsPopulated) {
|
|
1139
|
-
return;
|
|
1140
|
-
}
|
|
1141
|
-
// INTERACTIONS
|
|
1142
|
-
// attempt to mint new token to this minter contract, only if max
|
|
1143
|
-
// invocations has not been reached
|
|
1144
|
-
// we require up-to-date invocation data to properly handle last token
|
|
1145
|
-
// and avoid revert if relying on core to limit invocations, therefore
|
|
1146
|
-
// use MaxInvocationsLib.invocationsRemain, which calls core contract
|
|
1147
|
-
// to get latest invocation data
|
|
1148
|
-
if (
|
|
1149
|
-
!MaxInvocationsLib.invocationsRemain(
|
|
1150
|
-
_maxInvocationProjectConfig,
|
|
1151
|
-
_projectId,
|
|
1152
|
-
_coreContract
|
|
1153
|
-
)
|
|
1154
|
-
) {
|
|
1155
|
-
// we have reached the max invocations, so we do not mint a new
|
|
1156
|
-
// token as the "next token", and leave the next token number as
|
|
1157
|
-
// not populated
|
|
1158
|
-
return;
|
|
1159
|
-
}
|
|
1160
|
-
// @dev this is an effect after a trusted contract interaction
|
|
1161
|
-
_SEAProjectConfig.nextTokenNumberIsPopulated = true;
|
|
1162
|
-
// mint a new token to this project's "next token" slot
|
|
1163
|
-
// @dev this is an interaction with a trusted contract
|
|
1164
|
-
uint256 nextTokenId = minterFilter.mint_joo(
|
|
1165
|
-
address(this),
|
|
1166
|
-
_projectId,
|
|
1167
|
-
_coreContract,
|
|
1168
|
-
msg.sender
|
|
1169
|
-
);
|
|
1170
|
-
// update state to reflect new token number
|
|
1171
|
-
// @dev state changes after trusted contract interaction
|
|
1172
|
-
// @dev unchecked is safe because mod 1e6 is guaranteed to be less than
|
|
1173
|
-
// max uint24
|
|
1174
|
-
unchecked {
|
|
1175
|
-
_SEAProjectConfig.nextTokenNumber = uint24(
|
|
1176
|
-
ABHelpers.tokenIdToTokenNumber(nextTokenId)
|
|
1177
|
-
);
|
|
1178
|
-
}
|
|
1179
|
-
// update local maxHasBeenInvoked value if necessary
|
|
1180
|
-
MaxInvocationsLib.validatePurchaseEffectsInvocations({
|
|
1181
|
-
_tokenId: nextTokenId,
|
|
1182
|
-
maxInvocationsProjectConfig: _maxInvocationProjectConfig
|
|
1183
|
-
});
|
|
1184
|
-
emit ProjectNextTokenUpdated({
|
|
1185
|
-
projectId: _projectId,
|
|
1186
|
-
coreContract: _coreContract,
|
|
1187
|
-
tokenId: nextTokenId
|
|
845
|
+
SEALib.createBid({
|
|
846
|
+
tokenId: tokenId,
|
|
847
|
+
coreContract: coreContract,
|
|
848
|
+
minterTimeBufferSeconds: _minterTimeBufferSeconds,
|
|
849
|
+
minterRefundGasLimit: _minterRefundGasLimit,
|
|
850
|
+
minterFilter: _minterFilter
|
|
1188
851
|
});
|
|
1189
852
|
}
|
|
1190
853
|
}
|