commit2897abccc9Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Fri Jul 14 15:31:29 2023 +0200 Update ERC721.sol commite26d5c0951Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Fri Jul 14 08:46:48 2023 +0200 Update IERC721.sol commita475ffae0aAuthor: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Fri Jul 14 08:45:25 2023 +0200 Update ERC721.sol commit20bb47f439Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Fri Jul 14 08:43:14 2023 +0200 Update contracts/token/ERC721/ERC721.sol commitf404802d55Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Fri Jul 14 08:41:30 2023 +0200 Update ERC721.sol commitb982e2a808Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Fri Jul 14 08:38:46 2023 +0200 Update ERC721.behavior.js commitca32b459ecAuthor: Francisco Giordano <fg@frang.io> Date: Thu Jul 13 19:14:15 2023 -0300 fix _safeTransfer docs commitcaabbf3c46Author: Francisco Giordano <fg@frang.io> Date: Thu Jul 13 19:08:36 2023 -0300 improve warnings and notes commita023cad591Author: Francisco Giordano <fg@frang.io> Date: Thu Jul 13 18:21:27 2023 -0300 wrap long line commit5ce49a45fdAuthor: Francisco Giordano <fg@frang.io> Date: Thu Jul 13 18:19:30 2023 -0300 remove unnecessary solhint annotation commitd0375301f1Author: Francisco <fg@frang.io> Date: Thu Jul 13 18:17:24 2023 -0300 Apply suggestions from code review Co-authored-by: Ernesto García <ernestognw@gmail.com> commit81aca96467Author: Francisco <fg@frang.io> Date: Thu Jul 13 18:16:42 2023 -0300 Update CHANGELOG.md Co-authored-by: Ernesto García <ernestognw@gmail.com> commit12f63b3b1bAuthor: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Thu Jul 13 17:28:04 2023 +0200 add test commit08da709ba7Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Thu Jul 13 16:45:30 2023 +0200 refactor _checkAuhtorized commit328b16bf8cAuthor: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Thu Jul 13 16:29:05 2023 +0200 Authorised → Authorized commitb29e573383Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Thu Jul 13 16:14:57 2023 +0200 rename from → previousOwner commite996ba49d8Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Thu Jul 13 16:00:38 2023 +0200 add ERC721 specific details in the 'How to upgrade from 4.x' section of the CHANGELOG commit20048ca3b9Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Thu Jul 13 11:00:11 2023 +0200 Changes suggested in the PR discussions commit4c25b48803Merge:d7a6aaf4fb4d9510Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Thu Jul 13 10:00:55 2023 +0200 Merge branch 'refactor/erc721-update-fnPointer' of https://github.com/Amxx/openzeppelin-contracts into refactor/erc721-update-fnPointer commitd7a6aaf41fAuthor: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Thu Jul 13 10:00:50 2023 +0200 remove _exists commitfb4d9510deAuthor: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Thu Jul 13 10:00:39 2023 +0200 Apply suggestions from code review Co-authored-by: Francisco <fg@frang.io> Co-authored-by: Ernesto García <ernestognw@gmail.com> commit10815081f7Author: ernestognw <ernestognw@gmail.com> Date: Wed Jul 12 21:09:18 2023 -0600 Lint commit9ba012005fAuthor: ernestognw <ernestognw@gmail.com> Date: Wed Jul 12 20:28:50 2023 -0600 Format _increaseBalance NatSpec commit7c3f1615b0Author: Francisco <fg@frang.io> Date: Wed Jul 12 20:29:11 2023 -0300 Update .changeset/eighty-lemons-shake.md Co-authored-by: Ernesto García <ernestognw@gmail.com> commit4516803058Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Wed Jul 12 17:15:48 2023 +0200 make the safe function without a data field non virtual commite4b0e725dfAuthor: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Wed Jul 12 16:56:07 2023 +0200 use whenNotPaused in ERC721Pausable commitb973d985a4Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Wed Jul 12 14:11:59 2023 +0200 changesets commit7121ff7c5fMerge:2558c8fade570d0dAuthor: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Wed Jul 12 13:46:07 2023 +0200 Merge branch 'erc721-approve-0' into refactor/erc721-update-fnPointer commitde570d0d14Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Wed Jul 12 13:42:46 2023 +0200 allow using approve/_approve to clean approval commit2558c8fac8Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Wed Jul 12 10:16:55 2023 +0200 change _increaseBalance type to uint128 commit16f2f15673Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Wed Jul 12 10:01:30 2023 +0200 remove _isApproedOrOwner in favor of _isApproved + refactor _checkOnERC721Received commit7e9d024d08Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Wed Jul 12 09:31:18 2023 +0200 Apply suggestions from code review Co-authored-by: Ernesto García <ernestognw@gmail.com> commit1a9552009bAuthor: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Tue Jul 11 21:47:23 2023 +0200 replace constraints with a simple operator check commitbd0c52e34aAuthor: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Tue Jul 11 18:06:29 2023 +0200 refactor constraint into an optionalChecks bitmap commit5ab254cf95Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Fri Jul 7 16:13:17 2023 +0200 lint commit0bb98cb8c6Merge:562ddf567ccea54dAuthor: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Fri Jul 7 16:11:40 2023 +0200 Merge branch 'master' into feature/Governor-storage commit562ddf566aAuthor: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Wed Jul 5 18:45:42 2023 +0200 implement hybrid _update commit54cb3ca05fMerge:c7303ec2bb644589Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Mon Jul 3 21:09:30 2023 +0200 Merge branch 'master' into refactor/erc721-update-fnPointer commitc7303ec2aeAuthor: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Mon Jul 3 09:37:53 2023 +0200 fix lint commit1cc7f54ab5Merge:78c280b506861dceAuthor: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Mon Jul 3 09:35:35 2023 +0200 Merge remote-tracking branch 'upstream' into refactor/erc721-update-fnPointer commit78c280b537Merge:e2fdbacd04342118Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Fri Jun 30 18:40:55 2023 +0200 Merge branch 'master' into refactor/erc721-update-fnPointer commite9f03bd211Author: Francisco Giordano <fg@frang.io> Date: Fri Jun 30 12:09:15 2023 -0300 Exclude address(0) in ERC721._isApprovedOrOwner commite2fdbacd63Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Wed Jun 21 22:09:50 2023 +0200 fix lint commit7ec34355aeAuthor: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Wed Jun 21 17:59:22 2023 +0200 Apply suggestions from code review commit1ed8f9ef2cAuthor: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Wed Jun 21 17:56:00 2023 +0200 use __unsafe_increaseBalance to react to batch minting commita3526acdf2Author: Hadrien Croubois <hadrien.croubois@gmail.com> Date: Thu Apr 27 16:37:40 2023 +0200 Rebase ERC721._update on top of next-v5
177 lines
7.2 KiB
Solidity
177 lines
7.2 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/extensions/ERC721Consecutive.sol)
|
|
|
|
pragma solidity ^0.8.19;
|
|
|
|
import {ERC721} from "../ERC721.sol";
|
|
import {IERC2309} from "../../../interfaces/IERC2309.sol";
|
|
import {BitMaps} from "../../../utils/structs/BitMaps.sol";
|
|
import {Checkpoints} from "../../../utils/structs/Checkpoints.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 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 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
|
|
* batch. The hooks will be only called once per batch, so you should take `batchSize` parameter into consideration
|
|
* when relying on hooks.
|
|
*
|
|
* IMPORTANT: When overriding {_afterTokenTransfer}, be careful about call ordering. {ownerOf} may return invalid
|
|
* values during the {_afterTokenTransfer} execution if the super call is not called first. To be safe, execute the
|
|
* super call before your custom logic.
|
|
*/
|
|
abstract contract ERC721Consecutive is IERC2309, ERC721 {
|
|
using BitMaps for BitMaps.BitMap;
|
|
using Checkpoints for Checkpoints.Trace160;
|
|
|
|
Checkpoints.Trace160 private _sequentialOwnership;
|
|
BitMaps.BitMap private _sequentialBurn;
|
|
|
|
/**
|
|
* @dev Batch mint is restricted to the constructor.
|
|
* Any batch mint not emitting the {IERC721-Transfer} event outside of the constructor
|
|
* is non-ERC721 compliant.
|
|
*/
|
|
error ERC721ForbiddenBatchMint();
|
|
|
|
/**
|
|
* @dev Exceeds the max amount of mints per batch.
|
|
*/
|
|
error ERC721ExceededMaxBatchMint(uint256 batchSize, uint256 maxBatch);
|
|
|
|
/**
|
|
* @dev Individual minting is not allowed.
|
|
*/
|
|
error ERC721ForbiddenMint();
|
|
|
|
/**
|
|
* @dev Batch burn is not supported.
|
|
*/
|
|
error ERC721ForbiddenBatchBurn();
|
|
|
|
/**
|
|
* @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.
|
|
*/
|
|
function _ownerOf(uint256 tokenId) internal view virtual override returns (address) {
|
|
address owner = super._ownerOf(tokenId);
|
|
|
|
// If token is owned by the core, or beyond consecutive range, return base value
|
|
if (owner != address(0) || tokenId > type(uint96).max || tokenId < _firstConsecutiveId()) {
|
|
return owner;
|
|
}
|
|
|
|
// Otherwise, check the token was not burned, and fetch ownership from the anchors
|
|
// Note: no need for safe cast, we know that tokenId <= type(uint96).max
|
|
return _sequentialBurn.get(tokenId) ? address(0) : address(_sequentialOwnership.lowerLookup(uint96(tokenId)));
|
|
}
|
|
|
|
/**
|
|
* @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).
|
|
*
|
|
* CAUTION: Does not emit a `Transfer` event. This is ERC721 compliant as long as it is done inside of the
|
|
* constructor, which is enforced by this function.
|
|
*
|
|
* CAUTION: Does not invoke `onERC721Received` on the receiver.
|
|
*
|
|
* Emits a {IERC2309-ConsecutiveTransfer} event.
|
|
*/
|
|
function _mintConsecutive(address to, uint96 batchSize) internal virtual returns (uint96) {
|
|
uint96 next = _nextConsecutiveId();
|
|
|
|
// minting a batch of size 0 is a no-op
|
|
if (batchSize > 0) {
|
|
if (address(this).code.length > 0) {
|
|
revert ERC721ForbiddenBatchMint();
|
|
}
|
|
if (to == address(0)) {
|
|
revert ERC721InvalidReceiver(address(0));
|
|
}
|
|
|
|
uint256 maxBatchSize = _maxBatchSize();
|
|
if (batchSize > maxBatchSize) {
|
|
revert ERC721ExceededMaxBatchMint(batchSize, maxBatchSize);
|
|
}
|
|
|
|
// push an ownership checkpoint & emit event
|
|
uint96 last = next + batchSize - 1;
|
|
_sequentialOwnership.push(last, uint160(to));
|
|
|
|
// The invariant required by this function is preserved because the new sequentialOwnership checkpoint
|
|
// is attributing ownership of `batchSize` new tokens to account `to`.
|
|
_increaseBalance(to, batchSize);
|
|
|
|
emit ConsecutiveTransfer(next, last, address(0), to);
|
|
}
|
|
|
|
return next;
|
|
}
|
|
|
|
/**
|
|
* @dev See {ERC721-_update}. Override version that restricts normal minting to after construction.
|
|
*
|
|
* WARNING: Using {ERC721Consecutive} prevents minting during construction in favor of {_mintConsecutive}.
|
|
* After construction, {_mintConsecutive} is no longer available and minting through {_update} becomes available.
|
|
*/
|
|
function _update(address to, uint256 tokenId, address auth) internal virtual override returns (address) {
|
|
address previousOwner = super._update(to, tokenId, auth);
|
|
|
|
// only mint after construction
|
|
if (previousOwner == address(0) && address(this).code.length == 0) {
|
|
revert ERC721ForbiddenMint();
|
|
}
|
|
|
|
// record burn
|
|
if (
|
|
to == address(0) && // if we burn
|
|
tokenId < _nextConsecutiveId() && // and the tokenId was minted in a batch
|
|
!_sequentialBurn.get(tokenId) // and the token was never marked as burnt
|
|
) {
|
|
_sequentialBurn.set(tokenId);
|
|
}
|
|
|
|
return previousOwner;
|
|
}
|
|
|
|
/**
|
|
* @dev Used to offset the first token id in {_nextConsecutiveId}
|
|
*/
|
|
function _firstConsecutiveId() internal view virtual returns (uint96) {
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @dev Returns the next tokenId to mint using {_mintConsecutive}. It will return {_firstConsecutiveId}
|
|
* if no consecutive tokenId has been minted before.
|
|
*/
|
|
function _nextConsecutiveId() private view returns (uint96) {
|
|
(bool exists, uint96 latestId, ) = _sequentialOwnership.latestCheckpoint();
|
|
return exists ? latestId + 1 : _firstConsecutiveId();
|
|
}
|
|
}
|