diff --git a/src/DN404.sol b/src/DN404.sol index 0e888f9..b1ed1ee 100644 --- a/src/DN404.sol +++ b/src/DN404.sol @@ -249,6 +249,13 @@ abstract contract DN404 { mstore(0x00, 0xd125259c) // `LinkMirrorContractFailed()`. revert(0x1c, 0x04) } + // Query `owner()` on this contract, and if it is non-zero, call `pullOwner()` on the mirror. + // This allows for any Ownable (e.g. OpenZeppelin, Solady). + mstore(0x00, 0x8da5cb5b6cef16e6) // `owner()` and `pullOwner()`. + if and( + lt(iszero(shl(96, mload(0x20))), gt(returndatasize(), 0x1f)), + staticcall(gas(), address(), 0x18, 0x04, 0x20, 0x20) + ) { if iszero(call(gas(), mirror, 0, 0x1c, 0x04, 0x00, 0x00)) { revert(0x00, 0x00) } } } $.nextTokenId = uint32(_toUint(_useOneIndexed())); diff --git a/test/DN404Mirror.t.sol b/test/DN404Mirror.t.sol index 4c09229..86a5b08 100644 --- a/test/DN404Mirror.t.sol +++ b/test/DN404Mirror.t.sol @@ -293,19 +293,36 @@ contract DN404MirrorTest is SoladyTest { assertEq(mirror.owner(), address(0)); } - function testPullOwnerWithOwnable() public { - MockDN404Ownable dnOwnable = new MockDN404Ownable(); + function testAutomaticPullOwnerWithOwnable() public { + MockDN404Ownable dnOwnable = new MockDN404Ownable(address(0)); dnOwnable.initializeDN404(1000, address(this), address(mirror)); + assertEq(mirror.owner(), address(0)); + mirror.pullOwner(); + assertEq(mirror.owner(), address(0)); + + dnOwnable.initializeOwner(address(this)); + assertEq(mirror.owner(), address(0)); + mirror.pullOwner(); + assertEq(mirror.owner(), address(this)); + address newOwner = address(123); dnOwnable.transferOwnership(newOwner); - assertEq(mirror.owner(), address(0)); vm.expectEmit(true, true, true, true); - emit OwnershipTransferred(address(0), newOwner); + emit OwnershipTransferred(address(this), newOwner); mirror.pullOwner(); assertEq(mirror.owner(), newOwner); } + function testAutomaticPullOwnerWithOwnable2() public { + MockDN404Ownable dnOwnable = new MockDN404Ownable(address(this)); + assertEq(mirror.owner(), address(0)); + vm.expectEmit(true, true, true, true); + emit OwnershipTransferred(address(0), address(this)); + dnOwnable.initializeDN404(1000, address(this), address(mirror)); + assertEq(mirror.owner(), address(this)); + } + function testFnSelectorNotRecognized() public { (bool success, bytes memory result) = address(dn).call(abi.encodeWithSignature("nonSupportedFunction123()")); diff --git a/test/utils/mocks/MockDN404Ownable.sol b/test/utils/mocks/MockDN404Ownable.sol index 050288a..5956cec 100644 --- a/test/utils/mocks/MockDN404Ownable.sol +++ b/test/utils/mocks/MockDN404Ownable.sol @@ -5,7 +5,13 @@ import "./MockDN404.sol"; import {Ownable} from "solady/auth/Ownable.sol"; contract MockDN404Ownable is MockDN404, Ownable { - constructor() { - _initializeOwner(msg.sender); + constructor(address initialOwner) { + if (initialOwner != address(0)) { + _initializeOwner(initialOwner); + } + } + + function initializeOwner(address initialOwner) public { + _initializeOwner(initialOwner); } }