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

safemint #4

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
19 changes: 19 additions & 0 deletions src/ERC721ACH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ contract ERC721ACH is ERC721AC, IERC721ACH {
ISetApprovalForAllHook public setApprovalForAllHook;
IGetApprovedHook public getApprovedHook;
IIsApprovedForAllHook public isApprovedForAllHook;
ISafeMintHook public safeMintHook;

/// @notice Contract constructor
/// @param _contractName The name for the token contract
Expand All @@ -45,6 +46,18 @@ contract ERC721ACH is ERC721AC, IERC721ACH {
return super.supportsInterface(interfaceId);
}

/// @inheritdoc IERC721A
function mint(address to, uint256 quantity) external {
if (
address(safeMintHook) != address(0) &&
safeMintHook.useSafeMintHook(to, quantity)
) {
safeMintHook.safeMintOverrideHook(to, quantity);
} else {
super._safeMint(to, quantity);
}
}

/////////////////////////////////////////////////
/// ERC721 overrides
/////////////////////////////////////////////////
Expand Down Expand Up @@ -247,6 +260,12 @@ contract ERC721ACH is ERC721AC, IERC721ACH {
emit UpdatedHookBalanceOf(msg.sender, address(_hook));
}

/// TODO
function setSafeMintHook(ISafeMintHook _hook) external virtual onlyOwner {
safeMintHook = _hook;
emit SafeMintHookUsed(msg.sender, address(_hook));
}

/// TODO
function setOwnerOfHook(IOwnerOfHook _hook) external virtual onlyOwner {
ownerOfHook = _hook;
Expand Down
6 changes: 5 additions & 1 deletion src/interfaces/IERC721ACH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import {IApproveHook} from "./IApproveHook.sol";
import {ISetApprovalForAllHook} from "./ISetApprovalForAllHook.sol";
import {IGetApprovedHook} from "./IGetApprovedHook.sol";
import {IIsApprovedForAllHook} from "./IIsApprovedForAllHook.sol";
import {ISafeMintHook} from "./ISafeMintHook.sol";

interface IERC721ACH {
interface IERC721ACH is ISafeMintHook {
/// @notice error onlyOwner
error Access_OnlyOwner();

Expand Down Expand Up @@ -66,6 +67,9 @@ interface IERC721ACH {
/// TODO
function setBalanceOfHook(IBalanceOfHook _hook) external;

/// TODO
function setSafeMintHook(ISafeMintHook _hook) external;

/// TODO
function setOwnerOfHook(IOwnerOfHook _hook) external;

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

interface ISafeMintHook {

/// @notice Emitted when approve hook is used
/// @param to The address to hold the minted token
/// @param quantity The token quantity to be minted
event SafeMintHookUsed(address indexed to, uint256 indexed quantity);

/// @notice Check if the safeMint function should use hook.
/// @param to The address to hold the minted token
/// @param quantity The token quantity to be minted
function useSafeMintHook(address to, uint256 quantity) public ;

/// @notice safeMint Hook for custom implementation.
/// @param to The address to hold the minted token
/// @param quantity The token quantity to be minted
function safeMintOverrideHook(
address to,
uint256 quantity
) external view returns (uint256);
}
54 changes: 54 additions & 0 deletions test/hooks/SafeMintHook.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 {SafeMintHookMock} from "../utils/hooks/SafeMintHookMock.sol";

contract SafeMintHook is DSTest {
Vm public constant vm = Vm(HEVM_ADDRESS);
address public constant DEFAULT_OWNER_ADDRESS = address(0x23499);
address public constant DEFAULT_BUYER_ADDRESS = address(0x111);
ERC721ACHMock erc721Mock;
SafeMintHookMock hookMock;

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

function test_mintHook() public {
assertEq(address(0), address(erc721Mock.safeMintHook()));
}

function test_setSafeMintHook() public {
assertEq(address(0), address(erc721Mock.safeMintHook()));
vm.prank(DEFAULT_OWNER_ADDRESS);
erc721Mock.setSafeMintHook(hookMock);
assertEq(address(hookMock), address(erc721Mock.safeMintHook()));
}

function test_mint(
uint256 _mintQuantity,
) public {
vm.assume(_mintQuantity > 0);


// Verify normal functionality
uint256 preTotalSupply = erc721Mock.totalSupply();
erc721Mock.mint(DEFAULT_BUYER_ADDRESS, _mintQuantity);
uint256 totalSupply = erc721Mock.totalSupply();
assertEq(preTotalSupply + _mintQuantity, totalSupply);

// Verify hook override
test_setSafeMintHook();
hookMock.setSafeMintEnabled(true);
uint256 preTotalSupply = erc721Mock.totalSupply();
erc721Mock.mint(DEFAULT_BUYER_ADDRESS, _mintQuantity);
uint256 totalSupply = erc721Mock.totalSupply();
assertEq(preTotalSupply + _mintQuantity, totalSupply);

}
}
33 changes: 33 additions & 0 deletions test/utils/hooks/SafeMintHookMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

import {ISafeMintHook} from "../../../src/interfaces/ISafeMintHook";

contract SafeMintHookMock is ISafeMintHook {
/// @notice safeMint hook was executed
error SafeMintHook_Executed();

bool public hooksEnabled;

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

/// @notice Check if the safeMint function should use hook.
/// @dev Returns whether or not to use the hook for safeMint function
function useSafeMintHook(
address to,
uint256 quantity
) external view override{
require(quantity > 0, "SafeMintHook: Invalid Qualtity")
}

/// @notice safeMint Hook for custom implementation.
function safeMintOverrideHook(
address,
uint256
) external pure override {
revert SafeMintHook_Executed();
}
}
Loading