Adopt new Solidity features interfaceId, try/catch, keccak constants (#2487)
* Clean code - using type().interfaceId to improve readeability of ERC165 registration - hardcoding some keccak256 that are otherwise computed at construction. * hardcode keccak256 result * Improve code readeability using try/catch * Remove hardcoded hash tests show that solc 0.8.0 does the optimization as expected * Use try/catch to improve readability * ERC165Checker: Do not revert when returndata is empty + new test * Address PR comments * improve testing of ERC721Receiver errors * put back comment about invalid interface id * coverage does not support 0.8.1. Reverting back to 0.8.0 * bubble all data with length > 0 if onERC721Receive fails. * Fix test: revert without message trigger is bubble with the default message * using enum object to improve readability
This commit is contained in:
@ -3,6 +3,7 @@ require('@openzeppelin/test-helpers');
|
||||
const { expect } = require('chai');
|
||||
|
||||
const ERC165CheckerMock = artifacts.require('ERC165CheckerMock');
|
||||
const ERC165MissingData = artifacts.require('ERC165MissingData');
|
||||
const ERC165NotSupported = artifacts.require('ERC165NotSupported');
|
||||
const ERC165InterfacesSupported = artifacts.require('ERC165InterfacesSupported');
|
||||
|
||||
@ -18,6 +19,33 @@ contract('ERC165Checker', function (accounts) {
|
||||
this.mock = await ERC165CheckerMock.new();
|
||||
});
|
||||
|
||||
context('ERC165 missing return data', function () {
|
||||
beforeEach(async function () {
|
||||
this.target = await ERC165MissingData.new();
|
||||
});
|
||||
|
||||
it('does not support ERC165', async function () {
|
||||
const supported = await this.mock.supportsERC165(this.target.address);
|
||||
expect(supported).to.equal(false);
|
||||
});
|
||||
|
||||
it('does not support mock interface via supportsInterface', async function () {
|
||||
const supported = await this.mock.supportsInterface(this.target.address, DUMMY_ID);
|
||||
expect(supported).to.equal(false);
|
||||
});
|
||||
|
||||
it('does not support mock interface via supportsAllInterfaces', async function () {
|
||||
const supported = await this.mock.supportsAllInterfaces(this.target.address, [DUMMY_ID]);
|
||||
expect(supported).to.equal(false);
|
||||
});
|
||||
|
||||
it('does not support mock interface via getSupportedInterfaces', async function () {
|
||||
const supported = await this.mock.getSupportedInterfaces(this.target.address, [DUMMY_ID]);
|
||||
expect(supported.length).to.equal(1);
|
||||
expect(supported[0]).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
context('ERC165 not supported', function () {
|
||||
beforeEach(async function () {
|
||||
this.target = await ERC165NotSupported.new();
|
||||
|
||||
@ -8,6 +8,9 @@ const { shouldSupportInterfaces } = require('../../introspection/SupportsInterfa
|
||||
const ERC721Mock = artifacts.require('ERC721Mock');
|
||||
const ERC721ReceiverMock = artifacts.require('ERC721ReceiverMock');
|
||||
|
||||
const Error = [ 'None', 'RevertWithMessage', 'RevertWithoutMessage', 'Panic' ]
|
||||
.reduce((acc, entry, idx) => Object.assign({ [entry]: idx }, acc), {});
|
||||
|
||||
contract('ERC721', function (accounts) {
|
||||
const [owner, newOwner, approved, anotherApproved, operator, other] = accounts;
|
||||
|
||||
@ -324,7 +327,7 @@ contract('ERC721', function (accounts) {
|
||||
|
||||
describe('to a valid receiver contract', function () {
|
||||
beforeEach(async function () {
|
||||
this.receiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, false);
|
||||
this.receiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.None);
|
||||
this.toWhom = this.receiver.address;
|
||||
});
|
||||
|
||||
@ -379,7 +382,7 @@ contract('ERC721', function (accounts) {
|
||||
|
||||
describe('to a receiver contract returning unexpected value', function () {
|
||||
it('reverts', async function () {
|
||||
const invalidReceiver = await ERC721ReceiverMock.new('0x42', false);
|
||||
const invalidReceiver = await ERC721ReceiverMock.new('0x42', Error.None);
|
||||
await expectRevert(
|
||||
this.token.safeTransferFrom(owner, invalidReceiver.address, tokenId, { from: owner }),
|
||||
'ERC721: transfer to non ERC721Receiver implementer',
|
||||
@ -387,9 +390,9 @@ contract('ERC721', function (accounts) {
|
||||
});
|
||||
});
|
||||
|
||||
describe('to a receiver contract that throws', function () {
|
||||
describe('to a receiver contract that reverts with message', function () {
|
||||
it('reverts', async function () {
|
||||
const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, true);
|
||||
const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.RevertWithMessage);
|
||||
await expectRevert(
|
||||
this.token.safeTransferFrom(owner, revertingReceiver.address, tokenId, { from: owner }),
|
||||
'ERC721ReceiverMock: reverting',
|
||||
@ -397,6 +400,25 @@ contract('ERC721', function (accounts) {
|
||||
});
|
||||
});
|
||||
|
||||
describe('to a receiver contract that reverts without message', function () {
|
||||
it('reverts', async function () {
|
||||
const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.RevertWithoutMessage);
|
||||
await expectRevert(
|
||||
this.token.safeTransferFrom(owner, revertingReceiver.address, tokenId, { from: owner }),
|
||||
'ERC721: transfer to non ERC721Receiver implementer',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('to a receiver contract that panics', function () {
|
||||
it('reverts', async function () {
|
||||
const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.Panic);
|
||||
await expectRevert.unspecified(
|
||||
this.token.safeTransferFrom(owner, revertingReceiver.address, tokenId, { from: owner }),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('to a contract that does not implement the required function', function () {
|
||||
it('reverts', async function () {
|
||||
const nonReceiver = this.token;
|
||||
@ -416,7 +438,7 @@ contract('ERC721', function (accounts) {
|
||||
|
||||
describe('via safeMint', function () { // regular minting is tested in ERC721Mintable.test.js and others
|
||||
it('calls onERC721Received — with data', async function () {
|
||||
this.receiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, false);
|
||||
this.receiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.None);
|
||||
const receipt = await this.token.safeMint(this.receiver.address, tokenId, data);
|
||||
|
||||
await expectEvent.inTransaction(receipt.tx, ERC721ReceiverMock, 'Received', {
|
||||
@ -427,7 +449,7 @@ contract('ERC721', function (accounts) {
|
||||
});
|
||||
|
||||
it('calls onERC721Received — without data', async function () {
|
||||
this.receiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, false);
|
||||
this.receiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.None);
|
||||
const receipt = await this.token.safeMint(this.receiver.address, tokenId);
|
||||
|
||||
await expectEvent.inTransaction(receipt.tx, ERC721ReceiverMock, 'Received', {
|
||||
@ -438,7 +460,7 @@ contract('ERC721', function (accounts) {
|
||||
|
||||
context('to a receiver contract returning unexpected value', function () {
|
||||
it('reverts', async function () {
|
||||
const invalidReceiver = await ERC721ReceiverMock.new('0x42', false);
|
||||
const invalidReceiver = await ERC721ReceiverMock.new('0x42', Error.None);
|
||||
await expectRevert(
|
||||
this.token.safeMint(invalidReceiver.address, tokenId),
|
||||
'ERC721: transfer to non ERC721Receiver implementer',
|
||||
@ -446,9 +468,9 @@ contract('ERC721', function (accounts) {
|
||||
});
|
||||
});
|
||||
|
||||
context('to a receiver contract that throws', function () {
|
||||
context('to a receiver contract that reverts with message', function () {
|
||||
it('reverts', async function () {
|
||||
const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, true);
|
||||
const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.RevertWithMessage);
|
||||
await expectRevert(
|
||||
this.token.safeMint(revertingReceiver.address, tokenId),
|
||||
'ERC721ReceiverMock: reverting',
|
||||
@ -456,6 +478,25 @@ contract('ERC721', function (accounts) {
|
||||
});
|
||||
});
|
||||
|
||||
context('to a receiver contract that reverts without message', function () {
|
||||
it('reverts', async function () {
|
||||
const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.RevertWithoutMessage);
|
||||
await expectRevert(
|
||||
this.token.safeMint(revertingReceiver.address, tokenId),
|
||||
'ERC721: transfer to non ERC721Receiver implementer',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('to a receiver contract that panics', function () {
|
||||
it('reverts', async function () {
|
||||
const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.Panic);
|
||||
await expectRevert.unspecified(
|
||||
this.token.safeMint(revertingReceiver.address, tokenId),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('to a contract that does not implement the required function', function () {
|
||||
it('reverts', async function () {
|
||||
const nonReceiver = this.token;
|
||||
|
||||
Reference in New Issue
Block a user