From c607d3df5c302bd4b8671c8e1e1d3fc14a86de54 Mon Sep 17 00:00:00 2001 From: Vectorized Date: Mon, 12 Feb 2024 19:09:23 +0800 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Remove=20dependency=20on?= =?UTF-8?q?=20LibMap=20(#32)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gas-snapshot | 148 +++++++++++++++++++++++++++--------------- src/DN404.sol | 102 +++++++++++++++++++---------- test/Bench.t.sol | 166 ++++++++++++++++++++--------------------------- 3 files changed, 232 insertions(+), 184 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index e9ef622..11be98f 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,85 +1,125 @@ -BenchTest:testMintAndTransferTokensDN404_01() (gas: 212708) -BenchTest:testMintAndTransferTokensDN404_02() (gas: 247138) -BenchTest:testMintAndTransferTokensDN404_04() (gas: 274238) -BenchTest:testMintAndTransferTokensDN404_08() (gas: 348385) -BenchTest:testMintAndTransferTokensDN404_16() (gas: 540454) -BenchTest:testMintAndTransferTokensDN404_32() (gas: 924705) -BenchTest:testMintAndTransferTokensPandora_01() (gas: 190500) -BenchTest:testMintAndTransferTokensPandora_02() (gas: 306382) -BenchTest:testMintAndTransferTokensPandora_04() (gas: 538183) -BenchTest:testMintAndTransferTokensPandora_08() (gas: 1001802) -BenchTest:testMintAndTransferTokensPandora_16() (gas: 1928966) -BenchTest:testMintAndTransferTokensPandora_32() (gas: 3783400) -BenchTest:testMintTokensDN404_01() (gas: 123295) -BenchTest:testMintTokensDN404_02() (gas: 126847) -BenchTest:testMintTokensDN404_04() (gas: 155848) -BenchTest:testMintTokensDN404_08() (gas: 192064) -BenchTest:testMintTokensDN404_16() (gas: 286248) -BenchTest:testMintTokensDN404_32() (gas: 474610) -BenchTest:testMintTokensPandora_01() (gas: 133881) -BenchTest:testMintTokensPandora_02() (gas: 203429) -BenchTest:testMintTokensPandora_04() (gas: 342392) -BenchTest:testMintTokensPandora_08() (gas: 620452) -BenchTest:testMintTokensPandora_16() (gas: 1176485) -BenchTest:testMintTokensPandora_32() (gas: 2288570) -BenchTest:test__codesize() (gas: 24824) +BenchTest:testMintAndTransferDN404_01() (gas: 211467) +BenchTest:testMintAndTransferDN404_02() (gas: 244745) +BenchTest:testMintAndTransferDN404_03() (gas: 236183) +BenchTest:testMintAndTransferDN404_04() (gas: 269465) +BenchTest:testMintAndTransferDN404_05() (gas: 280824) +BenchTest:testMintAndTransferDN404_06() (gas: 314061) +BenchTest:testMintAndTransferDN404_07() (gas: 305512) +BenchTest:testMintAndTransferDN404_08() (gas: 338803) +BenchTest:testMintAndTransferDN404_09() (gas: 393918) +BenchTest:testMintAndTransferDN404_10() (gas: 427156) +BenchTest:testMintAndTransferDN404_11() (gas: 418637) +BenchTest:testMintAndTransferDN404_12() (gas: 451940) +BenchTest:testMintAndTransferDN404_13() (gas: 463255) +BenchTest:testMintAndTransferDN404_14() (gas: 496514) +BenchTest:testMintAndTransferDN404_15() (gas: 487953) +BenchTest:testMintAndTransferDN404_16() (gas: 521256) +BenchTest:testMintAndTransferPandora_01() (gas: 190491) +BenchTest:testMintAndTransferPandora_02() (gas: 306372) +BenchTest:testMintAndTransferPandora_03() (gas: 422256) +BenchTest:testMintAndTransferPandora_04() (gas: 538156) +BenchTest:testMintAndTransferPandora_05() (gas: 654092) +BenchTest:testMintAndTransferPandora_06() (gas: 769973) +BenchTest:testMintAndTransferPandora_07() (gas: 885890) +BenchTest:testMintAndTransferPandora_08() (gas: 1001773) +BenchTest:testMintAndTransferPandora_09() (gas: 1117673) +BenchTest:testMintAndTransferPandora_10() (gas: 1233556) +BenchTest:testMintAndTransferPandora_11() (gas: 1349472) +BenchTest:testMintAndTransferPandora_12() (gas: 1465408) +BenchTest:testMintAndTransferPandora_13() (gas: 1581274) +BenchTest:testMintAndTransferPandora_14() (gas: 1697190) +BenchTest:testMintAndTransferPandora_15() (gas: 1813056) +BenchTest:testMintAndTransferPandora_16() (gas: 1929009) +BenchTest:testMintDN404_01() (gas: 122943) +BenchTest:testMintDN404_02() (gas: 126123) +BenchTest:testMintDN404_03() (gas: 129263) +BenchTest:testMintDN404_04() (gas: 154390) +BenchTest:testMintDN404_05() (gas: 157571) +BenchTest:testMintDN404_06() (gas: 160689) +BenchTest:testMintDN404_07() (gas: 163940) +BenchTest:testMintDN404_08() (gas: 188978) +BenchTest:testMintDN404_09() (gas: 214083) +BenchTest:testMintDN404_10() (gas: 217246) +BenchTest:testMintDN404_11() (gas: 220427) +BenchTest:testMintDN404_12() (gas: 245511) +BenchTest:testMintDN404_13() (gas: 248694) +BenchTest:testMintDN404_14() (gas: 251855) +BenchTest:testMintDN404_15() (gas: 255079) +BenchTest:testMintDN404_16() (gas: 280142) +BenchTest:testMintPandora_01() (gas: 133912) +BenchTest:testMintPandora_02() (gas: 203416) +BenchTest:testMintPandora_03() (gas: 272897) +BenchTest:testMintPandora_04() (gas: 342371) +BenchTest:testMintPandora_05() (gas: 411929) +BenchTest:testMintPandora_06() (gas: 481455) +BenchTest:testMintPandora_07() (gas: 550914) +BenchTest:testMintPandora_08() (gas: 620441) +BenchTest:testMintPandora_09() (gas: 689944) +BenchTest:testMintPandora_10() (gas: 759449) +BenchTest:testMintPandora_11() (gas: 828907) +BenchTest:testMintPandora_12() (gas: 898435) +BenchTest:testMintPandora_13() (gas: 967960) +BenchTest:testMintPandora_14() (gas: 1037484) +BenchTest:testMintPandora_15() (gas: 1106967) +BenchTest:testMintPandora_16() (gas: 1176473) +BenchTest:test__codesize() (gas: 29464) DN404MirrorTest:testBaseERC20() (gas: 114753) DN404MirrorTest:testLinkMirrorContract() (gas: 45802) DN404MirrorTest:testLogTransfer() (gas: 120757) DN404MirrorTest:testNameAndSymbol(string,string) (runs: 256, μ: 207652, ~: 207995) DN404MirrorTest:testNotLinked() (gas: 12698) -DN404MirrorTest:testSafeTransferFrom(uint32) (runs: 256, μ: 469698, ~: 469691) -DN404MirrorTest:testSetAndGetApprovalForAll() (gas: 325387) -DN404MirrorTest:testSetAndGetApproved() (gas: 318214) +DN404MirrorTest:testSafeTransferFrom(uint32) (runs: 256, μ: 467764, ~: 467756) +DN404MirrorTest:testSetAndGetApprovalForAll() (gas: 325000) +DN404MirrorTest:testSetAndGetApproved() (gas: 318322) DN404MirrorTest:testSupportsInterface() (gas: 7544) DN404MirrorTest:testTokenURI(string,uint256) (runs: 256, μ: 158189, ~: 135888) -DN404MirrorTest:testTransferFrom(uint32) (runs: 256, μ: 344588, ~: 344576) -DN404MirrorTest:test__codesize() (gas: 30387) +DN404MirrorTest:testTransferFrom(uint32) (runs: 256, μ: 342668, ~: 342661) +DN404MirrorTest:test__codesize() (gas: 29898) DN404OnlyERC20Test:testApprove() (gas: 35912) DN404OnlyERC20Test:testApprove(address,uint256) (runs: 256, μ: 30219, ~: 31463) DN404OnlyERC20Test:testBurn() (gas: 49769) -DN404OnlyERC20Test:testBurn(address,uint256,uint256) (runs: 256, μ: 50858, ~: 50970) -DN404OnlyERC20Test:testBurnInsufficientBalanceReverts(address,uint256,uint256) (runs: 256, μ: 43805, ~: 43888) +DN404OnlyERC20Test:testBurn(address,uint256,uint256) (runs: 256, μ: 50847, ~: 50970) +DN404OnlyERC20Test:testBurnInsufficientBalanceReverts(address,uint256,uint256) (runs: 256, μ: 43813, ~: 43879) DN404OnlyERC20Test:testInfiniteApproveTransferFrom() (gas: 102011) DN404OnlyERC20Test:testMaxSupplyTrick(uint256) (runs: 256, μ: 541, ~: 541) DN404OnlyERC20Test:testMetadata() (gas: 10111) DN404OnlyERC20Test:testMint() (gas: 45320) DN404OnlyERC20Test:testMintOverMaxLimitReverts() (gas: 40544) -DN404OnlyERC20Test:testMintz(address,uint256) (runs: 256, μ: 45818, ~: 45742) +DN404OnlyERC20Test:testMintz(address,uint256) (runs: 256, μ: 45815, ~: 45742) DN404OnlyERC20Test:testTransfer() (gas: 74556) -DN404OnlyERC20Test:testTransfer(address,uint256) (runs: 256, μ: 74899, ~: 75013) +DN404OnlyERC20Test:testTransfer(address,uint256) (runs: 256, μ: 74912, ~: 75013) DN404OnlyERC20Test:testTransferFrom() (gas: 84636) -DN404OnlyERC20Test:testTransferFrom(address,address,address,uint256,uint256) (runs: 256, μ: 105698, ~: 107617) +DN404OnlyERC20Test:testTransferFrom(address,address,address,uint256,uint256) (runs: 256, μ: 105391, ~: 107617) DN404OnlyERC20Test:testTransferFromInsufficientAllowanceReverts() (gas: 68086) -DN404OnlyERC20Test:testTransferFromInsufficientAllowanceReverts(address,uint256,uint256) (runs: 256, μ: 68600, ~: 69187) +DN404OnlyERC20Test:testTransferFromInsufficientAllowanceReverts(address,uint256,uint256) (runs: 256, μ: 68607, ~: 69187) DN404OnlyERC20Test:testTransferFromInsufficientBalanceReverts() (gas: 75030) -DN404OnlyERC20Test:testTransferFromInsufficientBalanceReverts(address,uint256,uint256) (runs: 256, μ: 76174, ~: 76160) +DN404OnlyERC20Test:testTransferFromInsufficientBalanceReverts(address,uint256,uint256) (runs: 256, μ: 76183, ~: 76160) DN404OnlyERC20Test:testTransferInsufficientBalanceReverts() (gas: 66261) -DN404OnlyERC20Test:testTransferInsufficientBalanceReverts(address,uint256,uint256) (runs: 256, μ: 67396, ~: 67384) -DN404OnlyERC20Test:test__codesize() (gas: 29774) -DN404Test:testBatchNFTLog() (gas: 314471) -DN404Test:testBurnOnTransfer(uint32,address) (runs: 256, μ: 264026, ~: 264046) -DN404Test:testInitialize(uint32,address) (runs: 256, μ: 112902, ~: 116477) -DN404Test:testMintAndBurn() (gas: 339377) -DN404Test:testMintAndBurn2() (gas: 263133) -DN404Test:testMintOnTransfer(uint32,address) (runs: 256, μ: 262610, ~: 262620) -DN404Test:testMixed(uint256) (runs: 256, μ: 600208, ~: 572067) +DN404OnlyERC20Test:testTransferInsufficientBalanceReverts(address,uint256,uint256) (runs: 256, μ: 67302, ~: 67357) +DN404OnlyERC20Test:test__codesize() (gas: 29362) +DN404Test:testBatchNFTLog() (gas: 306241) +DN404Test:testBurnOnTransfer(uint32,address) (runs: 256, μ: 264116, ~: 264136) +DN404Test:testInitialize(uint32,address) (runs: 256, μ: 112826, ~: 116477) +DN404Test:testMintAndBurn() (gas: 336898) +DN404Test:testMintAndBurn2() (gas: 262914) +DN404Test:testMintOnTransfer(uint32,address) (runs: 256, μ: 262981, ~: 262991) +DN404Test:testMixed(uint256) (runs: 256, μ: 600098, ~: 565960) DN404Test:testNameAndSymbol(string,string) (runs: 256, μ: 207282, ~: 207623) -DN404Test:testRegisterAndResolveAlias(address,address) (runs: 256, μ: 126873, ~: 127078) -DN404Test:testSetAndGetAux(address,uint88) (runs: 256, μ: 21968, ~: 22275) +DN404Test:testRegisterAndResolveAlias(address,address) (runs: 256, μ: 127068, ~: 127078) +DN404Test:testSetAndGetAux(address,uint88) (runs: 256, μ: 21933, ~: 22275) DN404Test:testSetAndGetOperatorApprovals(address,address,bool) (runs: 256, μ: 129762, ~: 120828) DN404Test:testSetAndGetSkipNFT() (gas: 89239) DN404Test:testTokenURI(string,uint256) (runs: 256, μ: 158077, ~: 135776) -DN404Test:testTransfersAndBurns() (gas: 453395) -DN404Test:testWrapAround(uint32,uint256) (runs: 256, μ: 354173, ~: 347752) -DN404Test:test__codesize() (gas: 40891) -ERC20Invariants:invariantBalanceSum() (runs: 256, calls: 3840, reverts: 2639) -ERC20Invariants:test__codesize() (gas: 16961) +DN404Test:testTransfersAndBurns() (gas: 448770) +DN404Test:testWrapAround(uint32,uint256) (runs: 256, μ: 351673, ~: 344953) +DN404Test:test__codesize() (gas: 40402) +ERC20Invariants:invariantBalanceSum() (runs: 256, calls: 3840, reverts: 2677) +ERC20Invariants:test__codesize() (gas: 16549) SimpleDN404Test:testMint() (gas: 45198) SimpleDN404Test:testName() (gas: 9674) SimpleDN404Test:testSetBaseURI() (gas: 38574) SimpleDN404Test:testSymbol() (gas: 9716) SimpleDN404Test:testWithdraw() (gas: 27356) -SimpleDN404Test:test__codesize() (gas: 19428) +SimpleDN404Test:test__codesize() (gas: 19041) 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 148f8d0..56161f7 100644 --- a/src/DN404.sol +++ b/src/DN404.sol @@ -1,8 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; -import {LibMap} from "solady/utils/LibMap.sol"; - /// @title DN404 /// @notice DN404 is a hybrid ERC20 and ERC721 implementation that mints /// and burns NFTs based on an account's ERC20 token balance. @@ -19,8 +17,6 @@ import {LibMap} from "solady/utils/LibMap.sol"; /// DN404Mirror contract ***MUST*** be deployed and linked during /// initialization. abstract contract DN404 { - using LibMap for *; - /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* EVENTS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ @@ -113,6 +109,11 @@ abstract contract DN404 { uint96 balance; } + /// @dev A uint32 map in storage. + struct Uint32Map { + mapping(uint256 => uint256) map; + } + /// @dev Struct containing the base token contract storage. struct DN404Storage { // Current number of address aliases assigned. @@ -134,9 +135,9 @@ abstract contract DN404 { // Mapping of user allowances for token spenders. mapping(address => mapping(address => uint256)) allowance; // Mapping of NFT token IDs owned by an address. - mapping(address => LibMap.Uint32Map) owned; + mapping(address => Uint32Map) owned; // Even indices: owner aliases. Odd indices: owned indices. - LibMap.Uint32Map oo; + Uint32Map oo; // Mapping of user account AddressData mapping(address => AddressData) addressData; } @@ -315,7 +316,7 @@ abstract contract DN404 { toAddressData.balance = uint96(toBalance); if (toAddressData.flags & _ADDRESS_DATA_SKIP_NFT_FLAG == 0) { - LibMap.Uint32Map storage toOwned = $.owned[to]; + Uint32Map storage toOwned = $.owned[to]; uint256 toIndex = toAddressData.ownedLength; uint256 toEnd = toBalance / _WAD; _PackedLogs memory packedLogs = _packedLogsMalloc(_zeroFloorSub(toEnd, toIndex)); @@ -328,12 +329,11 @@ abstract contract DN404 { toAddressData.ownedLength = uint32(toEnd); // Mint loop. do { - while ($.oo.get(_ownershipIndex(id)) != 0) { + while (_get($.oo, _ownershipIndex(id)) != 0) { if (++id > maxNFTId) id = 1; } - toOwned.set(toIndex, uint32(id)); - $.oo.set(_ownershipIndex(id), toAlias); - $.oo.set(_ownedIndex(id), uint32(toIndex++)); + _set(toOwned, toIndex, uint32(id)); + _setOwnerAliasAndOwnedIndex($.oo, id, toAlias, uint32(toIndex++)); _packedLogsAppend(packedLogs, to, id, 0); if (++id > maxNFTId) id = 1; } while (toIndex != toEnd); @@ -371,7 +371,7 @@ abstract contract DN404 { currentTokenSupply -= amount; $.totalSupply = uint96(currentTokenSupply); - LibMap.Uint32Map storage fromOwned = $.owned[from]; + Uint32Map storage fromOwned = $.owned[from]; uint256 fromIndex = fromAddressData.ownedLength; uint256 nftAmountToBurn = _zeroFloorSub(fromIndex, fromBalance / _WAD); @@ -383,9 +383,8 @@ abstract contract DN404 { uint256 fromEnd = fromIndex - nftAmountToBurn; // Burn loop. do { - uint256 id = fromOwned.get(--fromIndex); - $.oo.set(_ownedIndex(id), 0); - $.oo.set(_ownershipIndex(id), 0); + uint256 id = _get(fromOwned, --fromIndex); + _setOwnerAliasAndOwnedIndex($.oo, id, 0, 0); delete $.tokenApprovals[id]; _packedLogsAppend(packedLogs, from, id, 1); } while (fromIndex != fromEnd); @@ -441,23 +440,22 @@ abstract contract DN404 { _PackedLogs memory packedLogs = _packedLogsMalloc(t.nftAmountToBurn + t.nftAmountToMint); if (t.nftAmountToBurn != 0) { - LibMap.Uint32Map storage fromOwned = $.owned[from]; + Uint32Map storage fromOwned = $.owned[from]; uint256 fromIndex = t.fromOwnedLength; uint256 fromEnd = fromIndex - t.nftAmountToBurn; $.totalNFTSupply -= uint32(t.nftAmountToBurn); fromAddressData.ownedLength = uint32(fromEnd); // Burn loop. do { - uint256 id = fromOwned.get(--fromIndex); - $.oo.set(_ownedIndex(id), 0); - $.oo.set(_ownershipIndex(id), 0); + uint256 id = _get(fromOwned, --fromIndex); + _setOwnerAliasAndOwnedIndex($.oo, id, 0, 0); delete $.tokenApprovals[id]; _packedLogsAppend(packedLogs, from, id, 1); } while (fromIndex != fromEnd); } if (t.nftAmountToMint != 0) { - LibMap.Uint32Map storage toOwned = $.owned[to]; + Uint32Map storage toOwned = $.owned[to]; uint256 toIndex = t.toOwnedLength; uint256 toEnd = toIndex + t.nftAmountToMint; uint32 toAlias = _registerAndResolveAlias(toAddressData, to); @@ -467,12 +465,11 @@ abstract contract DN404 { toAddressData.ownedLength = uint32(toEnd); // Mint loop. do { - while ($.oo.get(_ownershipIndex(id)) != 0) { + while (_get($.oo, _ownershipIndex(id)) != 0) { if (++id > maxNFTId) id = 1; } - toOwned.set(toIndex, uint32(id)); - $.oo.set(_ownershipIndex(id), toAlias); - $.oo.set(_ownedIndex(id), uint32(toIndex++)); + _set(toOwned, toIndex, uint32(id)); + _setOwnerAliasAndOwnedIndex($.oo, id, toAlias, uint32(toIndex++)); _packedLogsAppend(packedLogs, to, id, 0); if (++id > maxNFTId) id = 1; } while (toIndex != toEnd); @@ -505,7 +502,7 @@ abstract contract DN404 { if (to == address(0)) revert TransferToZeroAddress(); - address owner = $.aliasToAddress[$.oo.get(_ownershipIndex(id))]; + address owner = $.aliasToAddress[_get($.oo, _ownershipIndex(id))]; if (from != owner) revert TransferFromIncorrectOwner(); @@ -525,16 +522,16 @@ abstract contract DN404 { unchecked { toAddressData.balance += uint96(_WAD); - $.oo.set(_ownershipIndex(id), _registerAndResolveAlias(toAddressData, to)); + _set($.oo, _ownershipIndex(id), _registerAndResolveAlias(toAddressData, to)); delete $.tokenApprovals[id]; - uint256 updatedId = $.owned[from].get(--fromAddressData.ownedLength); - $.owned[from].set($.oo.get(_ownedIndex(id)), uint32(updatedId)); + uint256 updatedId = _get($.owned[from], --fromAddressData.ownedLength); + _set($.owned[from], _get($.oo, _ownedIndex(id)), uint32(updatedId)); uint256 n = toAddressData.ownedLength++; - $.oo.set(_ownedIndex(updatedId), $.oo.get(_ownedIndex(id))); - $.owned[to].set(n, uint32(id)); - $.oo.set(_ownedIndex(id), uint32(n)); + _set($.oo, _ownedIndex(updatedId), _get($.oo, _ownedIndex(id))); + _set($.owned[to], n, uint32(id)); + _set($.oo, _ownedIndex(id), uint32(n)); } emit Transfer(from, to, _WAD); @@ -643,7 +640,7 @@ abstract contract DN404 { /// Returns the zero address instead of reverting if the token does not exist. function _ownerAt(uint256 id) internal view virtual returns (address) { DN404Storage storage $ = _getDN404Storage(); - return $.aliasToAddress[$.oo.get(_ownershipIndex(id))]; + return $.aliasToAddress[_get($.oo, _ownershipIndex(id))]; } /// @dev Returns the owner of token `id`. @@ -679,7 +676,7 @@ abstract contract DN404 { { DN404Storage storage $ = _getDN404Storage(); - address owner = $.aliasToAddress[$.oo.get(_ownershipIndex(id))]; + address owner = $.aliasToAddress[_get($.oo, _ownershipIndex(id))]; if (msgSender != owner) { if (!$.operatorApprovals[owner][msgSender]) { @@ -921,4 +918,43 @@ abstract contract DN404 { return (i << 1) + 1; } } + + /// @dev Returns the uint32 value at `index` in `map`. + function _get(Uint32Map storage map, uint256 index) private view returns (uint32 result) { + result = uint32(map.map[index >> 3] >> ((index & 7) << 5)); + } + + /// @dev Updates the uint32 value at `index` in `map`. + function _set(Uint32Map storage map, uint256 index, uint32 value) private { + /// @solidity memory-safe-assembly + assembly { + mstore(0x20, map.slot) + mstore(0x00, shr(3, index)) + let s := keccak256(0x00, 0x40) // Storage slot. + let o := shl(5, and(index, 7)) // Storage slot offset (bits). + let v := sload(s) // Storage slot value. + let m := 0xffffffff // Value mask. + sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value))))) + } + } + + /// @dev Sets the owner alias and the owned index together. + function _setOwnerAliasAndOwnedIndex( + Uint32Map storage map, + uint256 id, + uint32 ownership, + uint32 ownedIndex + ) private { + /// @solidity memory-safe-assembly + assembly { + let value := or(shl(32, ownedIndex), and(0xffffffff, ownership)) + mstore(0x20, map.slot) + mstore(0x00, shr(2, id)) + let s := keccak256(0x00, 0x40) // Storage slot. + let o := shl(6, and(id, 3)) // Storage slot offset (bits). + let v := sload(s) // Storage slot value. + let m := 0xffffffffffffffff // Value mask. + sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value))))) + } + } } diff --git a/test/Bench.t.sol b/test/Bench.t.sol index 44a9827..b073461 100644 --- a/test/Bench.t.sol +++ b/test/Bench.t.sol @@ -382,62 +382,48 @@ contract BenchTest is SoladyTest { dn.initializeDN404(10000 * 10 ** 18, address(this), address(mirror)); } - function _mintTokens(address a, uint256 amount) internal { + modifier mint(address a, uint256 amount) { unchecked { address alice = address(111); IERC20(a).transfer(alice, amount * 10 ** 18); } + _; } - function testMintTokensPandora_01() public { - _mintTokens(address(pandora), 1); - } - - function testMintTokensDN404_01() public { - _mintTokens(address(dn), 1); - } - - function testMintTokensPandora_02() public { - _mintTokens(address(pandora), 2); - } - - function testMintTokensDN404_02() public { - _mintTokens(address(dn), 2); - } - - function testMintTokensPandora_04() public { - _mintTokens(address(pandora), 4); - } - - function testMintTokensDN404_04() public { - _mintTokens(address(dn), 4); - } - - function testMintTokensPandora_08() public { - _mintTokens(address(pandora), 8); - } - - function testMintTokensDN404_08() public { - _mintTokens(address(dn), 8); - } - - function testMintTokensPandora_16() public { - _mintTokens(address(pandora), 16); - } - - function testMintTokensDN404_16() public { - _mintTokens(address(dn), 16); - } - - function testMintTokensPandora_32() public { - _mintTokens(address(pandora), 32); - } - - function testMintTokensDN404_32() public { - _mintTokens(address(dn), 32); - } - - function _mintAndTransferTokens(address a, uint256 amount) internal { + function testMintPandora_01() public mint(address(pandora), 1) {} + function testMintDN404_01() public mint(address(dn), 1) {} + function testMintPandora_02() public mint(address(pandora), 2) {} + function testMintDN404_02() public mint(address(dn), 2) {} + function testMintPandora_03() public mint(address(pandora), 3) {} + function testMintDN404_03() public mint(address(dn), 3) {} + function testMintPandora_04() public mint(address(pandora), 4) {} + function testMintDN404_04() public mint(address(dn), 4) {} + function testMintPandora_05() public mint(address(pandora), 5) {} + function testMintDN404_05() public mint(address(dn), 5) {} + function testMintPandora_06() public mint(address(pandora), 6) {} + function testMintDN404_06() public mint(address(dn), 6) {} + function testMintPandora_07() public mint(address(pandora), 7) {} + function testMintDN404_07() public mint(address(dn), 7) {} + function testMintPandora_08() public mint(address(pandora), 8) {} + function testMintDN404_08() public mint(address(dn), 8) {} + function testMintPandora_09() public mint(address(pandora), 9) {} + function testMintDN404_09() public mint(address(dn), 9) {} + function testMintPandora_10() public mint(address(pandora), 10) {} + function testMintDN404_10() public mint(address(dn), 10) {} + function testMintPandora_11() public mint(address(pandora), 11) {} + function testMintDN404_11() public mint(address(dn), 11) {} + function testMintPandora_12() public mint(address(pandora), 12) {} + function testMintDN404_12() public mint(address(dn), 12) {} + function testMintPandora_13() public mint(address(pandora), 13) {} + function testMintDN404_13() public mint(address(dn), 13) {} + function testMintPandora_14() public mint(address(pandora), 14) {} + function testMintDN404_14() public mint(address(dn), 14) {} + function testMintPandora_15() public mint(address(pandora), 15) {} + function testMintDN404_15() public mint(address(dn), 15) {} + function testMintPandora_16() public mint(address(pandora), 16) {} + function testMintDN404_16() public mint(address(dn), 16) {} + + modifier mintAndTransfer(address a, uint256 amount) { unchecked { address alice = address(111); address bob = address(222); @@ -445,53 +431,39 @@ contract BenchTest is SoladyTest { vm.prank(alice); IERC20(a).transfer(bob, amount * 10 ** 18); } + _; } - function testMintAndTransferTokensPandora_01() public { - _mintAndTransferTokens(address(pandora), 1); - } - - function testMintAndTransferTokensDN404_01() public { - _mintAndTransferTokens(address(dn), 1); - } - - function testMintAndTransferTokensPandora_02() public { - _mintAndTransferTokens(address(pandora), 2); - } - - function testMintAndTransferTokensDN404_02() public { - _mintAndTransferTokens(address(dn), 2); - } - - function testMintAndTransferTokensPandora_04() public { - _mintAndTransferTokens(address(pandora), 4); - } - - function testMintAndTransferTokensDN404_04() public { - _mintAndTransferTokens(address(dn), 4); - } - - function testMintAndTransferTokensPandora_08() public { - _mintAndTransferTokens(address(pandora), 8); - } - - function testMintAndTransferTokensDN404_08() public { - _mintAndTransferTokens(address(dn), 8); - } - - function testMintAndTransferTokensPandora_16() public { - _mintAndTransferTokens(address(pandora), 16); - } - - function testMintAndTransferTokensDN404_16() public { - _mintAndTransferTokens(address(dn), 16); - } - - function testMintAndTransferTokensPandora_32() public { - _mintAndTransferTokens(address(pandora), 32); - } - - function testMintAndTransferTokensDN404_32() public { - _mintAndTransferTokens(address(dn), 32); - } + function testMintAndTransferPandora_01() public mintAndTransfer(address(pandora), 1) {} + function testMintAndTransferDN404_01() public mintAndTransfer(address(dn), 1) {} + function testMintAndTransferPandora_02() public mintAndTransfer(address(pandora), 2) {} + function testMintAndTransferDN404_02() public mintAndTransfer(address(dn), 2) {} + function testMintAndTransferPandora_03() public mintAndTransfer(address(pandora), 3) {} + function testMintAndTransferDN404_03() public mintAndTransfer(address(dn), 3) {} + function testMintAndTransferPandora_04() public mintAndTransfer(address(pandora), 4) {} + function testMintAndTransferDN404_04() public mintAndTransfer(address(dn), 4) {} + function testMintAndTransferPandora_05() public mintAndTransfer(address(pandora), 5) {} + function testMintAndTransferDN404_05() public mintAndTransfer(address(dn), 5) {} + function testMintAndTransferPandora_06() public mintAndTransfer(address(pandora), 6) {} + function testMintAndTransferDN404_06() public mintAndTransfer(address(dn), 6) {} + function testMintAndTransferPandora_07() public mintAndTransfer(address(pandora), 7) {} + function testMintAndTransferDN404_07() public mintAndTransfer(address(dn), 7) {} + function testMintAndTransferPandora_08() public mintAndTransfer(address(pandora), 8) {} + function testMintAndTransferDN404_08() public mintAndTransfer(address(dn), 8) {} + function testMintAndTransferPandora_09() public mintAndTransfer(address(pandora), 9) {} + function testMintAndTransferDN404_09() public mintAndTransfer(address(dn), 9) {} + function testMintAndTransferPandora_10() public mintAndTransfer(address(pandora), 10) {} + function testMintAndTransferDN404_10() public mintAndTransfer(address(dn), 10) {} + function testMintAndTransferPandora_11() public mintAndTransfer(address(pandora), 11) {} + function testMintAndTransferDN404_11() public mintAndTransfer(address(dn), 11) {} + function testMintAndTransferPandora_12() public mintAndTransfer(address(pandora), 12) {} + function testMintAndTransferDN404_12() public mintAndTransfer(address(dn), 12) {} + function testMintAndTransferPandora_13() public mintAndTransfer(address(pandora), 13) {} + function testMintAndTransferDN404_13() public mintAndTransfer(address(dn), 13) {} + function testMintAndTransferPandora_14() public mintAndTransfer(address(pandora), 14) {} + function testMintAndTransferDN404_14() public mintAndTransfer(address(dn), 14) {} + function testMintAndTransferPandora_15() public mintAndTransfer(address(pandora), 15) {} + function testMintAndTransferDN404_15() public mintAndTransfer(address(dn), 15) {} + function testMintAndTransferPandora_16() public mintAndTransfer(address(pandora), 16) {} + function testMintAndTransferDN404_16() public mintAndTransfer(address(dn), 16) {} }