Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added ownerOf hook+ #14

Merged
merged 5 commits into from
Aug 5, 2023
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
15 changes: 15 additions & 0 deletions src/ERC721ACH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {ERC721AC} from "ERC721C/erc721c/ERC721AC.sol";
import {IERC721A} from "erc721a/contracts/IERC721A.sol";
import {IBeforeTokenTransfersHook} from "./interfaces/IBeforeTokenTransfersHook.sol";
import {IAfterTokenTransfersHook} from "./interfaces/IAfterTokenTransfersHook.sol";
import {IOwnerOfHook} from "./interfaces/IOwnerOfHook.sol";
import {IERC721ACH} from "./interfaces/IERC721ACH.sol";

/**
Expand Down Expand Up @@ -93,6 +94,20 @@ contract ERC721ACH is ERC721AC, IERC721ACH {
}
}

function ownerOf(uint256 tokenId) public view virtual override returns (address) {

IOwnerOfHook ownerOfHook = IOwnerOfHook(hooks[HookType.OwnerOf]);

if (
address(ownerOfHook) != address(0) &&
ownerOfHook.useOwnerOfHook(tokenId)
) {
return ownerOfHook.ownerOfOverrideHook(tokenId);
}

return super.ownerOf(tokenId);
}


/**
* @notice Returns the contract address for a specified hook type.
Expand Down
5 changes: 3 additions & 2 deletions src/interfaces/IERC721ACH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ interface IERC721ACH {
/// @notice Hook for custom logic before a token transfer occurs.
BeforeTokenTransfers,
/// @notice Hook for custom logic after a token transfer occurs.
AfterTokenTransfers

AfterTokenTransfers,
/// @notice Hook for custom logic for ownerOf() function.
OwnerOf
}


Expand Down
35 changes: 35 additions & 0 deletions src/interfaces/IOwnerOfHook.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

/// @title IOwnerOfHook
/// @dev Interface that defines hooks for retrieving the owner of a token.
interface IOwnerOfHook {

/**
@notice Emitted when the owner of hook is used.
@param tokenId The ID of the token whose owner is being retrieved.
@param owner The address of the owner of the token.
*/
event OwnerOfHookUsed(
uint256 tokenId,
address owner
);

/**
@notice Checks if the owner retrieval function should use the custom hook.
@param tokenId The ID of the token whose owner is being retrieved.
@return A boolean indicating whether or not to use the custom hook for the owner retrieval function.
*/
function useOwnerOfHook(
uint256 tokenId
) external view returns (bool);

/**
@notice Provides a custom implementation for the owner retrieval process.
@param tokenId The ID of the token whose owner is being retrieved.
@return The address of the owner of the token.
*/
function ownerOfOverrideHook(
uint256 tokenId
) external view returns (address);
}
54 changes: 54 additions & 0 deletions test/hooks/OwnerOfHook.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

import {Vm} from "forge-std/Vm.sol";
import {DSTest} from "ds-test/test.sol";
import {ERC721ACHMock} from "../utils/ERC721ACHMock.sol";
import {IERC721A} from "lib/ERC721A/contracts/IERC721A.sol";
import {OwnerOfHookMock} from "../utils/hooks/OwnerOfHookMock.sol";
import {IERC721ACH} from "../../src/interfaces/IERC721ACH.sol";

contract OwnerOfHookTest is DSTest {
Vm public constant vm = Vm(HEVM_ADDRESS);
address public constant DEFAULT_OWNER_ADDRESS = address(0xC0FFEE);
address public constant DEFAULT_BUYER_ADDRESS = address(0xBABE);
ERC721ACHMock erc721Mock;
OwnerOfHookMock hookMock;

IERC721ACH.HookType constant OwnerOf = IERC721ACH.HookType.OwnerOf;

function setUp() public {
erc721Mock = new ERC721ACHMock(DEFAULT_OWNER_ADDRESS);
hookMock = new OwnerOfHookMock();
}

function test_ownerOfHook() public {
assertEq(address(0), address(erc721Mock.getHook(OwnerOf)));
}

function test_setOwnerOfHook() public {
assertEq(address(0), address(erc721Mock.getHook(OwnerOf)));

// calling an admin function without being the contract owner should revert
vm.expectRevert();
erc721Mock.setHook(OwnerOf, address(hookMock));

vm.prank(DEFAULT_OWNER_ADDRESS);
erc721Mock.setHook(OwnerOf, address(hookMock));
assertEq(address(hookMock), address(erc721Mock.getHook(OwnerOf)));
}

function test_ownerOfHook(uint256 tokenId) public {
vm.assume(tokenId > 0);
vm.assume(tokenId < 10);

test_setOwnerOfHook();
erc721Mock.mint(DEFAULT_BUYER_ADDRESS, tokenId);

assertEq(DEFAULT_BUYER_ADDRESS, erc721Mock.ownerOf(tokenId));

hookMock.setHooksEnabled(true);
vm.expectRevert(OwnerOfHookMock.OwnerOfHook_Executed.selector);
erc721Mock.ownerOf(tokenId);
}
}
37 changes: 37 additions & 0 deletions test/utils/hooks/OwnerOfHookMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

import {IOwnerOfHook} from "../../../src/interfaces/IOwnerOfHook.sol";

contract OwnerOfHookMock is IOwnerOfHook {
/// @notice hook was executed
error OwnerOfHook_Executed();

bool public hooksEnabled;
address public fixedOwner;

/// @notice toggle ownerOf hook.
function setHooksEnabled(bool _enabled) public {
hooksEnabled = _enabled;
}

/// @notice set fixed owner returned by the hook.
function setFixedOwner(address _fixedOwner) public {
fixedOwner = _fixedOwner;
}

/// @notice Check if the ownerOf function should use hook.
/// @dev Returns whether or not to use the hook for ownerOf function
function useOwnerOfHook(
uint256
) external view override returns (bool) {
return hooksEnabled;
}

/// @notice custom implementation for ownerOf Hook.
function ownerOfOverrideHook(
uint256
) external view override returns (address) {
revert OwnerOfHook_Executed();
}
}
Loading