diff --git a/.gas-snapshot b/.gas-snapshot index fa2fdf6..7a08900 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -3,22 +3,22 @@ BaseInvariantTest:invariantMirror721BalanceSum() (runs: 30, calls: 450, reverts: BaseInvariantTest:invariantMirrorAndBaseRemainImmutable() (runs: 30, calls: 450, reverts: 0) BaseInvariantTest:invariantTotalReflectionIsValid() (runs: 30, calls: 450, reverts: 0) BaseInvariantTest:invariantUserReflectionIsValid() (runs: 30, calls: 450, reverts: 0) -BenchTest:testMintAndTransferDN404_01() (gas: 208984) -BenchTest:testMintAndTransferDN404_02() (gas: 215086) -BenchTest:testMintAndTransferDN404_03() (gas: 221232) -BenchTest:testMintAndTransferDN404_04() (gas: 227379) -BenchTest:testMintAndTransferDN404_05() (gas: 255470) -BenchTest:testMintAndTransferDN404_06() (gas: 261593) -BenchTest:testMintAndTransferDN404_07() (gas: 267731) -BenchTest:testMintAndTransferDN404_08() (gas: 273863) -BenchTest:testMintAndTransferDN404_09() (gas: 345754) -BenchTest:testMintAndTransferDN404_10() (gas: 351835) -BenchTest:testMintAndTransferDN404_11() (gas: 358046) -BenchTest:testMintAndTransferDN404_12() (gas: 364126) -BenchTest:testMintAndTransferDN404_13() (gas: 392173) -BenchTest:testMintAndTransferDN404_14() (gas: 398385) -BenchTest:testMintAndTransferDN404_15() (gas: 404533) -BenchTest:testMintAndTransferDN404_16() (gas: 410678) +BenchTest:testMintAndTransferDN404_01() (gas: 208504) +BenchTest:testMintAndTransferDN404_02() (gas: 214588) +BenchTest:testMintAndTransferDN404_03() (gas: 220716) +BenchTest:testMintAndTransferDN404_04() (gas: 226845) +BenchTest:testMintAndTransferDN404_05() (gas: 254918) +BenchTest:testMintAndTransferDN404_06() (gas: 261023) +BenchTest:testMintAndTransferDN404_07() (gas: 267143) +BenchTest:testMintAndTransferDN404_08() (gas: 273257) +BenchTest:testMintAndTransferDN404_09() (gas: 345130) +BenchTest:testMintAndTransferDN404_10() (gas: 351193) +BenchTest:testMintAndTransferDN404_11() (gas: 357386) +BenchTest:testMintAndTransferDN404_12() (gas: 363448) +BenchTest:testMintAndTransferDN404_13() (gas: 391477) +BenchTest:testMintAndTransferDN404_14() (gas: 397671) +BenchTest:testMintAndTransferDN404_15() (gas: 403801) +BenchTest:testMintAndTransferDN404_16() (gas: 409928) BenchTest:testMintAndTransferDN420_01() (gas: 135827) BenchTest:testMintAndTransferDN420_02() (gas: 138887) BenchTest:testMintAndTransferDN420_03() (gas: 141970) @@ -35,22 +35,22 @@ BenchTest:testMintAndTransferDN420_13() (gas: 172843) BenchTest:testMintAndTransferDN420_14() (gas: 175926) BenchTest:testMintAndTransferDN420_15() (gas: 178987) BenchTest:testMintAndTransferDN420_16() (gas: 182049) -BenchTest:testMintDN404_01() (gas: 123546) -BenchTest:testMintDN404_02() (gas: 126639) -BenchTest:testMintDN404_03() (gas: 129707) -BenchTest:testMintDN404_04() (gas: 132802) -BenchTest:testMintDN404_05() (gas: 157836) -BenchTest:testMintDN404_06() (gas: 160907) -BenchTest:testMintDN404_07() (gas: 163998) -BenchTest:testMintDN404_08() (gas: 167114) -BenchTest:testMintDN404_09() (gas: 213961) -BenchTest:testMintDN404_10() (gas: 217055) -BenchTest:testMintDN404_11() (gas: 220168) -BenchTest:testMintDN404_12() (gas: 223238) -BenchTest:testMintDN404_13() (gas: 248231) -BenchTest:testMintDN404_14() (gas: 251322) -BenchTest:testMintDN404_15() (gas: 254456) -BenchTest:testMintDN404_16() (gas: 257528) +BenchTest:testMintDN404_01() (gas: 123309) +BenchTest:testMintDN404_02() (gas: 126402) +BenchTest:testMintDN404_03() (gas: 129470) +BenchTest:testMintDN404_04() (gas: 132565) +BenchTest:testMintDN404_05() (gas: 157599) +BenchTest:testMintDN404_06() (gas: 160670) +BenchTest:testMintDN404_07() (gas: 163761) +BenchTest:testMintDN404_08() (gas: 166877) +BenchTest:testMintDN404_09() (gas: 213724) +BenchTest:testMintDN404_10() (gas: 216818) +BenchTest:testMintDN404_11() (gas: 219931) +BenchTest:testMintDN404_12() (gas: 223001) +BenchTest:testMintDN404_13() (gas: 247994) +BenchTest:testMintDN404_14() (gas: 251085) +BenchTest:testMintDN404_15() (gas: 254219) +BenchTest:testMintDN404_16() (gas: 257291) BenchTest:testMintDN420_01() (gas: 94501) BenchTest:testMintDN420_02() (gas: 95950) BenchTest:testMintDN420_03() (gas: 97333) @@ -67,81 +67,81 @@ BenchTest:testMintDN420_13() (gas: 111640) BenchTest:testMintDN420_14() (gas: 113114) BenchTest:testMintDN420_15() (gas: 114496) BenchTest:testMintDN420_16() (gas: 115948) -BenchTest:test__codesize() (gas: 28697) -DN404CustomUnitTest:testInitializeCorrectUnitSuccess() (gas: 129992) +BenchTest:test__codesize() (gas: 28670) +DN404CustomUnitTest:testInitializeCorrectUnitSuccess() (gas: 129962) DN404CustomUnitTest:testInitializeWithUnitTooLargeReverts() (gas: 33824) DN404CustomUnitTest:testInitializeWithZeroUnitReverts() (gas: 13897) -DN404CustomUnitTest:testMint() (gas: 764779) -DN404CustomUnitTest:testMintWithoutNFTs(uint256,uint256,uint256) (runs: 258, μ: 685149, ~: 764102) -DN404CustomUnitTest:testNFTMint() (gas: 59220902) -DN404CustomUnitTest:testNFTMintAndBurn(uint256,uint256,uint256) (runs: 258, μ: 1144481, ~: 763505) -DN404CustomUnitTest:testNFTMintViaTransfer(uint256,uint256,uint256) (runs: 258, μ: 735928, ~: 842344) -DN404CustomUnitTest:testTotalSupplyOverflowsTrick(uint256,uint256) (runs: 258, μ: 638, ~: 692) -DN404CustomUnitTest:testTotalSupplyOverflowsTrick(uint256,uint256,uint256) (runs: 258, μ: 780, ~: 746) +DN404CustomUnitTest:testMint() (gas: 764319) +DN404CustomUnitTest:testMintWithoutNFTs(uint256,uint256,uint256) (runs: 258, μ: 670118, ~: 763731) +DN404CustomUnitTest:testNFTMint() (gas: 60455413) +DN404CustomUnitTest:testNFTMintAndBurn(uint256,uint256,uint256) (runs: 258, μ: 1168345, ~: 763069) +DN404CustomUnitTest:testNFTMintViaTransfer(uint256,uint256,uint256) (runs: 258, μ: 705503, ~: 841285) +DN404CustomUnitTest:testTotalSupplyOverflowsTrick(uint256,uint256) (runs: 258, μ: 635, ~: 692) +DN404CustomUnitTest:testTotalSupplyOverflowsTrick(uint256,uint256,uint256) (runs: 258, μ: 781, ~: 746) DN404CustomUnitTest:testUnitInvalidCheckTrick(uint256) (runs: 258, μ: 548, ~: 550) -DN404CustomUnitTest:test__codesize() (gas: 28387) -DN404MirrorTest:testBaseERC20() (gas: 114608) +DN404CustomUnitTest:test__codesize() (gas: 28382) +DN404MirrorTest:testBaseERC20() (gas: 114578) DN404MirrorTest:testFnSelectorNotRecognized() (gas: 7032) DN404MirrorTest:testLinkMirrorContract() (gas: 45864) -DN404MirrorTest:testLogDirectTransfers() (gas: 1610907) -DN404MirrorTest:testLogTransfer() (gas: 120685) -DN404MirrorTest:testNameAndSymbol(string,string) (runs: 258, μ: 207604, ~: 208117) +DN404MirrorTest:testLogDirectTransfers() (gas: 1606798) +DN404MirrorTest:testLogTransfer() (gas: 120655) +DN404MirrorTest:testNameAndSymbol(string,string) (runs: 258, μ: 207574, ~: 208087) DN404MirrorTest:testNotLinked() (gas: 12767) -DN404MirrorTest:testPullOwner() (gas: 112643) -DN404MirrorTest:testPullOwnerWithOwnable() (gas: 3289528) -DN404MirrorTest:testSafeTransferFrom(uint32) (runs: 258, μ: 2315506, ~: 2315489) -DN404MirrorTest:testSetAndGetApprovalForAll() (gas: 2170983) -DN404MirrorTest:testSetAndGetApproved() (gas: 2167717) +DN404MirrorTest:testPullOwner() (gas: 112613) +DN404MirrorTest:testPullOwnerWithOwnable() (gas: 3284890) +DN404MirrorTest:testSafeTransferFrom(uint32) (runs: 258, μ: 2308447, ~: 2308395) +DN404MirrorTest:testSetAndGetApprovalForAll() (gas: 2165706) +DN404MirrorTest:testSetAndGetApproved() (gas: 2162800) DN404MirrorTest:testSupportsInterface() (gas: 7544) -DN404MirrorTest:testTokenURI(string,uint256) (runs: 258, μ: 158086, ~: 135821) -DN404MirrorTest:testTransferFrom(uint32) (runs: 258, μ: 2219126, ~: 2219076) -DN404MirrorTest:testTransferFromMixed(uint256) (runs: 258, μ: 10844442, ~: 8629376) -DN404MirrorTest:test__codesize() (gas: 57325) +DN404MirrorTest:testTokenURI(string,uint256) (runs: 258, μ: 158056, ~: 135791) +DN404MirrorTest:testTransferFrom(uint32) (runs: 258, μ: 2209990, ~: 2210027) +DN404MirrorTest:testTransferFromMixed(uint256) (runs: 258, μ: 10566022, ~: 8538957) +DN404MirrorTest:test__codesize() (gas: 57279) DN404OnlyERC20Test:testApprove() (gas: 35803) DN404OnlyERC20Test:testApprove(address,uint256) (runs: 258, μ: 30119, ~: 31354) -DN404OnlyERC20Test:testBurn() (gas: 52009) -DN404OnlyERC20Test:testBurn(address,uint256,uint256) (runs: 258, μ: 53070, ~: 53210) -DN404OnlyERC20Test:testBurnInsufficientBalanceReverts(address,uint256,uint256) (runs: 258, μ: 46324, ~: 46312) -DN404OnlyERC20Test:testInfiniteApproveTransferFrom() (gas: 104918) +DN404OnlyERC20Test:testBurn() (gas: 51486) +DN404OnlyERC20Test:testBurn(address,uint256,uint256) (runs: 258, μ: 52571, ~: 52687) +DN404OnlyERC20Test:testBurnInsufficientBalanceReverts(address,uint256,uint256) (runs: 258, μ: 45709, ~: 45780) +DN404OnlyERC20Test:testInfiniteApproveTransferFrom() (gas: 104368) DN404OnlyERC20Test:testMaxSupplyTrick(uint256) (runs: 258, μ: 541, ~: 541) DN404OnlyERC20Test:testMetadata() (gas: 10044) -DN404OnlyERC20Test:testMint() (gas: 47577) -DN404OnlyERC20Test:testMintOverMaxLimitReverts() (gas: 43571) -DN404OnlyERC20Test:testMintz(address,uint256) (runs: 258, μ: 47891, ~: 47999) -DN404OnlyERC20Test:testTransfer() (gas: 77636) -DN404OnlyERC20Test:testTransfer(address,uint256) (runs: 258, μ: 77963, ~: 78093) -DN404OnlyERC20Test:testTransferFrom() (gas: 87376) -DN404OnlyERC20Test:testTransferFrom(address,address,address,uint256,uint256) (runs: 258, μ: 107960, ~: 110345) -DN404OnlyERC20Test:testTransferFromInsufficientAllowanceReverts() (gas: 70282) -DN404OnlyERC20Test:testTransferFromInsufficientAllowanceReverts(address,uint256,uint256) (runs: 258, μ: 70985, ~: 71392) -DN404OnlyERC20Test:testTransferFromInsufficientBalanceReverts() (gas: 77235) -DN404OnlyERC20Test:testTransferFromInsufficientBalanceReverts(address,uint256,uint256) (runs: 258, μ: 78305, ~: 78356) -DN404OnlyERC20Test:testTransferInsufficientBalanceReverts() (gas: 68734) -DN404OnlyERC20Test:testTransferInsufficientBalanceReverts(address,uint256,uint256) (runs: 258, μ: 69868, ~: 69830) -DN404OnlyERC20Test:test__codesize() (gas: 30292) -DN404Test:testBatchNFTLog() (gas: 3670932) -DN404Test:testBurnOnTransfer(uint32,address) (runs: 258, μ: 1644456, ~: 1501184) +DN404OnlyERC20Test:testMint() (gas: 47556) +DN404OnlyERC20Test:testMintOverMaxLimitReverts() (gas: 43535) +DN404OnlyERC20Test:testMintz(address,uint256) (runs: 258, μ: 48044, ~: 47978) +DN404OnlyERC20Test:testTransfer() (gas: 77086) +DN404OnlyERC20Test:testTransfer(address,uint256) (runs: 258, μ: 77436, ~: 77543) +DN404OnlyERC20Test:testTransferFrom() (gas: 86826) +DN404OnlyERC20Test:testTransferFrom(address,address,address,uint256,uint256) (runs: 258, μ: 107523, ~: 109795) +DN404OnlyERC20Test:testTransferFromInsufficientAllowanceReverts() (gas: 70261) +DN404OnlyERC20Test:testTransferFromInsufficientAllowanceReverts(address,uint256,uint256) (runs: 258, μ: 70785, ~: 71366) +DN404OnlyERC20Test:testTransferFromInsufficientBalanceReverts() (gas: 76697) +DN404OnlyERC20Test:testTransferFromInsufficientBalanceReverts(address,uint256,uint256) (runs: 258, μ: 77843, ~: 77818) +DN404OnlyERC20Test:testTransferInsufficientBalanceReverts() (gas: 68196) +DN404OnlyERC20Test:testTransferInsufficientBalanceReverts(address,uint256,uint256) (runs: 258, μ: 69230, ~: 69292) +DN404OnlyERC20Test:test__codesize() (gas: 30269) +DN404Test:testBatchNFTLog() (gas: 3843676) +DN404Test:testBurnOnTransfer(uint32,address) (runs: 258, μ: 1651212, ~: 1497089) DN404Test:testFnSelectorNotRecognized() (gas: 6974) -DN404Test:testInitialize(uint32,address) (runs: 258, μ: 113100, ~: 116323) -DN404Test:testMintAndBurn() (gas: 2792646) -DN404Test:testMintAndBurn2() (gas: 3355751) -DN404Test:testMintNext() (gas: 2476800) -DN404Test:testMintNextMixed(uint256) (runs: 258, μ: 11279993, ~: 7283849) -DN404Test:testMintOnTransfer(uint32,address) (runs: 258, μ: 1016576, ~: 903330) -DN404Test:testMixed(uint256) (runs: 258, μ: 9190713, ~: 5481989) -DN404Test:testNameAndSymbol(string,string) (runs: 258, μ: 207322, ~: 207835) -DN404Test:testNumAliasesOverflowReverts() (gas: 57369) -DN404Test:testOwnedIds() (gas: 15735632) -DN404Test:testOwnedIds(uint256) (runs: 258, μ: 1677360, ~: 1513374) -DN404Test:testPermit2() (gas: 2899852) -DN404Test:testRegisterAndResolveAlias(address,address) (runs: 258, μ: 126590, ~: 126677) +DN404Test:testInitialize(uint32,address) (runs: 258, μ: 112875, ~: 116293) +DN404Test:testMintAndBurn() (gas: 2785258) +DN404Test:testMintAndBurn2() (gas: 3346549) +DN404Test:testMintNext() (gas: 2471299) +DN404Test:testMintNextMixed(uint256) (runs: 258, μ: 11300860, ~: 7087341) +DN404Test:testMintOnTransfer(uint32,address) (runs: 258, μ: 995234, ~: 901215) +DN404Test:testMixed(uint256) (runs: 258, μ: 9821914, ~: 6304092) +DN404Test:testNameAndSymbol(string,string) (runs: 258, μ: 207292, ~: 207805) +DN404Test:testNumAliasesOverflowReverts() (gas: 57345) +DN404Test:testOwnedIds() (gas: 15691833) +DN404Test:testOwnedIds(uint256) (runs: 258, μ: 1667659, ~: 1509731) +DN404Test:testPermit2() (gas: 2892016) +DN404Test:testRegisterAndResolveAlias(address,address) (runs: 258, μ: 126419, ~: 126593) DN404Test:testSetAndGetAux(address,uint88) (runs: 258, μ: 22075, ~: 22344) -DN404Test:testSetAndGetOperatorApprovals(address,address,bool) (runs: 258, μ: 129289, ~: 120342) -DN404Test:testSetAndGetSkipNFT() (gas: 719817) -DN404Test:testTokenURI(string,uint256) (runs: 258, μ: 157952, ~: 135687) -DN404Test:testTransfersAndBurns() (gas: 2924439) -DN404Test:testWrapAround(uint32,uint256) (runs: 258, μ: 3705836, ~: 3425799) -DN404Test:test__codesize() (gas: 57382) +DN404Test:testSetAndGetOperatorApprovals(address,address,bool) (runs: 258, μ: 129363, ~: 120416) +DN404Test:testSetAndGetSkipNFT() (gas: 719127) +DN404Test:testTokenURI(string,uint256) (runs: 258, μ: 157922, ~: 135657) +DN404Test:testTransfersAndBurns() (gas: 2916475) +DN404Test:testWrapAround(uint32,uint256) (runs: 258, μ: 3746256, ~: 3412953) +DN404Test:test__codesize() (gas: 57359) DN420OnlyERC20Test:testApprove() (gas: 35770) DN420OnlyERC20Test:testApprove(address,uint256) (runs: 258, μ: 30086, ~: 31321) DN420OnlyERC20Test:testBurn() (gas: 50438) @@ -190,21 +190,21 @@ MappingsTest:testUint32MapSetAndGet(uint256) (runs: 258, μ: 1322218, ~: 1465647 MappingsTest:testUint32MapSetAndGet(uint256,uint256,uint32,uint32) (runs: 258, μ: 43149, ~: 46200) MappingsTest:testWrapNFTIdWithOverflowCheck(uint256,uint256,uint256) (runs: 258, μ: 826, ~: 852) MappingsTest:test__codesize() (gas: 9063) -MintTests:test_WhenAmountIsGreaterThan_MAX_SUPPLYOrMintMakesNFTTotalSupplyExceed_MAX_SUPPLY(uint256) (runs: 258, μ: 777538, ~: 680342) -MintTests:test_WhenRecipientAddressHasSkipNFTEnabled(uint256) (runs: 258, μ: 793418, ~: 701518) -MintTests:test_WhenRecipientIsAddress0(uint256) (runs: 258, μ: 694980, ~: 646331) -MintTests:test_WhenRecipientsBalanceDifferenceIsNotUpTo1e18(uint256) (runs: 258, μ: 1029051, ~: 698516) -MintTests:test_WhenRecipientsBalanceDifferenceIsUpTo1e18OrAbove(uint256) (runs: 258, μ: 781120, ~: 705038) -MintTests:test__codesize() (gas: 26743) -NFTMintDN404Test:testAllowlistMint() (gas: 257485) -NFTMintDN404Test:testMint() (gas: 231816) -NFTMintDN404Test:testTotalSupplyReached() (gas: 629746900) -NFTMintDN404Test:test__codesize() (gas: 26536) -SimpleDN404Test:testMint() (gas: 47592) +MintTests:test_WhenAmountIsGreaterThan_MAX_SUPPLYOrMintMakesNFTTotalSupplyExceed_MAX_SUPPLY(uint256) (runs: 258, μ: 789234, ~: 678293) +MintTests:test_WhenRecipientAddressHasSkipNFTEnabled(uint256) (runs: 258, μ: 796376, ~: 699877) +MintTests:test_WhenRecipientIsAddress0(uint256) (runs: 258, μ: 686507, ~: 644635) +MintTests:test_WhenRecipientsBalanceDifferenceIsNotUpTo1e18(uint256) (runs: 258, μ: 1034804, ~: 696763) +MintTests:test_WhenRecipientsBalanceDifferenceIsUpTo1e18OrAbove(uint256) (runs: 258, μ: 790552, ~: 703210) +MintTests:test__codesize() (gas: 26720) +NFTMintDN404Test:testAllowlistMint() (gas: 257449) +NFTMintDN404Test:testMint() (gas: 231750) +NFTMintDN404Test:testTotalSupplyReached() (gas: 629566900) +NFTMintDN404Test:test__codesize() (gas: 26501) +SimpleDN404Test:testMint() (gas: 47571) SimpleDN404Test:testName() (gas: 9674) SimpleDN404Test:testSetBaseURI() (gas: 47011) SimpleDN404Test:testSymbol() (gas: 9672) SimpleDN404Test:testWithdraw() (gas: 18277) -SimpleDN404Test:test__codesize() (gas: 20255) +SimpleDN404Test:test__codesize() (gas: 20220) SoladyTest:test__codesize() (gas: 1102) TestPlus:test__codesize() (gas: 406) \ No newline at end of file diff --git a/src/DN404.sol b/src/DN404.sol index ee51fa1..7346d0b 100644 --- a/src/DN404.sol +++ b/src/DN404.sol @@ -331,7 +331,7 @@ abstract contract DN404 { function allowance(address owner, address spender) public view returns (uint256) { if (_givePermit2DefaultInfiniteAllowance() && spender == _PERMIT2) { uint8 flags = _getDN404Storage().addressData[owner].flags; - if (flags & _ADDRESS_DATA_OVERRIDE_PERMIT2_FLAG == 0) return type(uint256).max; + if (_isZero(flags & _ADDRESS_DATA_OVERRIDE_PERMIT2_FLAG)) return type(uint256).max; } return _ref(_getDN404Storage().allowance, owner, spender).value; } @@ -382,7 +382,7 @@ abstract contract DN404 { Uint256Ref storage a = _ref(_getDN404Storage().allowance, from, msg.sender); uint256 allowed = _givePermit2DefaultInfiniteAllowance() && msg.sender == _PERMIT2 - && (_getDN404Storage().addressData[from].flags & _ADDRESS_DATA_OVERRIDE_PERMIT2_FLAG) == 0 + && _isZero(_getDN404Storage().addressData[from].flags & _ADDRESS_DATA_OVERRIDE_PERMIT2_FLAG) ? type(uint256).max : a.value; @@ -439,7 +439,7 @@ abstract contract DN404 { maxId = totalSupply_ / _unit(); } unchecked { - if (toAddressData.flags & _ADDRESS_DATA_SKIP_NFT_FLAG == 0) { + if (_isZero(toAddressData.flags & _ADDRESS_DATA_SKIP_NFT_FLAG)) { Uint32Map storage toOwned = $.owned[to]; Uint32Map storage oo = $.oo; uint256 toIndex = toAddressData.ownedLength; @@ -521,7 +521,7 @@ abstract contract DN404 { maxId = totalSupply_ / _unit(); } unchecked { - if (toAddressData.flags & _ADDRESS_DATA_SKIP_NFT_FLAG == 0) { + if (_isZero(toAddressData.flags & _ADDRESS_DATA_SKIP_NFT_FLAG)) { Uint32Map storage toOwned = $.owned[to]; Uint32Map storage oo = $.oo; uint256 toIndex = toAddressData.ownedLength; @@ -571,10 +571,10 @@ abstract contract DN404 { /// /// Emits a {Transfer} event. function _burn(address from, uint256 amount) internal virtual { - AddressData storage fromAddressData = _addressData(from); DN404Storage storage $ = _getDN404Storage(); if ($.mirrorERC721 == address(0)) revert DNNotInitialized(); + AddressData storage fromAddressData = $.addressData[from]; uint256 fromBalance = fromAddressData.balance; if (amount > fromBalance) revert InsufficientBalance(); @@ -644,9 +644,9 @@ abstract contract DN404 { function _transfer(address from, address to, uint256 amount) internal virtual { if (to == address(0)) revert TransferToZeroAddress(); - AddressData storage fromAddressData = _addressData(from); - AddressData storage toAddressData = _addressData(to); DN404Storage storage $ = _getDN404Storage(); + AddressData storage fromAddressData = $.addressData[from]; + AddressData storage toAddressData = _addressData(to); if ($.mirrorERC721 == address(0)) revert DNNotInitialized(); _DNTransferTemps memory t; @@ -663,7 +663,7 @@ abstract contract DN404 { toAddressData.balance = uint96(toBalance); t.numNFTBurns = _zeroFloorSub(t.fromOwnedLength, fromBalance / _unit()); - if (toAddressData.flags & _ADDRESS_DATA_SKIP_NFT_FLAG == 0) { + if (_isZero(toAddressData.flags & _ADDRESS_DATA_SKIP_NFT_FLAG)) { if (from == to) t.toOwnedLength = t.fromOwnedLength - t.numNFTBurns; t.numNFTMints = _zeroFloorSub(toBalance / _unit(), t.toOwnedLength); } @@ -671,7 +671,7 @@ abstract contract DN404 { while (_useDirectTransfersIfPossible()) { uint256 n = _min(t.fromOwnedLength, _min(t.numNFTBurns, t.numNFTMints)); - if (n == 0) break; + if (_isZero(n)) break; t.numNFTBurns -= n; t.numNFTMints -= n; if (from == to) { @@ -683,18 +683,19 @@ abstract contract DN404 { Uint32Map storage toOwned = $.owned[to]; t.toAlias = _registerAndResolveAlias(toAddressData, to); uint256 toIndex = t.toOwnedLength; + n = toIndex + n; // Direct transfer loop. do { uint256 id = _get(fromOwned, --t.fromOwnedLength); _set(toOwned, toIndex, uint32(id)); - _setOwnerAliasAndOwnedIndex($.oo, id, t.toAlias, uint32(toIndex++)); + _setOwnerAliasAndOwnedIndex($.oo, id, t.toAlias, uint32(toIndex)); _directLogsAppend(directLogs, id); if (_get($.mayHaveNFTApproval, id)) { _set($.mayHaveNFTApproval, id, false); delete $.nftApprovals[id]; } _afterNFTTransfer(from, to, id); - } while (--n != 0); + } while (++toIndex != n); toAddressData.ownedLength = uint32(t.toOwnedLength = toIndex); fromAddressData.ownedLength = uint32(t.fromOwnedLength); @@ -805,19 +806,18 @@ abstract contract DN404 { } if (msgSender != from) { - if (_ref($.operatorApprovals, from, msgSender).value == 0) { - if (msgSender != $.nftApprovals[id]) { + if (!_isApprovedForAll(from, msgSender)) { + if (_getApproved(id) != msgSender) { revert TransferCallerNotOwnerNorApproved(); } } } - AddressData storage fromAddressData = _addressData(from); - AddressData storage toAddressData = _addressData(to); + AddressData storage fromAddressData = $.addressData[from]; + AddressData storage toAddressData = $.addressData[to]; uint256 unit = _unit(); mapping(address => Uint32Map) storage owned = $.owned; - Uint32Map storage fromOwned = owned[from]; unchecked { uint256 fromBalance = fromAddressData.balance; @@ -830,6 +830,7 @@ abstract contract DN404 { delete $.nftApprovals[id]; } unchecked { + Uint32Map storage fromOwned = owned[from]; uint32 updatedId = _get(fromOwned, --fromAddressData.ownedLength); uint32 i = _get(oo, _ownedIndex(id)); _set(fromOwned, i, updatedId); @@ -897,7 +898,7 @@ abstract contract DN404 { /// Returns false otherwise. function getSkipNFT(address owner) public view virtual returns (bool) { AddressData storage d = _getDN404Storage().addressData[owner]; - if (d.flags & _ADDRESS_DATA_INITIALIZED_FLAG == 0) return _hasCode(owner); + if (_isZero(d.flags & _ADDRESS_DATA_INITIALIZED_FLAG)) return _hasCode(owner); return d.flags & _ADDRESS_DATA_SKIP_NFT_FLAG != 0; } @@ -932,7 +933,7 @@ abstract contract DN404 { function _addressData(address owner) internal virtual returns (AddressData storage d) { d = _getDN404Storage().addressData[owner]; unchecked { - if (d.flags & _ADDRESS_DATA_INITIALIZED_FLAG == 0) { + if (_isZero(d.flags & _ADDRESS_DATA_INITIALIZED_FLAG)) { uint256 skipNFT = _toUint(_hasCode(owner)) * _ADDRESS_DATA_SKIP_NFT_FLAG; d.flags = uint8(skipNFT | _ADDRESS_DATA_INITIALIZED_FLAG); } @@ -949,13 +950,13 @@ abstract contract DN404 { { DN404Storage storage $ = _getDN404Storage(); addressAlias = toAddressData.addressAlias; - if (addressAlias == 0) { + if (_isZero(addressAlias)) { unchecked { addressAlias = ++$.numAliases; } toAddressData.addressAlias = addressAlias; $.aliasToAddress[addressAlias] = to; - if (addressAlias == 0) revert(); // Overflow. + if (_isZero(addressAlias)) revert(); // Overflow. } } @@ -994,6 +995,16 @@ abstract contract DN404 { return _ownerAt(id); } + /// @dev Returns whether `operator` is approved to manage the NFT tokens of `owner`. + function _isApprovedForAll(address owner, address operator) + internal + view + virtual + returns (bool) + { + return !_isZero(_ref(_getDN404Storage().operatorApprovals, owner, operator).value); + } + /// @dev Returns if token `id` exists. function _exists(uint256 id) internal view virtual returns (bool) { return _ownerAt(id) != address(0); @@ -1022,7 +1033,7 @@ abstract contract DN404 { owner = $.aliasToAddress[_get($.oo, _ownershipIndex(_restrictNFTId(id)))]; if (msgSender != owner) { - if (_ref($.operatorApprovals, owner, msgSender).value == 0) { + if (!_isApprovedForAll(owner, msgSender)) { revert ApprovalCallerNotOwnerNorApproved(); } } @@ -1096,12 +1107,11 @@ abstract contract DN404 { } // `isApprovedForAll(address,address)`. if (fnSelector == 0xe985e9c5) { - Uint256Ref storage ref = _ref( - $.operatorApprovals, + bool result = _isApprovedForAll( address(uint160(_calldataload(0x04))), // `owner`. address(uint160(_calldataload(0x24))) // `operator`. ); - _return(ref.value); + _return(_toUint(result)); } // `ownerOf(uint256)`. if (fnSelector == 0x6352211e) { @@ -1350,6 +1360,14 @@ abstract contract DN404 { } } + /// @dev Returns `b == 0`. This is because solc is sometimes dumb. + function _isZero(uint256 x) internal pure returns (bool result) { + /// @solidity memory-safe-assembly + assembly { + result := iszero(x) + } + } + /// @dev Struct containing direct transfer log data for {Transfer} events to be /// emitted by the mirror NFT contract. struct _DNDirectLogs {