|
@@ -0,0 +1,299 @@
|
|
|
+const { ethers } = require('hardhat');
|
|
|
+const { expect } = require('chai');
|
|
|
+const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
|
|
|
+const { RevertType } = require('../../../helpers/enums');
|
|
|
+const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic');
|
|
|
+
|
|
|
+const firstTokenId = 1n;
|
|
|
+const secondTokenId = 2n;
|
|
|
+const firstTokenValue = 1000n;
|
|
|
+const secondTokenValue = 1000n;
|
|
|
+
|
|
|
+const RECEIVER_SINGLE_MAGIC_VALUE = '0xf23a6e61';
|
|
|
+const RECEIVER_BATCH_MAGIC_VALUE = '0xbc197c81';
|
|
|
+
|
|
|
+const deployReceiver = (
|
|
|
+ revertType,
|
|
|
+ returnValueSingle = RECEIVER_SINGLE_MAGIC_VALUE,
|
|
|
+ returnValueBatched = RECEIVER_BATCH_MAGIC_VALUE,
|
|
|
+) => ethers.deployContract('$ERC1155ReceiverMock', [returnValueSingle, returnValueBatched, revertType]);
|
|
|
+
|
|
|
+const fixture = async () => {
|
|
|
+ const [eoa, operator, owner] = await ethers.getSigners();
|
|
|
+ const utils = await ethers.deployContract('$ERC1155Utils');
|
|
|
+
|
|
|
+ const receivers = {
|
|
|
+ correct: await deployReceiver(RevertType.None),
|
|
|
+ invalid: await deployReceiver(RevertType.None, '0xdeadbeef', '0xdeadbeef'),
|
|
|
+ message: await deployReceiver(RevertType.RevertWithMessage),
|
|
|
+ empty: await deployReceiver(RevertType.RevertWithoutMessage),
|
|
|
+ customError: await deployReceiver(RevertType.RevertWithCustomError),
|
|
|
+ panic: await deployReceiver(RevertType.Panic),
|
|
|
+ nonReceiver: await ethers.deployContract('CallReceiverMock'),
|
|
|
+ eoa,
|
|
|
+ };
|
|
|
+
|
|
|
+ return { operator, owner, utils, receivers };
|
|
|
+};
|
|
|
+
|
|
|
+describe('ERC1155Utils', function () {
|
|
|
+ beforeEach(async function () {
|
|
|
+ Object.assign(this, await loadFixture(fixture));
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('onERC1155Received', function () {
|
|
|
+ it('succeeds when called by an EOA', async function () {
|
|
|
+ await expect(
|
|
|
+ this.utils.$checkOnERC1155Received(
|
|
|
+ this.operator,
|
|
|
+ this.owner,
|
|
|
+ this.receivers.eoa,
|
|
|
+ firstTokenId,
|
|
|
+ firstTokenValue,
|
|
|
+ '0x',
|
|
|
+ ),
|
|
|
+ ).to.not.be.reverted;
|
|
|
+ });
|
|
|
+
|
|
|
+ it('succeeds when data is passed', async function () {
|
|
|
+ const data = '0x12345678';
|
|
|
+ await expect(
|
|
|
+ this.utils.$checkOnERC1155Received(
|
|
|
+ this.operator,
|
|
|
+ this.owner,
|
|
|
+ this.receivers.correct,
|
|
|
+ firstTokenId,
|
|
|
+ firstTokenValue,
|
|
|
+ data,
|
|
|
+ ),
|
|
|
+ ).to.not.be.reverted;
|
|
|
+ });
|
|
|
+
|
|
|
+ it('succeeds when data is empty', async function () {
|
|
|
+ await expect(
|
|
|
+ this.utils.$checkOnERC1155Received(
|
|
|
+ this.operator,
|
|
|
+ this.owner,
|
|
|
+ this.receivers.correct,
|
|
|
+ firstTokenId,
|
|
|
+ firstTokenValue,
|
|
|
+ '0x',
|
|
|
+ ),
|
|
|
+ ).to.not.be.reverted;
|
|
|
+ });
|
|
|
+
|
|
|
+ it('reverts when receiver returns invalid value', async function () {
|
|
|
+ await expect(
|
|
|
+ this.utils.$checkOnERC1155Received(
|
|
|
+ this.operator,
|
|
|
+ this.owner,
|
|
|
+ this.receivers.invalid,
|
|
|
+ firstTokenId,
|
|
|
+ firstTokenValue,
|
|
|
+ '0x',
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ .to.be.revertedWithCustomError(this.utils, 'ERC1155InvalidReceiver')
|
|
|
+ .withArgs(this.receivers.invalid);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('reverts when receiver reverts with message', async function () {
|
|
|
+ await expect(
|
|
|
+ this.utils.$checkOnERC1155Received(
|
|
|
+ this.operator,
|
|
|
+ this.owner,
|
|
|
+ this.receivers.message,
|
|
|
+ firstTokenId,
|
|
|
+ firstTokenValue,
|
|
|
+ '0x',
|
|
|
+ ),
|
|
|
+ ).to.be.revertedWith('ERC1155ReceiverMock: reverting on receive');
|
|
|
+ });
|
|
|
+
|
|
|
+ it('reverts when receiver reverts without message', async function () {
|
|
|
+ await expect(
|
|
|
+ this.utils.$checkOnERC1155Received(
|
|
|
+ this.operator,
|
|
|
+ this.owner,
|
|
|
+ this.receivers.empty,
|
|
|
+ firstTokenId,
|
|
|
+ firstTokenValue,
|
|
|
+ '0x',
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ .to.be.revertedWithCustomError(this.utils, 'ERC1155InvalidReceiver')
|
|
|
+ .withArgs(this.receivers.empty);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('reverts when receiver reverts with custom error', async function () {
|
|
|
+ await expect(
|
|
|
+ this.utils.$checkOnERC1155Received(
|
|
|
+ this.operator,
|
|
|
+ this.owner,
|
|
|
+ this.receivers.customError,
|
|
|
+ firstTokenId,
|
|
|
+ firstTokenValue,
|
|
|
+ '0x',
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ .to.be.revertedWithCustomError(this.receivers.customError, 'CustomError')
|
|
|
+ .withArgs(RECEIVER_SINGLE_MAGIC_VALUE);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('reverts when receiver panics', async function () {
|
|
|
+ await expect(
|
|
|
+ this.utils.$checkOnERC1155Received(
|
|
|
+ this.operator,
|
|
|
+ this.owner,
|
|
|
+ this.receivers.panic,
|
|
|
+ firstTokenId,
|
|
|
+ firstTokenValue,
|
|
|
+ '0x',
|
|
|
+ ),
|
|
|
+ ).to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('reverts when receiver does not implement onERC1155Received', async function () {
|
|
|
+ await expect(
|
|
|
+ this.utils.$checkOnERC1155Received(
|
|
|
+ this.operator,
|
|
|
+ this.owner,
|
|
|
+ this.receivers.nonReceiver,
|
|
|
+ firstTokenId,
|
|
|
+ firstTokenValue,
|
|
|
+ '0x',
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ .to.be.revertedWithCustomError(this.utils, 'ERC1155InvalidReceiver')
|
|
|
+ .withArgs(this.receivers.nonReceiver);
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('onERC1155BatchReceived', function () {
|
|
|
+ it('succeeds when called by an EOA', async function () {
|
|
|
+ await expect(
|
|
|
+ this.utils.$checkOnERC1155BatchReceived(
|
|
|
+ this.operator,
|
|
|
+ this.owner,
|
|
|
+ this.receivers.eoa,
|
|
|
+ [firstTokenId, secondTokenId],
|
|
|
+ [firstTokenValue, secondTokenValue],
|
|
|
+ '0x',
|
|
|
+ ),
|
|
|
+ ).to.not.be.reverted;
|
|
|
+ });
|
|
|
+
|
|
|
+ it('succeeds when data is passed', async function () {
|
|
|
+ const data = '0x12345678';
|
|
|
+ await expect(
|
|
|
+ this.utils.$checkOnERC1155BatchReceived(
|
|
|
+ this.operator,
|
|
|
+ this.owner,
|
|
|
+ this.receivers.correct,
|
|
|
+ [firstTokenId, secondTokenId],
|
|
|
+ [firstTokenValue, secondTokenValue],
|
|
|
+ data,
|
|
|
+ ),
|
|
|
+ ).to.not.be.reverted;
|
|
|
+ });
|
|
|
+
|
|
|
+ it('succeeds when data is empty', async function () {
|
|
|
+ await expect(
|
|
|
+ this.utils.$checkOnERC1155BatchReceived(
|
|
|
+ this.operator,
|
|
|
+ this.owner,
|
|
|
+ this.receivers.correct,
|
|
|
+ [firstTokenId, secondTokenId],
|
|
|
+ [firstTokenValue, secondTokenValue],
|
|
|
+ '0x',
|
|
|
+ ),
|
|
|
+ ).to.not.be.reverted;
|
|
|
+ });
|
|
|
+
|
|
|
+ it('reverts when receiver returns invalid value', async function () {
|
|
|
+ await expect(
|
|
|
+ this.utils.$checkOnERC1155BatchReceived(
|
|
|
+ this.operator,
|
|
|
+ this.owner,
|
|
|
+ this.receivers.invalid,
|
|
|
+ [firstTokenId, secondTokenId],
|
|
|
+ [firstTokenValue, secondTokenValue],
|
|
|
+ '0x',
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ .to.be.revertedWithCustomError(this.utils, 'ERC1155InvalidReceiver')
|
|
|
+ .withArgs(this.receivers.invalid);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('reverts when receiver reverts with message', async function () {
|
|
|
+ await expect(
|
|
|
+ this.utils.$checkOnERC1155BatchReceived(
|
|
|
+ this.operator,
|
|
|
+ this.owner,
|
|
|
+ this.receivers.message,
|
|
|
+ [firstTokenId, secondTokenId],
|
|
|
+ [firstTokenValue, secondTokenValue],
|
|
|
+ '0x',
|
|
|
+ ),
|
|
|
+ ).to.be.revertedWith('ERC1155ReceiverMock: reverting on batch receive');
|
|
|
+ });
|
|
|
+
|
|
|
+ it('reverts when receiver reverts without message', async function () {
|
|
|
+ await expect(
|
|
|
+ this.utils.$checkOnERC1155BatchReceived(
|
|
|
+ this.operator,
|
|
|
+ this.owner,
|
|
|
+ this.receivers.empty,
|
|
|
+ [firstTokenId, secondTokenId],
|
|
|
+ [firstTokenValue, secondTokenValue],
|
|
|
+ '0x',
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ .to.be.revertedWithCustomError(this.utils, 'ERC1155InvalidReceiver')
|
|
|
+ .withArgs(this.receivers.empty);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('reverts when receiver reverts with custom error', async function () {
|
|
|
+ await expect(
|
|
|
+ this.utils.$checkOnERC1155BatchReceived(
|
|
|
+ this.operator,
|
|
|
+ this.owner,
|
|
|
+ this.receivers.customError,
|
|
|
+ [firstTokenId, secondTokenId],
|
|
|
+ [firstTokenValue, secondTokenValue],
|
|
|
+ '0x',
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ .to.be.revertedWithCustomError(this.receivers.customError, 'CustomError')
|
|
|
+ .withArgs(RECEIVER_SINGLE_MAGIC_VALUE);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('reverts when receiver panics', async function () {
|
|
|
+ await expect(
|
|
|
+ this.utils.$checkOnERC1155BatchReceived(
|
|
|
+ this.operator,
|
|
|
+ this.owner,
|
|
|
+ this.receivers.panic,
|
|
|
+ [firstTokenId, secondTokenId],
|
|
|
+ [firstTokenValue, secondTokenValue],
|
|
|
+ '0x',
|
|
|
+ ),
|
|
|
+ ).to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('reverts when receiver does not implement onERC1155BatchReceived', async function () {
|
|
|
+ await expect(
|
|
|
+ this.utils.$checkOnERC1155BatchReceived(
|
|
|
+ this.operator,
|
|
|
+ this.owner,
|
|
|
+ this.receivers.nonReceiver,
|
|
|
+ [firstTokenId, secondTokenId],
|
|
|
+ [firstTokenValue, secondTokenValue],
|
|
|
+ '0x',
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ .to.be.revertedWithCustomError(this.utils, 'ERC1155InvalidReceiver')
|
|
|
+ .withArgs(this.receivers.nonReceiver);
|
|
|
+ });
|
|
|
+ });
|
|
|
+});
|