Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 47 additions & 47 deletions .gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -67,73 +67,73 @@ BenchTest:testMintDN420_13() (gas: 111184)
BenchTest:testMintDN420_14() (gas: 112569)
BenchTest:testMintDN420_15() (gas: 114041)
BenchTest:testMintDN420_16() (gas: 115447)
BenchTest:test__codesize() (gas: 28252)
BenchTest:test__codesize() (gas: 28114)
DN404CustomUnitTest:testInitializeCorrectUnitSuccess() (gas: 130120)
DN404CustomUnitTest:testInitializeWithUnitTooLargeReverts() (gas: 33791)
DN404CustomUnitTest:testInitializeWithZeroUnitReverts() (gas: 13864)
DN404CustomUnitTest:testMint() (gas: 163237)
DN404CustomUnitTest:testMintWithoutNFTs(uint256,uint256,uint256) (runs: 276, μ: 160409, ~: 162733)
DN404CustomUnitTest:testMintWithoutNFTs(uint256,uint256,uint256) (runs: 276, μ: 160424, ~: 162733)
DN404CustomUnitTest:testNFTMint() (gas: 64873666)
DN404CustomUnitTest:testNFTMintAndBurn(uint256,uint256,uint256) (runs: 276, μ: 207856, ~: 159094)
DN404CustomUnitTest:testNFTMintViaTransfer(uint256,uint256,uint256) (runs: 276, μ: 235488, ~: 250925)
DN404CustomUnitTest:testTotalSupplyOverflowsTrick(uint256,uint256) (runs: 276, μ: 604, ~: 664)
DN404CustomUnitTest:testTotalSupplyOverflowsTrick(uint256,uint256,uint256) (runs: 276, μ: 775, ~: 746)
DN404CustomUnitTest:testNFTMintAndBurn(uint256,uint256,uint256) (runs: 276, μ: 203500, ~: 159083)
DN404CustomUnitTest:testNFTMintViaTransfer(uint256,uint256,uint256) (runs: 276, μ: 232805, ~: 250925)
DN404CustomUnitTest:testTotalSupplyOverflowsTrick(uint256,uint256) (runs: 276, μ: 603, ~: 664)
DN404CustomUnitTest:testTotalSupplyOverflowsTrick(uint256,uint256,uint256) (runs: 276, μ: 776, ~: 746)
DN404CustomUnitTest:testUnitInvalidCheckTrick(uint256) (runs: 276, μ: 526, ~: 527)
DN404CustomUnitTest:test__codesize() (gas: 28781)
DN404CustomUnitTest:test__codesize() (gas: 28643)
DN404MirrorTest:testAutomaticPullOwnerWithOwnable() (gas: 3664602)
DN404MirrorTest:testAutomaticPullOwnerWithOwnable2() (gas: 3652679)
DN404MirrorTest:testBaseERC20() (gas: 114787)
DN404MirrorTest:testFnSelectorNotRecognized() (gas: 6247)
DN404MirrorTest:testLinkMirrorContract() (gas: 39410)
DN404MirrorTest:testLogDirectTransfers() (gas: 395961)
DN404MirrorTest:testLogTransfer() (gas: 120943)
DN404MirrorTest:testNameAndSymbol(string,string) (runs: 276, μ: 203765, ~: 207074)
DN404MirrorTest:testNameAndSymbol(string,string) (runs: 276, μ: 203835, ~: 207144)
DN404MirrorTest:testNotLinked() (gas: 12794)
DN404MirrorTest:testPullOwner() (gas: 112833)
DN404MirrorTest:testSafeTransferFrom(uint32) (runs: 276, μ: 478719, ~: 478658)
DN404MirrorTest:testSafeTransferFrom(uint32,bytes) (runs: 276, μ: 533926, ~: 502002)
DN404MirrorTest:testSetAndGetApprovalForAll() (gas: 331059)
DN404MirrorTest:testSetAndGetApproved() (gas: 328139)
DN404MirrorTest:testSupportsInterface() (gas: 7567)
DN404MirrorTest:testTokenURI(string,uint256) (runs: 276, μ: 261507, ~: 266260)
DN404MirrorTest:testTransferFrom(uint32) (runs: 276, μ: 379939, ~: 379878)
DN404MirrorTest:testTransferFromMixed(uint256) (runs: 276, μ: 785229, ~: 716434)
DN404MirrorTest:test__codesize() (gas: 60249)
DN404MirrorTest:testSupportsInterface() (gas: 7544)
DN404MirrorTest:testTokenURI(string,uint256) (runs: 276, μ: 261981, ~: 266295)
DN404MirrorTest:testTransferFrom(uint32) (runs: 276, μ: 379975, ~: 379913)
DN404MirrorTest:testTransferFromMixed(uint256) (runs: 276, μ: 765680, ~: 687875)
DN404MirrorTest:test__codesize() (gas: 61980)
DN404OnlyERC20Test:testApprove() (gas: 35902)
DN404OnlyERC20Test:testApprove(address,uint256) (runs: 276, μ: 31380, ~: 31453)
DN404OnlyERC20Test:testBurn() (gas: 48166)
DN404OnlyERC20Test:testBurn(address,uint256,uint256) (runs: 276, μ: 49031, ~: 49345)
DN404OnlyERC20Test:testBurnInsufficientBalanceReverts(address,uint256,uint256) (runs: 276, μ: 42229, ~: 42379)
DN404OnlyERC20Test:testBurn(address,uint256,uint256) (runs: 276, μ: 49020, ~: 49345)
DN404OnlyERC20Test:testBurnInsufficientBalanceReverts(address,uint256,uint256) (runs: 276, μ: 42238, ~: 42379)
DN404OnlyERC20Test:testInfiniteApproveTransferFrom() (gas: 82978)
DN404OnlyERC20Test:testMaxSupplyTrick(uint256) (runs: 276, μ: 541, ~: 541)
DN404OnlyERC20Test:testMetadata() (gas: 8962)
DN404OnlyERC20Test:testMint() (gas: 44065)
DN404OnlyERC20Test:testMintOverMaxLimitReverts() (gas: 42035)
DN404OnlyERC20Test:testMintz(address,uint256) (runs: 276, μ: 44725, ~: 44487)
DN404OnlyERC20Test:testMintz(address,uint256) (runs: 276, μ: 44640, ~: 44487)
DN404OnlyERC20Test:testTransfer() (gas: 58082)
DN404OnlyERC20Test:testTransfer(address,uint256) (runs: 276, μ: 58729, ~: 58491)
DN404OnlyERC20Test:testTransfer(address,uint256) (runs: 276, μ: 58644, ~: 58491)
DN404OnlyERC20Test:testTransferFrom() (gas: 79976)
DN404OnlyERC20Test:testTransferFrom(address,address,address,uint256,uint256) (runs: 276, μ: 87059, ~: 88405)
DN404OnlyERC20Test:testTransferFrom(address,address,address,uint256,uint256) (runs: 276, μ: 87062, ~: 88405)
DN404OnlyERC20Test:testTransferFromInsufficientAllowanceReverts() (gas: 66880)
DN404OnlyERC20Test:testTransferFromInsufficientAllowanceReverts(address,uint256,uint256) (runs: 276, μ: 67849, ~: 67959)
DN404OnlyERC20Test:testTransferFromInsufficientAllowanceReverts(address,uint256,uint256) (runs: 276, μ: 67858, ~: 67959)
DN404OnlyERC20Test:testTransferFromInsufficientBalanceReverts() (gas: 51747)
DN404OnlyERC20Test:testTransferFromInsufficientBalanceReverts(address,uint256,uint256) (runs: 276, μ: 52378, ~: 52524)
DN404OnlyERC20Test:testTransferFromInsufficientBalanceReverts(address,uint256,uint256) (runs: 276, μ: 52385, ~: 52534)
DN404OnlyERC20Test:testTransferInsufficientBalanceReverts() (gas: 43948)
DN404OnlyERC20Test:testTransferInsufficientBalanceReverts(address,uint256,uint256) (runs: 276, μ: 44927, ~: 45057)
DN404OnlyERC20Test:test__codesize() (gas: 28201)
DN404OnlyERC20Test:testTransferInsufficientBalanceReverts(address,uint256,uint256) (runs: 276, μ: 44936, ~: 45057)
DN404OnlyERC20Test:test__codesize() (gas: 28063)
DN404Test:testBatchNFTLog() (gas: 327308)
DN404Test:testBurnOnTransfer(uint32,address) (runs: 274, μ: 275863, ~: 275863)
DN404Test:testFnSelectorNotRecognized() (gas: 6256)
DN404Test:testInitialize(uint32,address) (runs: 276, μ: 112730, ~: 113808)
DN404Test:testInitialize(uint32,address) (runs: 276, μ: 112465, ~: 113808)
DN404Test:testMintAndBurn() (gas: 346843)
DN404Test:testMintAndBurn2() (gas: 283400)
DN404Test:testMintNext() (gas: 707821)
DN404Test:testMintNextContiguous(uint256) (runs: 276, μ: 588301, ~: 538017)
DN404Test:testMintNextContiguous(uint256) (runs: 276, μ: 580234, ~: 530149)
DN404Test:testMintOnTransfer(uint32,address) (runs: 274, μ: 290438, ~: 290438)
DN404Test:testMixed(bytes32) (runs: 276, μ: 530506, ~: 477345)
DN404Test:testMixed(bytes32) (runs: 276, μ: 535439, ~: 477565)
DN404Test:testNameAndSymbol(string,string) (runs: 276, μ: 203567, ~: 206876)
DN404Test:testNumAliasesOverflowReverts() (gas: 40944)
DN404Test:testOwnedIds() (gas: 361141)
DN404Test:testOwnedIds(uint256) (runs: 276, μ: 268325, ~: 284584)
DN404Test:testOwnedIds(uint256) (runs: 276, μ: 270712, ~: 285417)
DN404Test:testPermit2() (gas: 456313)
DN404Test:testRegisterAndResolveAlias(address,address) (runs: 276, μ: 120191, ~: 120191)
DN404Test:testSetAndGetAux(address,uint88) (runs: 276, μ: 22056, ~: 22274)
Expand All @@ -142,33 +142,33 @@ DN404Test:testSetAndGetSkipNFT() (gas: 708368)
DN404Test:testTokenURI(string,uint256) (runs: 276, μ: 12997903, ~: 12975480)
DN404Test:testTransferWithMirrorEvent() (gas: 411009)
DN404Test:testTransfersAndBurns() (gas: 488426)
DN404Test:testWrapAround(uint32,uint256) (runs: 276, μ: 392580, ~: 389199)
DN404Test:test__codesize() (gas: 61066)
DN404Test:testWrapAround(uint32,uint256) (runs: 276, μ: 392860, ~: 389199)
DN404Test:test__codesize() (gas: 60928)
DN404ZeroIndexedTest:testBatchNFTLog() (gas: 326747)
DN404ZeroIndexedTest:testBurnOnTransfer(uint32,address) (runs: 274, μ: 255773, ~: 255783)
DN404ZeroIndexedTest:testBurnOnTransfer(uint32,address) (runs: 274, μ: 255783, ~: 255783)
DN404ZeroIndexedTest:testFnSelectorNotRecognized() (gas: 6256)
DN404ZeroIndexedTest:testInitialize(uint32,address) (runs: 276, μ: 111139, ~: 113802)
DN404ZeroIndexedTest:testInitialize(uint32,address) (runs: 276, μ: 111178, ~: 113802)
DN404ZeroIndexedTest:testMintAndBurn() (gas: 343724)
DN404ZeroIndexedTest:testMintAndBurn2() (gas: 280984)
DN404ZeroIndexedTest:testMintNext() (gas: 704822)
DN404ZeroIndexedTest:testMintNextContiguous(uint256) (runs: 276, μ: 574967, ~: 529585)
DN404ZeroIndexedTest:testMintOnTransfer(uint32,address) (runs: 274, μ: 270394, ~: 270404)
DN404ZeroIndexedTest:testMixed(bytes32) (runs: 276, μ: 517435, ~: 451049)
DN404ZeroIndexedTest:testMintNextContiguous(uint256) (runs: 276, μ: 573892, ~: 527005)
DN404ZeroIndexedTest:testMintOnTransfer(uint32,address) (runs: 274, μ: 270404, ~: 270404)
DN404ZeroIndexedTest:testMixed(bytes32) (runs: 276, μ: 541159, ~: 483085)
DN404ZeroIndexedTest:testNameAndSymbol(string,string) (runs: 276, μ: 203516, ~: 206825)
DN404ZeroIndexedTest:testNumAliasesOverflowReverts() (gas: 40944)
DN404ZeroIndexedTest:testOwnedIds() (gas: 348030)
DN404ZeroIndexedTest:testOwnedIds(uint256) (runs: 276, μ: 268702, ~: 285180)
DN404ZeroIndexedTest:testOwnedIds(uint256) (runs: 276, μ: 270873, ~: 287994)
DN404ZeroIndexedTest:testPermit2() (gas: 455948)
DN404ZeroIndexedTest:testRegisterAndResolveAlias(address,address) (runs: 276, μ: 120118, ~: 120191)
DN404ZeroIndexedTest:testSetAndGetAux(address,uint88) (runs: 276, μ: 22074, ~: 22290)
DN404ZeroIndexedTest:testSetAndGetAux(address,uint88) (runs: 276, μ: 22074, ~: 22292)
DN404ZeroIndexedTest:testSetAndGetOperatorApprovals(address,address,bool) (runs: 276, μ: 130339, ~: 120534)
DN404ZeroIndexedTest:testSetAndGetSkipNFT() (gas: 708390)
DN404ZeroIndexedTest:testTokenURI(string,uint256) (runs: 276, μ: 157093, ~: 134670)
DN404ZeroIndexedTest:testTransferWithMirrorEvent() (gas: 410515)
DN404ZeroIndexedTest:testTransfersAndBurns() (gas: 486461)
DN404ZeroIndexedTest:testWrapAround(uint32,uint256) (runs: 276, μ: 378032, ~: 383784)
DN404ZeroIndexedTest:testWrapNFTIdEquivalence(uint256,uint256,bool) (runs: 276, μ: 1379, ~: 1418)
DN404ZeroIndexedTest:test__codesize() (gas: 60861)
DN404ZeroIndexedTest:testWrapAround(uint32,uint256) (runs: 276, μ: 376766, ~: 383784)
DN404ZeroIndexedTest:testWrapNFTIdEquivalence(uint256,uint256,bool) (runs: 276, μ: 1382, ~: 1440)
DN404ZeroIndexedTest:test__codesize() (gas: 60723)
DN420OnlyERC20Test:testApprove() (gas: 35869)
DN420OnlyERC20Test:testApprove(address,uint256) (runs: 276, μ: 31347, ~: 31420)
DN420OnlyERC20Test:testBurn() (gas: 49038)
Expand Down Expand Up @@ -223,16 +223,16 @@ MaxUnitInvariant:invariantMirrorAndBaseRemainImmutable() (runs: 10, calls: 150,
MaxUnitInvariant:invariantNoUserOwnsInvalidToken() (runs: 10, calls: 150, reverts: 0)
MaxUnitInvariant:invariantTotalReflectionIsValid() (runs: 10, calls: 150, reverts: 0)
MaxUnitInvariant:invariantUserReflectionIsValid() (runs: 10, calls: 150, reverts: 0)
MintTests:test_WhenAmountIsGreaterThan_MAX_SUPPLYOrMintMakesNFTTotalSupplyExceed_MAX_SUPPLY(uint256) (runs: 276, μ: 60470, ~: 61591)
MintTests:test_WhenRecipientAddressHasSkipNFTEnabled(uint256) (runs: 276, μ: 85931, ~: 85934)
MintTests:test_WhenRecipientIsAddress0(uint256) (runs: 276, μ: 31043, ~: 30966)
MintTests:test_WhenRecipientsBalanceDifferenceIsNotUpTo1e18(uint256) (runs: 276, μ: 82999, ~: 83101)
MintTests:test_WhenRecipientsBalanceDifferenceIsUpTo1e18OrAbove(uint256) (runs: 276, μ: 89519, ~: 89631)
MintTests:test__codesize() (gas: 27378)
MintTests:test_WhenAmountIsGreaterThan_MAX_SUPPLYOrMintMakesNFTTotalSupplyExceed_MAX_SUPPLY(uint256) (runs: 276, μ: 60713, ~: 61594)
MintTests:test_WhenRecipientAddressHasSkipNFTEnabled(uint256) (runs: 276, μ: 85951, ~: 85935)
MintTests:test_WhenRecipientIsAddress0(uint256) (runs: 276, μ: 31047, ~: 30966)
MintTests:test_WhenRecipientsBalanceDifferenceIsNotUpTo1e18(uint256) (runs: 276, μ: 82981, ~: 83100)
MintTests:test_WhenRecipientsBalanceDifferenceIsUpTo1e18OrAbove(uint256) (runs: 276, μ: 89511, ~: 89631)
MintTests:test__codesize() (gas: 27240)
NFTMintDN404Test:testAllowlistMint() (gas: 258872)
NFTMintDN404Test:testMint() (gas: 231574)
NFTMintDN404Test:testTotalSupplyReached() (gas: 628086918)
NFTMintDN404Test:test__codesize() (gas: 22437)
NFTMintDN404Test:test__codesize() (gas: 22299)
NonMultipleUnitInvariant:invariantBurnedPoolLengthIsTailMinusHead() (runs: 10, calls: 150, reverts: 0)
NonMultipleUnitInvariant:invariantDN404BalanceSum() (runs: 10, calls: 150, reverts: 0)
NonMultipleUnitInvariant:invariantMirror721BalanceSum() (runs: 10, calls: 150, reverts: 0)
Expand All @@ -244,7 +244,7 @@ SimpleDN404Test:testMint() (gas: 49579)
SimpleDN404Test:testName() (gas: 9134)
SimpleDN404Test:testSymbol() (gas: 9132)
SimpleDN404Test:testWithdraw() (gas: 20732)
SimpleDN404Test:test__codesize() (gas: 18359)
SimpleDN404Test:test__codesize() (gas: 18221)
SoladyTest:test__codesize() (gas: 840)
TestPlus:test__codesize() (gas: 406)
WADUnitInvariant:invariantBurnedPoolLengthIsTailMinusHead() (runs: 10, calls: 150, reverts: 0)
Expand Down
87 changes: 34 additions & 53 deletions src/DN404Mirror.sol
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,12 @@ contract DN404Mirror {

/// @dev Equivalent to `safeTransferFrom(from, to, id, "")`.
function safeTransferFrom(address from, address to, uint256 id) public payable virtual {
transferFrom(from, to, id);
if (_hasCode(to)) _checkOnERC721Received(from, to, id, "");
bytes calldata emptyData;
/// @solidity memory-safe-assembly
assembly {
emptyData.length := 0
}
safeTransferFrom(from, to, id, emptyData);
}

/// @dev Transfers token `id` from `from` to `to`.
Expand All @@ -302,7 +306,34 @@ contract DN404Mirror {
virtual
{
transferFrom(from, to, id);
if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
/// @solidity memory-safe-assembly
assembly {
if extcodesize(to) {
// Prepare the calldata.
let m := mload(0x40)
let onERC721ReceivedSelector := 0x150b7a02
mstore(m, onERC721ReceivedSelector)
mstore(add(m, 0x20), caller()) // The `operator`, which is always `msg.sender`.
mstore(add(m, 0x40), shr(96, shl(96, from)))
mstore(add(m, 0x60), id)
mstore(add(m, 0x80), 0x80)
mstore(add(m, 0xa0), data.length)
calldatacopy(add(m, 0xc0), data.offset, data.length)
// Revert if the call reverts.
if iszero(call(gas(), to, 0, add(m, 0x1c), add(data.length, 0xa4), m, 0x20)) {
if returndatasize() {
// Bubble up the revert if the call reverts.
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
}
// Load the returndata and compare it.
if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) {
mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`.
revert(0x1c, 0x04)
}
}
}
}

/// @dev Returns true if this contract implements the interface defined by `interfaceId`.
Expand Down Expand Up @@ -498,14 +529,6 @@ contract DN404Mirror {
}
}

/// @dev Returns if `a` has bytecode of non-zero length.
function _hasCode(address a) private view returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := extcodesize(a) // Can handle dirty upper bits.
}
}

/// @dev More bytecode-efficient way to revert.
function _rv(uint32 s) private pure {
/// @solidity memory-safe-assembly
Expand All @@ -514,46 +537,4 @@ contract DN404Mirror {
revert(0x1c, 0x04)
}
}

/// @dev Perform a call to invoke {IERC721Receiver-onERC721Received} on `to`.
/// Reverts if the target does not support the function correctly.
function _checkOnERC721Received(address from, address to, uint256 id, bytes memory data)
private
{
/// @solidity memory-safe-assembly
assembly {
// Prepare the calldata.
let m := mload(0x40)
let onERC721ReceivedSelector := 0x150b7a02
mstore(m, onERC721ReceivedSelector)
mstore(add(m, 0x20), caller()) // The `operator`, which is always `msg.sender`.
mstore(add(m, 0x40), shr(96, shl(96, from)))
mstore(add(m, 0x60), id)
mstore(add(m, 0x80), 0x80)
let n := mload(data)
mstore(add(m, 0xa0), n)
if n {
let dst := add(m, 0xc0)
let end := add(dst, n)
for { let d := sub(add(data, 0x20), dst) } 1 {} {
mstore(dst, mload(add(dst, d)))
dst := add(dst, 0x20)
if iszero(lt(dst, end)) { break }
}
}
// Revert if the call reverts.
if iszero(call(gas(), to, 0, add(m, 0x1c), add(n, 0xa4), m, 0x20)) {
if returndatasize() {
// Bubble up the revert if the call reverts.
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
}
// Load the returndata and compare it.
if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) {
mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`.
revert(0x1c, 0x04)
}
}
}
}
Loading
Loading