Fix ERC721Consecutive balance update on batch size 1

Merge pull request from GHSA-878m-3g6q-594q

Co-authored-by: Francisco Giordano <fg@frang.io>
(cherry picked from commit 8ba26f388f)
This commit is contained in:
Hadrien Croubois
2023-03-02 23:41:28 +01:00
committed by Francisco Giordano
parent 82d47ca7b3
commit 167bf67ed3
5 changed files with 149 additions and 12 deletions

View File

@ -467,18 +467,9 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
function _beforeTokenTransfer(
address from,
address to,
uint256, /* firstTokenId */
uint256 firstTokenId,
uint256 batchSize
) internal virtual {
if (batchSize > 1) {
if (from != address(0)) {
_balances[from] -= batchSize;
}
if (to != address(0)) {
_balances[to] += batchSize;
}
}
}
) internal virtual {}
/**
* @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is
@ -500,4 +491,16 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
uint256 firstTokenId,
uint256 batchSize
) internal virtual {}
/**
* @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override.
*
* WARNING: Anyone calling this MUST ensure that the balances remain consistent with the ownership. The invariant
* being that for any address `a` the value returned by `balanceOf(a)` must be equal to the number of tokens such
* that `ownerOf(tokenId)` is `a`.
*/
// solhint-disable-next-line func-name-mixedcase
function __unsafe_increaseBalance(address account, uint256 amount) internal {
_balances[account] += amount;
}
}

View File

@ -96,6 +96,11 @@ abstract contract ERC721Consecutive is IERC2309, ERC721 {
// push an ownership checkpoint & emit event
uint96 last = first + 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`.
__unsafe_increaseBalance(to, batchSize);
emit ConsecutiveTransfer(first, last, address(0), to);
// hook after