Skip to content

Commit

Permalink
## Version -- 1.5.20
Browse files Browse the repository at this point in the history
- Implement ERC165 compliant version of ERC20.
- Update the NFTSpecChecker and tests.
  • Loading branch information
mvillere committed Feb 16, 2024
1 parent bfbdd74 commit 4017b45
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 21 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ As of 12/13/2022, this repo has been renamed from "nftc-open-contracts" to "nftc
## Version -- 1.5.next [Not published]
- TODO

## Version -- 1.5.20
- Implement ERC165 compliant version of ERC20.
- Update the NFTSpecChecker and tests.

## Version -- 1.5.19
- package lock cleanup
Expand Down
12 changes: 6 additions & 6 deletions contracts/mocks/token/ERC20/MockERC20.sol
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
import '../../../token/openzeppelin/ERC20/extensions/ERC20_165.sol';

/**
* @title MockERC20
* @title MockERC20_165
* @author @NFTCulture
*/
contract MockERC20 is ERC20 {
uint256 private immutable TOTAL_SUPPLY;
contract MockERC20_165 is ERC20_165 {
uint256 private immutable _maxSupply;

constructor() ERC20('MockERC20', 'M20') {
TOTAL_SUPPLY = 1000000000;
constructor() ERC20('MockERC20_165', 'M20') {
_maxSupply = 1000000000;
}
}
19 changes: 19 additions & 0 deletions contracts/token/openzeppelin/ERC20/extensions/ERC20_165.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
import '@openzeppelin/contracts/utils/introspection/ERC165.sol';

/**
* @title ERC20_165
* @author @NiftyMike | @NFTCulture
* @dev ERC20 with ERC165 support tacked on, for consistency with more modern ERC specs.
*/
abstract contract ERC20_165 is ERC20, ERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return
interfaceId == type(IERC20).interfaceId ||
interfaceId == type(IERC20Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
}
18 changes: 9 additions & 9 deletions contracts/utility/introspection/NFTSpecChecker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,17 @@ contract NFTSpecChecker {
bytes4 constant _ERC165_CONTRACT = type(IERC165).interfaceId;

/// @dev See {ERC165Checker-supportsInterface}
///> 0x36372b07
///> 0x36372b07 / 0xa219a025
bytes4 constant _ERC20_CONTRACT = type(IERC20).interfaceId;
bytes4 constant _ERC20_CONTRACT_METADATA = type(IERC20Metadata).interfaceId;

/// @dev See {ERC165Checker-supportsInterface}
///> 0x80ac58cd
///> 0x80ac58cd / 0x5b5e139f
bytes4 constant _ERC721_CONTRACT = type(IERC721).interfaceId;
bytes4 constant _ERC721_CONTRACT_METADATA = type(IERC721Metadata).interfaceId;

/// @dev See {ERC165Checker-supportsInterface}
///> 0xd9b67a26
///> 0xd9b67a26 / 0x0e89341c
bytes4 constant _ERC1155_CONTRACT = type(IERC1155).interfaceId;
bytes4 constant _ERC1155_CONTRACT_METADATA_URI = type(IERC1155MetadataURI).interfaceId;

Expand All @@ -56,8 +56,8 @@ contract NFTSpecChecker {
_checkContract(targetContract, _ERC20_CONTRACT) && _checkContract(targetContract, _ERC20_CONTRACT_METADATA);
}

function getERC20Code() external pure returns (string memory) {
return bytes4ToString(_ERC20_CONTRACT);
function getERC20Codes() external pure returns (string memory, string memory) {
return (bytes4ToString(_ERC20_CONTRACT), bytes4ToString(_ERC20_CONTRACT_METADATA));
}

function checkERC721(address targetContract) external view returns (bool) {
Expand All @@ -66,8 +66,8 @@ contract NFTSpecChecker {
_checkContract(targetContract, _ERC721_CONTRACT_METADATA);
}

function getERC721Code() external pure returns (string memory) {
return bytes4ToString(_ERC721_CONTRACT);
function getERC721Codes() external pure returns (string memory, string memory) {
return (bytes4ToString(_ERC721_CONTRACT), bytes4ToString(_ERC721_CONTRACT_METADATA));
}

function checkERC1155(address targetContract) external view returns (bool) {
Expand All @@ -76,8 +76,8 @@ contract NFTSpecChecker {
_checkContract(targetContract, _ERC1155_CONTRACT_METADATA_URI);
}

function getERC1155Code() external pure returns (string memory) {
return bytes4ToString(_ERC1155_CONTRACT);
function getERC1155Codes() external pure returns (string memory, string memory) {
return (bytes4ToString(_ERC1155_CONTRACT), bytes4ToString(_ERC1155_CONTRACT_METADATA_URI));
}

function checkERC2981(address targetContract) external view returns (bool) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nftculture/nftc-contracts",
"version": "1.5.19",
"version": "1.5.20",
"description": "NFTCulture Open Source Contracts Project",
"author": "@NFTCulture",
"license": "MIT",
Expand Down
13 changes: 8 additions & 5 deletions test/contracts/utility/introspection/NFTSpecChecker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ dotenv.config();

const TESTHARNESS_CONTRACT_NAME = 'TemplateTestHarness';
const SPEC_CHECKER_CONTRACT_NAME = 'NFTSpecChecker';
const MOCK_E20_CONTRACT_NAME = 'MockERC20';
const MOCK_E20_CONTRACT_NAME = 'MockERC20_165';
const MOCK_E721AB_CONTRACT_NAME = 'MockERC721ABurnable';
const MOCK_E1155_CONTRACT_NAME = 'MockERC1155';

Expand Down Expand Up @@ -91,14 +91,17 @@ describe(`File:${__filename}\nContract: ${TESTHARNESS_CONTRACT_NAME}\n`, functio

context('Spec Checker:', function () {
it('uses valid interface codes', async function () {
const erc20Code = await _specCheckerInstance.connect(this.owner).getERC20Code();
const [erc20Code, erc20MetadataCode] = await _specCheckerInstance.connect(this.owner).getERC20Codes();
expect(erc20Code).to.equal('0x36372b07');
expect(erc20MetadataCode).to.equal('0xa219a025');

const erc721Code = await _specCheckerInstance.connect(this.owner).getERC721Code();
const [erc721Code, erc721MetadataCode] = await _specCheckerInstance.connect(this.owner).getERC721Codes();
expect(erc721Code).to.equal('0x80ac58cd');
expect(erc721MetadataCode).to.equal('0x5b5e139f');

const erc1155Code = await _specCheckerInstance.connect(this.owner).getERC1155Code();
const [erc1155Code, erc1155MetadataCode] = await _specCheckerInstance.connect(this.owner).getERC1155Codes();
expect(erc1155Code).to.equal('0xd9b67a26');
expect(erc1155MetadataCode).to.equal('0x0e89341c');

const erc2981Code = await _specCheckerInstance.connect(this.owner).getERC2981Code();
expect(erc2981Code).to.equal('0x2a55205a');
Expand All @@ -107,7 +110,7 @@ describe(`File:${__filename}\nContract: ${TESTHARNESS_CONTRACT_NAME}\n`, functio
expect(erc7572Code).to.equal('0xe8a3d485');
});

it.skip('can validate ERC20s.', async function () {
it('can validate ERC20s.', async function () {
// NOTE: Technically OZ ERC20 doesn't implement ERC165. Hopefully at some point they fix this.
const result = await _specCheckerInstance.connect(this.owner).checkERC20(_mockERC20Instance.address);

Expand Down

0 comments on commit 4017b45

Please sign in to comment.