|
@@ -6,17 +6,17 @@ pragma solidity ^0.8.0;
|
|
|
import "../ERC721.sol";
|
|
|
import "../../../interfaces/IERC2309.sol";
|
|
|
import "../../../utils/Checkpoints.sol";
|
|
|
-import "../../../utils/math/SafeCast.sol";
|
|
|
import "../../../utils/structs/BitMaps.sol";
|
|
|
|
|
|
/**
|
|
|
* @dev Implementation of the ERC2309 "Consecutive Transfer Extension" as defined in
|
|
|
* https://eips.ethereum.org/EIPS/eip-2309[EIP-2309].
|
|
|
*
|
|
|
- * This extension allows the minting of large batches of tokens during the contract construction. These batches are
|
|
|
- * limited to 5000 tokens at a time to accommodate off-chain indexers.
|
|
|
+ * This extension allows the minting of large batches of tokens, during contract construction only. For upgradeable
|
|
|
+ * contracts this implies that batch minting is only available during proxy deployment, and not in subsequent upgrades.
|
|
|
+ * These batches are limited to 5000 tokens at a time by default to accommodate off-chain indexers.
|
|
|
*
|
|
|
- * Using this extension removes the ability to mint single tokens during the contract construction. This ability is
|
|
|
+ * Using this extension removes the ability to mint single tokens during contract construction. This ability is
|
|
|
* regained after construction. During construction, only batch minting is allowed.
|
|
|
*
|
|
|
* IMPORTANT: This extension bypasses the hooks {_beforeTokenTransfer} and {_afterTokenTransfer} for tokens minted in
|
|
@@ -36,6 +36,18 @@ abstract contract ERC721Consecutive is IERC2309, ERC721 {
|
|
|
Checkpoints.Trace160 private _sequentialOwnership;
|
|
|
BitMaps.BitMap private _sequentialBurn;
|
|
|
|
|
|
+ /**
|
|
|
+ * @dev Maximum size of a batch of consecutive tokens. This is designed to limit stress on off-chain indexing
|
|
|
+ * services that have to record one entry per token, and have protections against "unreasonably large" batches of
|
|
|
+ * tokens.
|
|
|
+ *
|
|
|
+ * NOTE: Overriding the default value of 5000 will not cause on-chain issues, but may result in the asset not being
|
|
|
+ * correctly supported by off-chain indexing services (including marketplaces).
|
|
|
+ */
|
|
|
+ function _maxBatchSize() internal view virtual returns (uint96) {
|
|
|
+ return 5000;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* @dev See {ERC721-_ownerOf}. Override that checks the sequential ownership structure for tokens that have
|
|
|
* been minted as part of a batch, and not yet transferred.
|
|
@@ -54,13 +66,18 @@ abstract contract ERC721Consecutive is IERC2309, ERC721 {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * @dev Mint a batch of tokens of length `batchSize` for `to`.
|
|
|
+ * @dev Mint a batch of tokens of length `batchSize` for `to`. Returns the token id of the first token minted in the
|
|
|
+ * batch; if `batchSize` is 0, returns the number of consecutive ids minted so far.
|
|
|
+ *
|
|
|
+ * Requirements:
|
|
|
+ *
|
|
|
+ * - `batchSize` must not be greater than {_maxBatchSize}.
|
|
|
+ * - The function is called in the constructor of the contract (directly or indirectly).
|
|
|
*
|
|
|
- * WARNING: Consecutive mint is only available during construction. ERC721 requires that any minting done after
|
|
|
- * construction emits a `Transfer` event, which is not the case of mints performed using this function.
|
|
|
+ * CAUTION: Does not emit a `Transfer` event. This is ERC721 compliant as long as it is done outside of the
|
|
|
+ * constructor, which is enforced by this function.
|
|
|
*
|
|
|
- * WARNING: Consecutive mint is limited to batches of 5000 tokens. Further minting is possible from a contract's
|
|
|
- * point of view but would cause indexing issues for off-chain services.
|
|
|
+ * CAUTION: Does not invoke `onERC721Received` on the receiver.
|
|
|
*
|
|
|
* Emits a {ConsecutiveTransfer} event.
|
|
|
*/
|
|
@@ -71,7 +88,7 @@ abstract contract ERC721Consecutive is IERC2309, ERC721 {
|
|
|
if (batchSize > 0) {
|
|
|
require(!Address.isContract(address(this)), "ERC721Consecutive: batch minting restricted to constructor");
|
|
|
require(to != address(0), "ERC721Consecutive: mint to the zero address");
|
|
|
- require(batchSize <= 5000, "ERC721Consecutive: batch too large");
|
|
|
+ require(batchSize <= _maxBatchSize(), "ERC721Consecutive: batch too large");
|
|
|
|
|
|
// hook before
|
|
|
_beforeConsecutiveTokenTransfer(address(0), to, first, batchSize);
|
|
@@ -100,7 +117,7 @@ abstract contract ERC721Consecutive is IERC2309, ERC721 {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * @dev See {ERC721-_afterTokenTransfer}. Burning of token that have been sequentially minted must be explicit.
|
|
|
+ * @dev See {ERC721-_afterTokenTransfer}. Burning of tokens that have been sequentially minted must be explicit.
|
|
|
*/
|
|
|
function _afterTokenTransfer(
|
|
|
address from,
|
|
@@ -109,7 +126,7 @@ abstract contract ERC721Consecutive is IERC2309, ERC721 {
|
|
|
) internal virtual override {
|
|
|
if (
|
|
|
to == address(0) && // if we burn
|
|
|
- tokenId <= _totalConsecutiveSupply() && // and the tokenId was minted is a batch
|
|
|
+ tokenId < _totalConsecutiveSupply() && // and the tokenId was minted in a batch
|
|
|
!_sequentialBurn.get(tokenId) // and the token was never marked as burnt
|
|
|
) {
|
|
|
_sequentialBurn.set(tokenId);
|