diff --git a/.gas-snapshot b/.gas-snapshot index c64ff83e28..e1cd56fa17 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -227,7 +227,7 @@ ERC4337FactoryTest:test__codesize() (gas: 13520) ERC4337Test:testCdFallback() (gas: 443989) ERC4337Test:testCdFallback2() (gas: 1140699) ERC4337Test:testDelegateExecute() (gas: 369570) -ERC4337Test:testDelegateExecute(uint256) (runs: 256, μ: 355685, ~: 344555) +ERC4337Test:testDelegateExecute(uint256) (runs: 256, μ: 354073, ~: 344555) ERC4337Test:testDelegateExecuteRevertsIfOwnerSlotValueChanged() (gas: 319282) ERC4337Test:testDepositFunctions() (gas: 502955) ERC4337Test:testDirectStorage() (gas: 70413) @@ -235,17 +235,17 @@ ERC4337Test:testDisableInitializerForImplementation() (gas: 1177324) ERC4337Test:testETHReceived() (gas: 16584) ERC4337Test:testExecute() (gas: 382786) ERC4337Test:testExecuteBatch() (gas: 692605) -ERC4337Test:testExecuteBatch(uint256) (runs: 256, μ: 514103, ~: 368298) +ERC4337Test:testExecuteBatch(uint256) (runs: 256, μ: 514311, ~: 368308) ERC4337Test:testInitializer() (gas: 285192) ERC4337Test:testIsValidSignature() (gas: 111663) ERC4337Test:testIsValidSignaturePersonalSign() (gas: 96270) ERC4337Test:testIsValidSignatureWrapped() (gas: 406706) ERC4337Test:testOnERC1155BatchReceived() (gas: 1393788) ERC4337Test:testOnERC1155Received() (gas: 1391111) -ERC4337Test:testOnERC721Received() (gas: 1372839) +ERC4337Test:testOnERC721Received() (gas: 1373839) ERC4337Test:testOwnerRecovery() (gas: 486105) ERC4337Test:testValidateUserOp() (gas: 491555) -ERC4337Test:test__codesize() (gas: 54809) +ERC4337Test:test__codesize() (gas: 54814) ERC4626Test:testDepositWithNoApprovalReverts() (gas: 16371) ERC4626Test:testDepositWithNotEnoughApprovalReverts() (gas: 89884) ERC4626Test:testDifferentialFullMulDiv(uint256,uint256,uint256) (runs: 256, μ: 3325, ~: 3185) @@ -266,21 +266,21 @@ ERC4626Test:testWithdrawWithNotEnoughUnderlyingAmountReverts() (gas: 144074) ERC4626Test:testWithdrawZero() (gas: 52807) ERC4626Test:test__codesize() (gas: 41067) ERC6551Test:testCdFallback() (gas: 894601) -ERC6551Test:testDeployERC6551(uint256) (runs: 256, μ: 171354, ~: 168782) +ERC6551Test:testDeployERC6551(uint256) (runs: 256, μ: 170920, ~: 168777) ERC6551Test:testDeployERC6551Proxy() (gas: 80751) ERC6551Test:testExecute() (gas: 507965) ERC6551Test:testExecuteBatch() (gas: 817065) -ERC6551Test:testExecuteBatch(uint256) (runs: 256, μ: 601662, ~: 483230) +ERC6551Test:testExecuteBatch(uint256) (runs: 256, μ: 630683, ~: 570903) ERC6551Test:testInitializeERC6551ProxyImplementation() (gas: 189823) ERC6551Test:testIsValidSignature() (gas: 187678) ERC6551Test:testOnERC1155BatchReceived() (gas: 1526564) ERC6551Test:testOnERC1155Received() (gas: 1523920) -ERC6551Test:testOnERC721Received() (gas: 1509583) +ERC6551Test:testOnERC721Received() (gas: 1510587) ERC6551Test:testOnERC721ReceivedCycles() (gas: 1714722) -ERC6551Test:testOnERC721ReceivedCyclesWithDifferentChainIds(uint256) (runs: 256, μ: 449035, ~: 454283) +ERC6551Test:testOnERC721ReceivedCyclesWithDifferentChainIds(uint256) (runs: 256, μ: 448956, ~: 454381) ERC6551Test:testSupportsInterface() (gas: 169409) ERC6551Test:testUpgrade() (gas: 1154933) -ERC6551Test:test__codesize() (gas: 48069) +ERC6551Test:test__codesize() (gas: 48074) ERC6909Test:testApprove() (gas: 36771) ERC6909Test:testApprove(address,uint256,uint256) (runs: 256, μ: 36480, ~: 37413) ERC6909Test:testBurn() (gas: 40676) @@ -317,57 +317,57 @@ ERC6909Test:testTransferInsufficientBalanceReverts(address,uint256,uint256,uint2 ERC6909Test:testTransferOverMaxUintReverts() (gas: 63438) ERC6909Test:testTransferOverMaxUintReverts(address,uint256,uint256,uint256) (runs: 256, μ: 63957, ~: 63967) ERC6909Test:test__codesize() (gas: 26802) -ERC721HooksTest:testERC721Hooks() (gas: 2945944) -ERC721HooksTest:test__codesize() (gas: 10033) -ERC721Test:testApprove(uint256) (runs: 256, μ: 108117, ~: 108141) -ERC721Test:testApproveAll(uint256) (runs: 256, μ: 47505, ~: 40334) -ERC721Test:testApproveBurn(uint256) (runs: 256, μ: 86810, ~: 86860) -ERC721Test:testApproveNonExistentReverts(uint256,address) (runs: 256, μ: 33635, ~: 33571) -ERC721Test:testApproveUnauthorizedReverts(uint256) (runs: 256, μ: 83253, ~: 82370) +ERC721HooksTest:testERC721Hooks() (gas: 2946944) +ERC721HooksTest:test__codesize() (gas: 10038) +ERC721Test:testApprove(uint256) (runs: 256, μ: 108129, ~: 108147) +ERC721Test:testApproveAll(uint256) (runs: 256, μ: 48290, ~: 40341) +ERC721Test:testApproveBurn(uint256) (runs: 256, μ: 86795, ~: 86844) +ERC721Test:testApproveNonExistentReverts(uint256,address) (runs: 256, μ: 33647, ~: 33709) +ERC721Test:testApproveUnauthorizedReverts(uint256) (runs: 256, μ: 83243, ~: 82363) ERC721Test:testAuthorizedEquivalence(address,bool,bool) (runs: 256, μ: 748, ~: 743) -ERC721Test:testAux(uint256) (runs: 256, μ: 191960, ~: 193100) -ERC721Test:testBurn(uint256) (runs: 256, μ: 83077, ~: 94049) +ERC721Test:testAux(uint256) (runs: 256, μ: 191910, ~: 193095) +ERC721Test:testBurn(uint256) (runs: 256, μ: 83148, ~: 94030) ERC721Test:testBurnNonExistentReverts(uint256) (runs: 256, μ: 10783, ~: 10783) -ERC721Test:testCannotExceedMaxBalance() (gas: 149932) -ERC721Test:testDoubleBurnReverts(uint256) (runs: 256, μ: 63588, ~: 63538) -ERC721Test:testDoubleMintReverts(uint256) (runs: 256, μ: 79180, ~: 79211) -ERC721Test:testEverything(uint256) (runs: 256, μ: 311696, ~: 378404) -ERC721Test:testExtraData(uint256) (runs: 256, μ: 99104, ~: 99180) +ERC721Test:testCannotExceedMaxBalance() (gas: 169111) +ERC721Test:testDoubleBurnReverts(uint256) (runs: 256, μ: 63594, ~: 63538) +ERC721Test:testDoubleMintReverts(uint256) (runs: 256, μ: 79187, ~: 79211) +ERC721Test:testEverything(uint256) (runs: 256, μ: 317690, ~: 340864) +ERC721Test:testExtraData(uint256) (runs: 256, μ: 99090, ~: 99184) ERC721Test:testExtraData2(uint256,uint256) (runs: 256, μ: 54285, ~: 53934) -ERC721Test:testIsApprovedOrOwner(uint256) (runs: 256, μ: 135193, ~: 135205) -ERC721Test:testMint(uint256) (runs: 256, μ: 82833, ~: 82756) -ERC721Test:testMintAndSetExtraDataUnchecked(uint256) (runs: 256, μ: 84364, ~: 84400) -ERC721Test:testMintAndSetExtraDataUncheckedWithOverwrite(uint256,uint96) (runs: 256, μ: 83617, ~: 83531) -ERC721Test:testMintToZeroReverts(uint256) (runs: 256, μ: 10327, ~: 10327) -ERC721Test:testOwnerOfNonExistent(uint256) (runs: 256, μ: 33394, ~: 33338) -ERC721Test:testSafeMintToEOA(uint256) (runs: 256, μ: 83361, ~: 83403) -ERC721Test:testSafeMintToERC721Recipient(uint256) (runs: 256, μ: 409324, ~: 410440) -ERC721Test:testSafeMintToERC721RecipientWithData(uint256,bytes) (runs: 256, μ: 470749, ~: 459869) +ERC721Test:testIsApprovedOrOwner(uint256) (runs: 256, μ: 135217, ~: 135219) +ERC721Test:testMint(uint256) (runs: 256, μ: 82843, ~: 82886) +ERC721Test:testMintAndSetExtraDataUnchecked(uint256) (runs: 256, μ: 84346, ~: 84383) +ERC721Test:testMintAndSetExtraDataUncheckedWithOverwrite(uint256,uint96) (runs: 256, μ: 83607, ~: 83670) +ERC721Test:testMintToZeroReverts(uint256) (runs: 256, μ: 34708, ~: 34708) +ERC721Test:testOwnerOfNonExistent(uint256) (runs: 256, μ: 33396, ~: 33338) +ERC721Test:testSafeMintToEOA(uint256) (runs: 256, μ: 83361, ~: 83402) +ERC721Test:testSafeMintToERC721Recipient(uint256) (runs: 256, μ: 409336, ~: 410440) +ERC721Test:testSafeMintToERC721RecipientWithData(uint256,bytes) (runs: 256, μ: 470767, ~: 460033) ERC721Test:testSafeMintToERC721RecipientWithWrongReturnData(uint256) (runs: 256, μ: 169942, ~: 169942) ERC721Test:testSafeMintToERC721RecipientWithWrongReturnDataWithData(uint256,bytes) (runs: 256, μ: 171157, ~: 171104) ERC721Test:testSafeMintToNonERC721RecipientReverts(uint256) (runs: 256, μ: 100404, ~: 100404) ERC721Test:testSafeMintToNonERC721RecipientWithDataReverts(uint256,bytes) (runs: 256, μ: 101651, ~: 101598) ERC721Test:testSafeMintToRevertingERC721RecipientReverts(uint256) (runs: 256, μ: 203061, ~: 203061) ERC721Test:testSafeMintToRevertingERC721RecipientWithDataReverts(uint256,bytes) (runs: 256, μ: 204297, ~: 204244) -ERC721Test:testSafeTransferFromToEOA(uint256) (runs: 256, μ: 121877, ~: 122025) -ERC721Test:testSafeTransferFromToERC721Recipient(uint256) (runs: 256, μ: 470923, ~: 472054) -ERC721Test:testSafeTransferFromToERC721RecipientWithData(uint256,bytes) (runs: 256, μ: 532348, ~: 521614) -ERC721Test:testSafeTransferFromToERC721RecipientWithWrongReturnDataReverts(uint256) (runs: 256, μ: 200897, ~: 200952) -ERC721Test:testSafeTransferFromToERC721RecipientWithWrongReturnDataWithDataReverts(uint256,bytes) (runs: 256, μ: 202134, ~: 202148) -ERC721Test:testSafeTransferFromToNonERC721RecipientReverts(uint256) (runs: 256, μ: 131304, ~: 131242) -ERC721Test:testSafeTransferFromToNonERC721RecipientWithDataReverts(uint256,bytes) (runs: 256, μ: 132615, ~: 132624) -ERC721Test:testSafeTransferFromToRevertingERC721RecipientReverts(uint256) (runs: 256, μ: 233972, ~: 234030) -ERC721Test:testSafeTransferFromToRevertingERC721RecipientWithDataReverts(uint256,bytes) (runs: 256, μ: 235285, ~: 235290) +ERC721Test:testSafeTransferFromToEOA(uint256) (runs: 256, μ: 121953, ~: 122046) +ERC721Test:testSafeTransferFromToERC721Recipient(uint256) (runs: 256, μ: 470927, ~: 472054) +ERC721Test:testSafeTransferFromToERC721RecipientWithData(uint256,bytes) (runs: 256, μ: 532341, ~: 521625) +ERC721Test:testSafeTransferFromToERC721RecipientWithWrongReturnDataReverts(uint256) (runs: 256, μ: 200903, ~: 200953) +ERC721Test:testSafeTransferFromToERC721RecipientWithWrongReturnDataWithDataReverts(uint256,bytes) (runs: 256, μ: 202131, ~: 202141) +ERC721Test:testSafeTransferFromToNonERC721RecipientReverts(uint256) (runs: 256, μ: 131303, ~: 131242) +ERC721Test:testSafeTransferFromToNonERC721RecipientWithDataReverts(uint256,bytes) (runs: 256, μ: 132611, ~: 132625) +ERC721Test:testSafeTransferFromToRevertingERC721RecipientReverts(uint256) (runs: 256, μ: 233969, ~: 234021) +ERC721Test:testSafeTransferFromToRevertingERC721RecipientWithDataReverts(uint256,bytes) (runs: 256, μ: 235271, ~: 235281) ERC721Test:testSafetyOfCustomStorage(uint256,uint256) (runs: 256, μ: 1063, ~: 713) ERC721Test:testTransferFrom() (gas: 85788) -ERC721Test:testTransferFrom(uint256) (runs: 256, μ: 114217, ~: 112500) -ERC721Test:testTransferFromApproveAll(uint256) (runs: 256, μ: 119313, ~: 119288) -ERC721Test:testTransferFromNotExistentReverts(address,address,uint256) (runs: 256, μ: 34038, ~: 34014) -ERC721Test:testTransferFromNotOwner(uint256) (runs: 256, μ: 84776, ~: 84735) -ERC721Test:testTransferFromSelf(uint256) (runs: 256, μ: 92733, ~: 92714) -ERC721Test:testTransferFromToZeroReverts(uint256) (runs: 256, μ: 79086, ~: 79067) -ERC721Test:testTransferFromWrongFromReverts(address,uint256) (runs: 256, μ: 80462, ~: 80467) -ERC721Test:test__codesize() (gas: 43506) +ERC721Test:testTransferFrom(uint256) (runs: 256, μ: 114011, ~: 112477) +ERC721Test:testTransferFromApproveAll(uint256) (runs: 256, μ: 119325, ~: 119309) +ERC721Test:testTransferFromNotExistentReverts(address,address,uint256) (runs: 256, μ: 34033, ~: 34014) +ERC721Test:testTransferFromNotOwner(uint256) (runs: 256, μ: 84763, ~: 84735) +ERC721Test:testTransferFromSelf(uint256) (runs: 256, μ: 92730, ~: 92715) +ERC721Test:testTransferFromToZeroReverts(uint256) (runs: 256, μ: 79097, ~: 79067) +ERC721Test:testTransferFromWrongFromReverts(address,uint256) (runs: 256, μ: 80472, ~: 80458) +ERC721Test:test__codesize() (gas: 43725) FixedPointMathLibTest:testAbs() (gas: 578) FixedPointMathLibTest:testAbs(int256) (runs: 256, μ: 516, ~: 485) FixedPointMathLibTest:testAbsEdgeCases() (gas: 410) diff --git a/src/tokens/ERC721.sol b/src/tokens/ERC721.sol index ef8bece111..ec70872254 100644 --- a/src/tokens/ERC721.sol +++ b/src/tokens/ERC721.sol @@ -505,23 +505,19 @@ abstract contract ERC721 { assembly { // Clear the upper 96 bits. to := shr(96, shl(96, to)) - // Revert if `to` is the zero address. - if iszero(to) { - mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. - revert(0x1c, 0x04) - } + // Update with the owner and extra data. mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) - // Update with the owner and extra data. sstore(add(id, add(id, keccak256(0x00, 0x20))), or(shl(160, value), to)) // Increment the balance of the owner. { mstore(0x00, to) let balanceSlot := keccak256(0x0c, 0x1c) let balanceSlotPacked := add(sload(balanceSlot), 1) - if iszero(and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE)) { - mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. - revert(0x1c, 0x04) + if iszero(mul(to, and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE))) { + // `TransferToZeroAddress()`, `AccountBalanceOverflow()`. + mstore(0x00, 0xea553b3401336cea) + revert(xor(0x1c, shl(2, iszero(to))), 0x04) } sstore(balanceSlot, balanceSlotPacked) } diff --git a/test/ERC721.t.sol b/test/ERC721.t.sol index a4ded07bc0..2f3ced6c68 100644 --- a/test/ERC721.t.sol +++ b/test/ERC721.t.sol @@ -311,6 +311,9 @@ contract ERC721Test is SoladyTest { vm.expectRevert(ERC721.AccountBalanceOverflow.selector); token.mint(owner0, 1); + vm.expectRevert(ERC721.AccountBalanceOverflow.selector); + token.mintWithExtraDataUnchecked(owner0, 1, _extraData(1)); + token.uncheckedBurn(0); assertEq(token.balanceOf(owner0), 0xfffffffe); diff --git a/test/utils/mocks/MockERC721.sol b/test/utils/mocks/MockERC721.sol index 29fc6f05be..35ce78669e 100644 --- a/test/utils/mocks/MockERC721.sol +++ b/test/utils/mocks/MockERC721.sol @@ -146,7 +146,7 @@ contract MockERC721 is ERC721 { function _brutalized(uint96 value) internal view returns (uint96 result) { /// @solidity memory-safe-assembly assembly { - result := or(value, shl(160, gas())) + result := or(value, shl(96, gas())) } } }