From be0572a8dc80dd7d2766c2a15f9eb5436ed3a445 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 21 Dec 2023 22:57:39 +0100 Subject: [PATCH] Migrate ERC1155 tests to ethers v6 (#4771) Co-authored-by: ernestognw --- .../generate/templates/EnumerableMap.opts.js | 5 +- .../generate/templates/EnumerableSet.opts.js | 4 +- test/access/Ownable.test.js | 2 +- test/access/manager/AccessManaged.test.js | 2 +- test/helpers/enums.js | 1 + test/token/ERC1155/ERC1155.behavior.js | 1111 ++++++++--------- test/token/ERC1155/ERC1155.test.js | 227 ++-- .../extensions/ERC1155Burnable.test.js | 67 +- .../extensions/ERC1155Pausable.test.js | 110 +- .../ERC1155/extensions/ERC1155Supply.test.js | 155 +-- .../extensions/ERC1155URIStorage.test.js | 76 +- .../token/ERC1155/utils/ERC1155Holder.test.js | 78 +- test/token/ERC721/ERC721.behavior.js | 4 +- 13 files changed, 847 insertions(+), 995 deletions(-) diff --git a/scripts/generate/templates/EnumerableMap.opts.js b/scripts/generate/templates/EnumerableMap.opts.js index 699fa7b14..7fef393a2 100644 --- a/scripts/generate/templates/EnumerableMap.opts.js +++ b/scripts/generate/templates/EnumerableMap.opts.js @@ -1,4 +1,7 @@ -const mapType = str => (str == 'uint256' ? 'Uint' : `${str.charAt(0).toUpperCase()}${str.slice(1)}`); +const { capitalize } = require('../../helpers'); + +const mapType = str => (str == 'uint256' ? 'Uint' : capitalize(str)); + const formatType = (keyType, valueType) => ({ name: `${mapType(keyType)}To${mapType(valueType)}Map`, keyType, diff --git a/scripts/generate/templates/EnumerableSet.opts.js b/scripts/generate/templates/EnumerableSet.opts.js index fb53724fe..739f0acdf 100644 --- a/scripts/generate/templates/EnumerableSet.opts.js +++ b/scripts/generate/templates/EnumerableSet.opts.js @@ -1,4 +1,6 @@ -const mapType = str => (str == 'uint256' ? 'Uint' : `${str.charAt(0).toUpperCase()}${str.slice(1)}`); +const { capitalize } = require('../../helpers'); + +const mapType = str => (str == 'uint256' ? 'Uint' : capitalize(str)); const formatType = type => ({ name: `${mapType(type)}Set`, diff --git a/test/access/Ownable.test.js b/test/access/Ownable.test.js index 568d52b68..d565fc382 100644 --- a/test/access/Ownable.test.js +++ b/test/access/Ownable.test.js @@ -14,7 +14,7 @@ describe('Ownable', function () { }); it('emits ownership transfer events during construction', async function () { - await expect(await this.ownable.deploymentTransaction()) + await expect(this.ownable.deploymentTransaction()) .to.emit(this.ownable, 'OwnershipTransferred') .withArgs(ethers.ZeroAddress, this.owner.address); }); diff --git a/test/access/manager/AccessManaged.test.js b/test/access/manager/AccessManaged.test.js index f3a433ebd..b468128ff 100644 --- a/test/access/manager/AccessManaged.test.js +++ b/test/access/manager/AccessManaged.test.js @@ -32,7 +32,7 @@ describe('AccessManaged', function () { }); it('sets authority and emits AuthorityUpdated event during construction', async function () { - await expect(await this.managed.deploymentTransaction()) + await expect(this.managed.deploymentTransaction()) .to.emit(this.managed, 'AuthorityUpdated') .withArgs(this.authority.target); }); diff --git a/test/helpers/enums.js b/test/helpers/enums.js index b75e73ba8..9a5d6b263 100644 --- a/test/helpers/enums.js +++ b/test/helpers/enums.js @@ -14,6 +14,7 @@ function createExport(Enum) { VoteType: Enum('Against', 'For', 'Abstain'), Rounding: Enum('Floor', 'Ceil', 'Trunc', 'Expand'), OperationState: Enum('Unset', 'Waiting', 'Ready', 'Done'), + RevertType: Enum('None', 'RevertWithoutMessage', 'RevertWithMessage', 'RevertWithCustomError', 'Panic'), }; } diff --git a/test/token/ERC1155/ERC1155.behavior.js b/test/token/ERC1155/ERC1155.behavior.js index 9f76fae29..4c81ea9d1 100644 --- a/test/token/ERC1155/ERC1155.behavior.js +++ b/test/token/ERC1155/ERC1155.behavior.js @@ -1,897 +1,798 @@ -const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ethers } = require('hardhat'); const { expect } = require('chai'); -const { ZERO_ADDRESS } = constants; - +const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs'); +const { + bigint: { RevertType }, +} = require('../../helpers/enums'); const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); -const { expectRevertCustomError } = require('../../helpers/customError'); -const { Enum } = require('../../helpers/enums'); -const ERC1155ReceiverMock = artifacts.require('ERC1155ReceiverMock'); -const RevertType = Enum('None', 'RevertWithoutMessage', 'RevertWithMessage', 'RevertWithCustomError', 'Panic'); +function shouldBehaveLikeERC1155() { + const firstTokenId = 1n; + const secondTokenId = 2n; + const unknownTokenId = 3n; -function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, multiTokenHolder, recipient, proxy]) { - const firstTokenId = new BN(1); - const secondTokenId = new BN(2); - const unknownTokenId = new BN(3); - - const firstTokenValue = new BN(1000); - const secondTokenValue = new BN(2000); + const firstTokenValue = 1000n; + const secondTokenValue = 2000n; const RECEIVER_SINGLE_MAGIC_VALUE = '0xf23a6e61'; const RECEIVER_BATCH_MAGIC_VALUE = '0xbc197c81'; + beforeEach(async function () { + [this.recipient, this.proxy, this.alice, this.bruce] = this.otherAccounts; + }); + describe('like an ERC1155', function () { describe('balanceOf', function () { it('should return 0 when queried about the zero address', async function () { - expect(await this.token.balanceOf(ZERO_ADDRESS, firstTokenId)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOf(ethers.ZeroAddress, firstTokenId)).to.equal(0n); }); - context("when accounts don't own tokens", function () { + describe("when accounts don't own tokens", function () { it('returns zero for given addresses', async function () { - expect(await this.token.balanceOf(firstTokenHolder, firstTokenId)).to.be.bignumber.equal('0'); - - expect(await this.token.balanceOf(secondTokenHolder, secondTokenId)).to.be.bignumber.equal('0'); - - expect(await this.token.balanceOf(firstTokenHolder, unknownTokenId)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOf(this.alice, firstTokenId)).to.equal(0n); + expect(await this.token.balanceOf(this.bruce, secondTokenId)).to.equal(0n); + expect(await this.token.balanceOf(this.alice, unknownTokenId)).to.equal(0n); }); }); - context('when accounts own some tokens', function () { + describe('when accounts own some tokens', function () { beforeEach(async function () { - await this.token.$_mint(firstTokenHolder, firstTokenId, firstTokenValue, '0x', { - from: minter, - }); - await this.token.$_mint(secondTokenHolder, secondTokenId, secondTokenValue, '0x', { - from: minter, - }); + await this.token.$_mint(this.alice, firstTokenId, firstTokenValue, '0x'); + await this.token.$_mint(this.bruce, secondTokenId, secondTokenValue, '0x'); }); it('returns the amount of tokens owned by the given addresses', async function () { - expect(await this.token.balanceOf(firstTokenHolder, firstTokenId)).to.be.bignumber.equal(firstTokenValue); - - expect(await this.token.balanceOf(secondTokenHolder, secondTokenId)).to.be.bignumber.equal(secondTokenValue); - - expect(await this.token.balanceOf(firstTokenHolder, unknownTokenId)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOf(this.alice, firstTokenId)).to.equal(firstTokenValue); + expect(await this.token.balanceOf(this.bruce, secondTokenId)).to.equal(secondTokenValue); + expect(await this.token.balanceOf(this.alice, unknownTokenId)).to.equal(0n); }); }); }); describe('balanceOfBatch', function () { it("reverts when input arrays don't match up", async function () { - const accounts1 = [firstTokenHolder, secondTokenHolder, firstTokenHolder, secondTokenHolder]; + const accounts1 = [this.alice, this.bruce, this.alice, this.bruce]; const ids1 = [firstTokenId, secondTokenId, unknownTokenId]; - await expectRevertCustomError(this.token.balanceOfBatch(accounts1, ids1), 'ERC1155InvalidArrayLength', [ - accounts1.length, - ids1.length, - ]); - const accounts2 = [firstTokenHolder, secondTokenHolder]; + await expect(this.token.balanceOfBatch(accounts1, ids1)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') + .withArgs(ids1.length, accounts1.length); + + const accounts2 = [this.alice, this.bruce]; const ids2 = [firstTokenId, secondTokenId, unknownTokenId]; - await expectRevertCustomError(this.token.balanceOfBatch(accounts2, ids2), 'ERC1155InvalidArrayLength', [ - accounts2.length, - ids2.length, - ]); + await expect(this.token.balanceOfBatch(accounts2, ids2)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') + .withArgs(ids2.length, accounts2.length); }); it('should return 0 as the balance when one of the addresses is the zero address', async function () { const result = await this.token.balanceOfBatch( - [firstTokenHolder, secondTokenHolder, ZERO_ADDRESS], + [this.alice, this.bruce, ethers.ZeroAddress], [firstTokenId, secondTokenId, unknownTokenId], ); - expect(result).to.be.an('array'); - expect(result[0]).to.be.a.bignumber.equal('0'); - expect(result[1]).to.be.a.bignumber.equal('0'); - expect(result[2]).to.be.a.bignumber.equal('0'); + expect(result).to.deep.equal([0n, 0n, 0n]); }); - context("when accounts don't own tokens", function () { + describe("when accounts don't own tokens", function () { it('returns zeros for each account', async function () { const result = await this.token.balanceOfBatch( - [firstTokenHolder, secondTokenHolder, firstTokenHolder], + [this.alice, this.bruce, this.alice], [firstTokenId, secondTokenId, unknownTokenId], ); - expect(result).to.be.an('array'); - expect(result[0]).to.be.a.bignumber.equal('0'); - expect(result[1]).to.be.a.bignumber.equal('0'); - expect(result[2]).to.be.a.bignumber.equal('0'); + expect(result).to.deep.equal([0n, 0n, 0n]); }); }); - context('when accounts own some tokens', function () { + describe('when accounts own some tokens', function () { beforeEach(async function () { - await this.token.$_mint(firstTokenHolder, firstTokenId, firstTokenValue, '0x', { - from: minter, - }); - await this.token.$_mint(secondTokenHolder, secondTokenId, secondTokenValue, '0x', { - from: minter, - }); + await this.token.$_mint(this.alice, firstTokenId, firstTokenValue, '0x'); + await this.token.$_mint(this.bruce, secondTokenId, secondTokenValue, '0x'); }); it('returns amounts owned by each account in order passed', async function () { const result = await this.token.balanceOfBatch( - [secondTokenHolder, firstTokenHolder, firstTokenHolder], + [this.bruce, this.alice, this.alice], [secondTokenId, firstTokenId, unknownTokenId], ); - expect(result).to.be.an('array'); - expect(result[0]).to.be.a.bignumber.equal(secondTokenValue); - expect(result[1]).to.be.a.bignumber.equal(firstTokenValue); - expect(result[2]).to.be.a.bignumber.equal('0'); + expect(result).to.deep.equal([secondTokenValue, firstTokenValue, 0n]); }); it('returns multiple times the balance of the same address when asked', async function () { const result = await this.token.balanceOfBatch( - [firstTokenHolder, secondTokenHolder, firstTokenHolder], + [this.alice, this.bruce, this.alice], [firstTokenId, secondTokenId, firstTokenId], ); - expect(result).to.be.an('array'); - expect(result[0]).to.be.a.bignumber.equal(result[2]); - expect(result[0]).to.be.a.bignumber.equal(firstTokenValue); - expect(result[1]).to.be.a.bignumber.equal(secondTokenValue); - expect(result[2]).to.be.a.bignumber.equal(firstTokenValue); + expect(result).to.deep.equal([firstTokenValue, secondTokenValue, firstTokenValue]); }); }); }); describe('setApprovalForAll', function () { - let receipt; beforeEach(async function () { - receipt = await this.token.setApprovalForAll(proxy, true, { from: multiTokenHolder }); + this.tx = await this.token.connect(this.holder).setApprovalForAll(this.proxy, true); }); it('sets approval status which can be queried via isApprovedForAll', async function () { - expect(await this.token.isApprovedForAll(multiTokenHolder, proxy)).to.be.equal(true); + expect(await this.token.isApprovedForAll(this.holder, this.proxy)).to.be.true; }); - it('emits an ApprovalForAll log', function () { - expectEvent(receipt, 'ApprovalForAll', { account: multiTokenHolder, operator: proxy, approved: true }); + it('emits an ApprovalForAll log', async function () { + await expect(this.tx) + .to.emit(this.token, 'ApprovalForAll') + .withArgs(this.holder.address, this.proxy.address, true); }); it('can unset approval for an operator', async function () { - await this.token.setApprovalForAll(proxy, false, { from: multiTokenHolder }); - expect(await this.token.isApprovedForAll(multiTokenHolder, proxy)).to.be.equal(false); + await this.token.connect(this.holder).setApprovalForAll(this.proxy, false); + expect(await this.token.isApprovedForAll(this.holder, this.proxy)).to.be.false; }); it('reverts if attempting to approve zero address as an operator', async function () { - await expectRevertCustomError( - this.token.setApprovalForAll(constants.ZERO_ADDRESS, true, { from: multiTokenHolder }), - 'ERC1155InvalidOperator', - [constants.ZERO_ADDRESS], - ); + await expect(this.token.connect(this.holder).setApprovalForAll(ethers.ZeroAddress, true)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidOperator') + .withArgs(ethers.ZeroAddress); }); }); describe('safeTransferFrom', function () { beforeEach(async function () { - await this.token.$_mint(multiTokenHolder, firstTokenId, firstTokenValue, '0x', { - from: minter, - }); - await this.token.$_mint(multiTokenHolder, secondTokenId, secondTokenValue, '0x', { - from: minter, - }); + await this.token.$_mint(this.holder, firstTokenId, firstTokenValue, '0x'); + await this.token.$_mint(this.holder, secondTokenId, secondTokenValue, '0x'); }); it('reverts when transferring more than balance', async function () { - await expectRevertCustomError( - this.token.safeTransferFrom(multiTokenHolder, recipient, firstTokenId, firstTokenValue.addn(1), '0x', { - from: multiTokenHolder, - }), - 'ERC1155InsufficientBalance', - [multiTokenHolder, firstTokenValue, firstTokenValue.addn(1), firstTokenId], - ); + await expect( + this.token + .connect(this.holder) + .safeTransferFrom(this.holder, this.recipient, firstTokenId, firstTokenValue + 1n, '0x'), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance') + .withArgs(this.holder.address, firstTokenValue, firstTokenValue + 1n, firstTokenId); }); it('reverts when transferring to zero address', async function () { - await expectRevertCustomError( - this.token.safeTransferFrom(multiTokenHolder, ZERO_ADDRESS, firstTokenId, firstTokenValue, '0x', { - from: multiTokenHolder, - }), - 'ERC1155InvalidReceiver', - [ZERO_ADDRESS], - ); + await expect( + this.token + .connect(this.holder) + .safeTransferFrom(this.holder, ethers.ZeroAddress, firstTokenId, firstTokenValue, '0x'), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(ethers.ZeroAddress); }); - function transferWasSuccessful({ operator, from, id, value }) { + function transferWasSuccessful() { it('debits transferred balance from sender', async function () { - const newBalance = await this.token.balanceOf(from, id); - expect(newBalance).to.be.a.bignumber.equal('0'); + expect(await this.token.balanceOf(this.args.from, this.args.id)).to.equal(0n); }); it('credits transferred balance to receiver', async function () { - const newBalance = await this.token.balanceOf(this.toWhom, id); - expect(newBalance).to.be.a.bignumber.equal(value); + expect(await this.token.balanceOf(this.args.to, this.args.id)).to.equal(this.args.value); }); - it('emits a TransferSingle log', function () { - expectEvent(this.transferLogs, 'TransferSingle', { - operator, - from, - to: this.toWhom, - id, - value, - }); + it('emits a TransferSingle log', async function () { + await expect(this.tx) + .to.emit(this.token, 'TransferSingle') + .withArgs( + this.args.operator.address ?? this.args.operator.target ?? this.args.operator, + this.args.from.address ?? this.args.from.target ?? this.args.from, + this.args.to.address ?? this.args.to.target ?? this.args.to, + this.args.id, + this.args.value, + ); }); } - context('when called by the multiTokenHolder', async function () { + describe('when called by the holder', async function () { beforeEach(async function () { - this.toWhom = recipient; - this.transferLogs = await this.token.safeTransferFrom( - multiTokenHolder, - recipient, - firstTokenId, - firstTokenValue, - '0x', - { - from: multiTokenHolder, - }, - ); + this.args = { + operator: this.holder, + from: this.holder, + to: this.recipient, + id: firstTokenId, + value: firstTokenValue, + data: '0x', + }; + this.tx = await this.token + .connect(this.args.operator) + .safeTransferFrom(this.args.from, this.args.to, this.args.id, this.args.value, this.args.data); }); - transferWasSuccessful.call(this, { - operator: multiTokenHolder, - from: multiTokenHolder, - id: firstTokenId, - value: firstTokenValue, - }); + transferWasSuccessful(); - it('preserves existing balances which are not transferred by multiTokenHolder', async function () { - const balance1 = await this.token.balanceOf(multiTokenHolder, secondTokenId); - expect(balance1).to.be.a.bignumber.equal(secondTokenValue); - - const balance2 = await this.token.balanceOf(recipient, secondTokenId); - expect(balance2).to.be.a.bignumber.equal('0'); + it('preserves existing balances which are not transferred by holder', async function () { + expect(await this.token.balanceOf(this.holder, secondTokenId)).to.equal(secondTokenValue); + expect(await this.token.balanceOf(this.recipient, secondTokenId)).to.equal(0n); }); }); - context('when called by an operator on behalf of the multiTokenHolder', function () { - context('when operator is not approved by multiTokenHolder', function () { + describe('when called by an operator on behalf of the holder', function () { + describe('when operator is not approved by holder', function () { beforeEach(async function () { - await this.token.setApprovalForAll(proxy, false, { from: multiTokenHolder }); + await this.token.connect(this.holder).setApprovalForAll(this.proxy, false); }); it('reverts', async function () { - await expectRevertCustomError( - this.token.safeTransferFrom(multiTokenHolder, recipient, firstTokenId, firstTokenValue, '0x', { - from: proxy, - }), - 'ERC1155MissingApprovalForAll', - [proxy, multiTokenHolder], - ); + await expect( + this.token + .connect(this.proxy) + .safeTransferFrom(this.holder, this.recipient, firstTokenId, firstTokenValue, '0x'), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155MissingApprovalForAll') + .withArgs(this.proxy.address, this.holder.address); }); }); - context('when operator is approved by multiTokenHolder', function () { + describe('when operator is approved by holder', function () { beforeEach(async function () { - this.toWhom = recipient; - await this.token.setApprovalForAll(proxy, true, { from: multiTokenHolder }); - this.transferLogs = await this.token.safeTransferFrom( - multiTokenHolder, - recipient, - firstTokenId, - firstTokenValue, - '0x', - { - from: proxy, - }, - ); + await this.token.connect(this.holder).setApprovalForAll(this.proxy, true); + + this.args = { + operator: this.proxy, + from: this.holder, + to: this.recipient, + id: firstTokenId, + value: firstTokenValue, + data: '0x', + }; + this.tx = await this.token + .connect(this.args.operator) + .safeTransferFrom(this.args.from, this.args.to, this.args.id, this.args.value, this.args.data); }); - transferWasSuccessful.call(this, { - operator: proxy, - from: multiTokenHolder, - id: firstTokenId, - value: firstTokenValue, - }); + transferWasSuccessful(); it("preserves operator's balances not involved in the transfer", async function () { - const balance1 = await this.token.balanceOf(proxy, firstTokenId); - expect(balance1).to.be.a.bignumber.equal('0'); - - const balance2 = await this.token.balanceOf(proxy, secondTokenId); - expect(balance2).to.be.a.bignumber.equal('0'); + expect(await this.token.balanceOf(this.proxy, firstTokenId)).to.equal(0n); + expect(await this.token.balanceOf(this.proxy, secondTokenId)).to.equal(0n); }); }); }); - context('when sending to a valid receiver', function () { + describe('when sending to a valid receiver', function () { beforeEach(async function () { - this.receiver = await ERC1155ReceiverMock.new( + this.receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ RECEIVER_SINGLE_MAGIC_VALUE, RECEIVER_BATCH_MAGIC_VALUE, RevertType.None, - ); + ]); }); - context('without data', function () { + describe('without data', function () { beforeEach(async function () { - this.toWhom = this.receiver.address; - this.transferReceipt = await this.token.safeTransferFrom( - multiTokenHolder, - this.receiver.address, - firstTokenId, - firstTokenValue, - '0x', - { from: multiTokenHolder }, - ); - this.transferLogs = this.transferReceipt; - }); - - transferWasSuccessful.call(this, { - operator: multiTokenHolder, - from: multiTokenHolder, - id: firstTokenId, - value: firstTokenValue, - }); - - it('calls onERC1155Received', async function () { - await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'Received', { - operator: multiTokenHolder, - from: multiTokenHolder, + this.args = { + operator: this.holder, + from: this.holder, + to: this.receiver, id: firstTokenId, value: firstTokenValue, - data: null, - }); + data: '0x', + }; + this.tx = await this.token + .connect(this.args.operator) + .safeTransferFrom(this.args.from, this.args.to, this.args.id, this.args.value, this.args.data); + }); + + transferWasSuccessful(); + + it('calls onERC1155Received', async function () { + await expect(this.tx) + .to.emit(this.receiver, 'Received') + .withArgs( + this.args.operator.address, + this.args.from.address, + this.args.id, + this.args.value, + this.args.data, + anyValue, + ); }); }); - context('with data', function () { - const data = '0xf00dd00d'; + describe('with data', function () { beforeEach(async function () { - this.toWhom = this.receiver.address; - this.transferReceipt = await this.token.safeTransferFrom( - multiTokenHolder, - this.receiver.address, - firstTokenId, - firstTokenValue, - data, - { from: multiTokenHolder }, - ); - this.transferLogs = this.transferReceipt; - }); - - transferWasSuccessful.call(this, { - operator: multiTokenHolder, - from: multiTokenHolder, - id: firstTokenId, - value: firstTokenValue, - }); - - it('calls onERC1155Received', async function () { - await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'Received', { - operator: multiTokenHolder, - from: multiTokenHolder, + this.args = { + operator: this.holder, + from: this.holder, + to: this.receiver, id: firstTokenId, value: firstTokenValue, - data, - }); + data: '0xf00dd00d', + }; + this.tx = await this.token + .connect(this.args.operator) + .safeTransferFrom(this.args.from, this.args.to, this.args.id, this.args.value, this.args.data); + }); + + transferWasSuccessful(); + + it('calls onERC1155Received', async function () { + await expect(this.tx) + .to.emit(this.receiver, 'Received') + .withArgs( + this.args.operator.address, + this.args.from.address, + this.args.id, + this.args.value, + this.args.data, + anyValue, + ); }); }); }); - context('to a receiver contract returning unexpected value', function () { - beforeEach(async function () { - this.receiver = await ERC1155ReceiverMock.new('0x00c0ffee', RECEIVER_BATCH_MAGIC_VALUE, RevertType.None); - }); - + describe('to a receiver contract returning unexpected value', function () { it('reverts', async function () { - await expectRevertCustomError( - this.token.safeTransferFrom(multiTokenHolder, this.receiver.address, firstTokenId, firstTokenValue, '0x', { - from: multiTokenHolder, - }), - 'ERC1155InvalidReceiver', - [this.receiver.address], - ); + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ + '0x00c0ffee', + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.None, + ]); + + await expect( + this.token + .connect(this.holder) + .safeTransferFrom(this.holder, receiver, firstTokenId, firstTokenValue, '0x'), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(receiver.target); }); }); - context('to a receiver contract that reverts', function () { - context('with a revert string', function () { - beforeEach(async function () { - this.receiver = await ERC1155ReceiverMock.new( + describe('to a receiver contract that reverts', function () { + describe('with a revert string', function () { + it('reverts', async function () { + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ RECEIVER_SINGLE_MAGIC_VALUE, RECEIVER_BATCH_MAGIC_VALUE, RevertType.RevertWithMessage, - ); - }); + ]); - it('reverts', async function () { - await expectRevert( - this.token.safeTransferFrom( - multiTokenHolder, - this.receiver.address, - firstTokenId, - firstTokenValue, - '0x', - { - from: multiTokenHolder, - }, - ), - 'ERC1155ReceiverMock: reverting on receive', - ); + await expect( + this.token + .connect(this.holder) + .safeTransferFrom(this.holder, receiver, firstTokenId, firstTokenValue, '0x'), + ).to.be.revertedWith('ERC1155ReceiverMock: reverting on receive'); }); }); - context('without a revert string', function () { - beforeEach(async function () { - this.receiver = await ERC1155ReceiverMock.new( + describe('without a revert string', function () { + it('reverts', async function () { + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ RECEIVER_SINGLE_MAGIC_VALUE, RECEIVER_BATCH_MAGIC_VALUE, RevertType.RevertWithoutMessage, - ); - }); + ]); - it('reverts', async function () { - await expectRevertCustomError( - this.token.safeTransferFrom( - multiTokenHolder, - this.receiver.address, - firstTokenId, - firstTokenValue, - '0x', - { - from: multiTokenHolder, - }, - ), - 'ERC1155InvalidReceiver', - [this.receiver.address], - ); + await expect( + this.token + .connect(this.holder) + .safeTransferFrom(this.holder, receiver, firstTokenId, firstTokenValue, '0x'), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(receiver.target); }); }); - context('with a custom error', function () { - beforeEach(async function () { - this.receiver = await ERC1155ReceiverMock.new( + describe('with a custom error', function () { + it('reverts', async function () { + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ RECEIVER_SINGLE_MAGIC_VALUE, RECEIVER_BATCH_MAGIC_VALUE, RevertType.RevertWithCustomError, - ); - }); + ]); - it('reverts', async function () { - await expectRevertCustomError( - this.token.safeTransferFrom( - multiTokenHolder, - this.receiver.address, - firstTokenId, - firstTokenValue, - '0x', - { - from: multiTokenHolder, - }, - ), - 'CustomError', - [RECEIVER_SINGLE_MAGIC_VALUE], - ); + await expect( + this.token + .connect(this.holder) + .safeTransferFrom(this.holder, receiver, firstTokenId, firstTokenValue, '0x'), + ) + .to.be.revertedWithCustomError(receiver, 'CustomError') + .withArgs(RECEIVER_SINGLE_MAGIC_VALUE); }); }); - context('with a panic', function () { - beforeEach(async function () { - this.receiver = await ERC1155ReceiverMock.new( + describe('with a panic', function () { + it('reverts', async function () { + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ RECEIVER_SINGLE_MAGIC_VALUE, RECEIVER_BATCH_MAGIC_VALUE, RevertType.Panic, - ); - }); + ]); - it('reverts', async function () { - await expectRevert.unspecified( - this.token.safeTransferFrom( - multiTokenHolder, - this.receiver.address, - firstTokenId, - firstTokenValue, - '0x', - { - from: multiTokenHolder, - }, - ), - ); + await expect( + this.token + .connect(this.holder) + .safeTransferFrom(this.holder, receiver, firstTokenId, firstTokenValue, '0x'), + ).to.be.revertedWithPanic(); }); }); }); - context('to a contract that does not implement the required function', function () { + describe('to a contract that does not implement the required function', function () { it('reverts', async function () { - const invalidReceiver = this.token; - await expectRevert.unspecified( - this.token.safeTransferFrom( - multiTokenHolder, - invalidReceiver.address, - firstTokenId, - firstTokenValue, - '0x', - { - from: multiTokenHolder, - }, - ), - ); + const invalidReceiver = this.token.target; + + await expect( + this.token + .connect(this.holder) + .safeTransferFrom(this.holder, invalidReceiver, firstTokenId, firstTokenValue, '0x'), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(invalidReceiver); }); }); }); describe('safeBatchTransferFrom', function () { beforeEach(async function () { - await this.token.$_mint(multiTokenHolder, firstTokenId, firstTokenValue, '0x', { - from: minter, - }); - await this.token.$_mint(multiTokenHolder, secondTokenId, secondTokenValue, '0x', { - from: minter, - }); + await this.token.$_mint(this.holder, firstTokenId, firstTokenValue, '0x'); + await this.token.$_mint(this.holder, secondTokenId, secondTokenValue, '0x'); }); it('reverts when transferring value more than any of balances', async function () { - await expectRevertCustomError( - this.token.safeBatchTransferFrom( - multiTokenHolder, - recipient, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue.addn(1)], - '0x', - { from: multiTokenHolder }, - ), - 'ERC1155InsufficientBalance', - [multiTokenHolder, secondTokenValue, secondTokenValue.addn(1), secondTokenId], - ); + await expect( + this.token + .connect(this.holder) + .safeBatchTransferFrom( + this.holder, + this.recipient, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue + 1n], + '0x', + ), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance') + .withArgs(this.holder.address, secondTokenValue, secondTokenValue + 1n, secondTokenId); }); it("reverts when ids array length doesn't match values array length", async function () { const ids1 = [firstTokenId]; const tokenValues1 = [firstTokenValue, secondTokenValue]; - await expectRevertCustomError( - this.token.safeBatchTransferFrom(multiTokenHolder, recipient, ids1, tokenValues1, '0x', { - from: multiTokenHolder, - }), - 'ERC1155InvalidArrayLength', - [ids1.length, tokenValues1.length], - ); + await expect( + this.token.connect(this.holder).safeBatchTransferFrom(this.holder, this.recipient, ids1, tokenValues1, '0x'), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') + .withArgs(ids1.length, tokenValues1.length); const ids2 = [firstTokenId, secondTokenId]; const tokenValues2 = [firstTokenValue]; - await expectRevertCustomError( - this.token.safeBatchTransferFrom(multiTokenHolder, recipient, ids2, tokenValues2, '0x', { - from: multiTokenHolder, - }), - 'ERC1155InvalidArrayLength', - [ids2.length, tokenValues2.length], - ); + + await expect( + this.token.connect(this.holder).safeBatchTransferFrom(this.holder, this.recipient, ids2, tokenValues2, '0x'), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') + .withArgs(ids2.length, tokenValues2.length); }); it('reverts when transferring to zero address', async function () { - await expectRevertCustomError( - this.token.safeBatchTransferFrom( - multiTokenHolder, - ZERO_ADDRESS, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - { from: multiTokenHolder }, - ), - 'ERC1155InvalidReceiver', - [ZERO_ADDRESS], - ); + await expect( + this.token + .connect(this.holder) + .safeBatchTransferFrom( + this.holder, + ethers.ZeroAddress, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(ethers.ZeroAddress); }); it('reverts when transferring from zero address', async function () { - await expectRevertCustomError( - this.token.$_safeBatchTransferFrom(ZERO_ADDRESS, multiTokenHolder, [firstTokenId], [firstTokenValue], '0x'), - 'ERC1155InvalidSender', - [ZERO_ADDRESS], - ); + await expect( + this.token.$_safeBatchTransferFrom(ethers.ZeroAddress, this.holder, [firstTokenId], [firstTokenValue], '0x'), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidSender') + .withArgs(ethers.ZeroAddress); }); - function batchTransferWasSuccessful({ operator, from, ids, values }) { + function batchTransferWasSuccessful() { it('debits transferred balances from sender', async function () { - const newBalances = await this.token.balanceOfBatch(new Array(ids.length).fill(from), ids); - for (const newBalance of newBalances) { - expect(newBalance).to.be.a.bignumber.equal('0'); - } + const newBalances = await this.token.balanceOfBatch( + this.args.ids.map(() => this.args.from), + this.args.ids, + ); + expect(newBalances).to.deep.equal(this.args.ids.map(() => 0n)); }); it('credits transferred balances to receiver', async function () { - const newBalances = await this.token.balanceOfBatch(new Array(ids.length).fill(this.toWhom), ids); - for (let i = 0; i < newBalances.length; i++) { - expect(newBalances[i]).to.be.a.bignumber.equal(values[i]); - } + const newBalances = await this.token.balanceOfBatch( + this.args.ids.map(() => this.args.to), + this.args.ids, + ); + expect(newBalances).to.deep.equal(this.args.values); }); - it('emits a TransferBatch log', function () { - expectEvent(this.transferLogs, 'TransferBatch', { - operator, - from, - to: this.toWhom, - // ids, - // values, - }); + it('emits a TransferBatch log', async function () { + await expect(this.tx) + .to.emit(this.token, 'TransferBatch') + .withArgs( + this.args.operator.address ?? this.args.operator.target ?? this.args.operator, + this.args.from.address ?? this.args.from.target ?? this.args.from, + this.args.to.address ?? this.args.to.target ?? this.args.to, + this.args.ids, + this.args.values, + ); }); } - context('when called by the multiTokenHolder', async function () { + describe('when called by the holder', async function () { beforeEach(async function () { - this.toWhom = recipient; - this.transferLogs = await this.token.safeBatchTransferFrom( - multiTokenHolder, - recipient, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - { from: multiTokenHolder }, - ); + this.args = { + operator: this.holder, + from: this.holder, + to: this.recipient, + ids: [firstTokenId, secondTokenId], + values: [firstTokenValue, secondTokenValue], + data: '0x', + }; + this.tx = await this.token + .connect(this.args.operator) + .safeBatchTransferFrom(this.args.from, this.args.to, this.args.ids, this.args.values, this.args.data); }); - batchTransferWasSuccessful.call(this, { - operator: multiTokenHolder, - from: multiTokenHolder, - ids: [firstTokenId, secondTokenId], - values: [firstTokenValue, secondTokenValue], - }); + batchTransferWasSuccessful(); }); - context('when called by an operator on behalf of the multiTokenHolder', function () { - context('when operator is not approved by multiTokenHolder', function () { + describe('when called by an operator on behalf of the holder', function () { + describe('when operator is not approved by holder', function () { beforeEach(async function () { - await this.token.setApprovalForAll(proxy, false, { from: multiTokenHolder }); + await this.token.connect(this.holder).setApprovalForAll(this.proxy, false); }); it('reverts', async function () { - await expectRevertCustomError( - this.token.safeBatchTransferFrom( - multiTokenHolder, - recipient, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - { from: proxy }, - ), - 'ERC1155MissingApprovalForAll', - [proxy, multiTokenHolder], - ); + await expect( + this.token + .connect(this.proxy) + .safeBatchTransferFrom( + this.holder, + this.recipient, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155MissingApprovalForAll') + .withArgs(this.proxy.address, this.holder.address); }); }); - context('when operator is approved by multiTokenHolder', function () { + describe('when operator is approved by holder', function () { beforeEach(async function () { - this.toWhom = recipient; - await this.token.setApprovalForAll(proxy, true, { from: multiTokenHolder }); - this.transferLogs = await this.token.safeBatchTransferFrom( - multiTokenHolder, - recipient, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - { from: proxy }, - ); + await this.token.connect(this.holder).setApprovalForAll(this.proxy, true); + + this.args = { + operator: this.proxy, + from: this.holder, + to: this.recipient, + ids: [firstTokenId, secondTokenId], + values: [firstTokenValue, secondTokenValue], + data: '0x', + }; + this.tx = await this.token + .connect(this.args.operator) + .safeBatchTransferFrom(this.args.from, this.args.to, this.args.ids, this.args.values, this.args.data); }); - batchTransferWasSuccessful.call(this, { - operator: proxy, - from: multiTokenHolder, - ids: [firstTokenId, secondTokenId], - values: [firstTokenValue, secondTokenValue], - }); + batchTransferWasSuccessful(); it("preserves operator's balances not involved in the transfer", async function () { - const balance1 = await this.token.balanceOf(proxy, firstTokenId); - expect(balance1).to.be.a.bignumber.equal('0'); - const balance2 = await this.token.balanceOf(proxy, secondTokenId); - expect(balance2).to.be.a.bignumber.equal('0'); + expect(await this.token.balanceOf(this.proxy, firstTokenId)).to.equal(0n); + expect(await this.token.balanceOf(this.proxy, secondTokenId)).to.equal(0n); }); }); }); - context('when sending to a valid receiver', function () { + describe('when sending to a valid receiver', function () { beforeEach(async function () { - this.receiver = await ERC1155ReceiverMock.new( + this.receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ RECEIVER_SINGLE_MAGIC_VALUE, RECEIVER_BATCH_MAGIC_VALUE, RevertType.None, - ); + ]); }); - context('without data', function () { + describe('without data', function () { beforeEach(async function () { - this.toWhom = this.receiver.address; - this.transferReceipt = await this.token.safeBatchTransferFrom( - multiTokenHolder, - this.receiver.address, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - { from: multiTokenHolder }, - ); - this.transferLogs = this.transferReceipt; + this.args = { + operator: this.holder, + from: this.holder, + to: this.receiver, + ids: [firstTokenId, secondTokenId], + values: [firstTokenValue, secondTokenValue], + data: '0x', + }; + this.tx = await this.token + .connect(this.args.operator) + .safeBatchTransferFrom(this.args.from, this.args.to, this.args.ids, this.args.values, this.args.data); }); - batchTransferWasSuccessful.call(this, { - operator: multiTokenHolder, - from: multiTokenHolder, - ids: [firstTokenId, secondTokenId], - values: [firstTokenValue, secondTokenValue], - }); + batchTransferWasSuccessful(); it('calls onERC1155BatchReceived', async function () { - await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'BatchReceived', { - operator: multiTokenHolder, - from: multiTokenHolder, - // ids: [firstTokenId, secondTokenId], - // values: [firstTokenValue, secondTokenValue], - data: null, - }); + await expect(this.tx) + .to.emit(this.receiver, 'BatchReceived') + .withArgs( + this.holder.address, + this.holder.address, + this.args.ids, + this.args.values, + this.args.data, + anyValue, + ); }); }); - context('with data', function () { - const data = '0xf00dd00d'; + describe('with data', function () { beforeEach(async function () { - this.toWhom = this.receiver.address; - this.transferReceipt = await this.token.safeBatchTransferFrom( - multiTokenHolder, - this.receiver.address, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - data, - { from: multiTokenHolder }, - ); - this.transferLogs = this.transferReceipt; + this.args = { + operator: this.holder, + from: this.holder, + to: this.receiver, + ids: [firstTokenId, secondTokenId], + values: [firstTokenValue, secondTokenValue], + data: '0xf00dd00d', + }; + this.tx = await this.token + .connect(this.args.operator) + .safeBatchTransferFrom(this.args.from, this.args.to, this.args.ids, this.args.values, this.args.data); }); - batchTransferWasSuccessful.call(this, { - operator: multiTokenHolder, - from: multiTokenHolder, - ids: [firstTokenId, secondTokenId], - values: [firstTokenValue, secondTokenValue], - }); + batchTransferWasSuccessful(); it('calls onERC1155Received', async function () { - await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'BatchReceived', { - operator: multiTokenHolder, - from: multiTokenHolder, - // ids: [firstTokenId, secondTokenId], - // values: [firstTokenValue, secondTokenValue], - data, - }); + await expect(this.tx) + .to.emit(this.receiver, 'BatchReceived') + .withArgs( + this.holder.address, + this.holder.address, + this.args.ids, + this.args.values, + this.args.data, + anyValue, + ); }); }); }); - context('to a receiver contract returning unexpected value', function () { - beforeEach(async function () { - this.receiver = await ERC1155ReceiverMock.new( + describe('to a receiver contract returning unexpected value', function () { + it('reverts', async function () { + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ RECEIVER_SINGLE_MAGIC_VALUE, RECEIVER_SINGLE_MAGIC_VALUE, RevertType.None, - ); - }); + ]); - it('reverts', async function () { - await expectRevertCustomError( - this.token.safeBatchTransferFrom( - multiTokenHolder, - this.receiver.address, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - { from: multiTokenHolder }, - ), - 'ERC1155InvalidReceiver', - [this.receiver.address], - ); + await expect( + this.token + .connect(this.holder) + .safeBatchTransferFrom( + this.holder, + receiver, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(receiver.target); }); }); - context('to a receiver contract that reverts', function () { - context('with a revert string', function () { - beforeEach(async function () { - this.receiver = await ERC1155ReceiverMock.new( + describe('to a receiver contract that reverts', function () { + describe('with a revert string', function () { + it('reverts', async function () { + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ RECEIVER_SINGLE_MAGIC_VALUE, RECEIVER_BATCH_MAGIC_VALUE, RevertType.RevertWithMessage, - ); - }); + ]); - it('reverts', async function () { - await expectRevert( - this.token.safeBatchTransferFrom( - multiTokenHolder, - this.receiver.address, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - { from: multiTokenHolder }, - ), - 'ERC1155ReceiverMock: reverting on batch receive', - ); + await expect( + this.token + .connect(this.holder) + .safeBatchTransferFrom( + this.holder, + receiver, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ).to.be.revertedWith('ERC1155ReceiverMock: reverting on batch receive'); }); }); - context('without a revert string', function () { - beforeEach(async function () { - this.receiver = await ERC1155ReceiverMock.new( + describe('without a revert string', function () { + it('reverts', async function () { + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ RECEIVER_SINGLE_MAGIC_VALUE, RECEIVER_BATCH_MAGIC_VALUE, RevertType.RevertWithoutMessage, - ); - }); + ]); - it('reverts', async function () { - await expectRevertCustomError( - this.token.safeBatchTransferFrom( - multiTokenHolder, - this.receiver.address, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - { from: multiTokenHolder }, - ), - 'ERC1155InvalidReceiver', - [this.receiver.address], - ); + await expect( + this.token + .connect(this.holder) + .safeBatchTransferFrom( + this.holder, + receiver, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(receiver.target); }); }); - context('with a custom error', function () { - beforeEach(async function () { - this.receiver = await ERC1155ReceiverMock.new( + describe('with a custom error', function () { + it('reverts', async function () { + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ RECEIVER_SINGLE_MAGIC_VALUE, RECEIVER_BATCH_MAGIC_VALUE, RevertType.RevertWithCustomError, - ); - }); + ]); - it('reverts', async function () { - await expectRevertCustomError( - this.token.safeBatchTransferFrom( - multiTokenHolder, - this.receiver.address, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - { from: multiTokenHolder }, - ), - 'CustomError', - [RECEIVER_SINGLE_MAGIC_VALUE], - ); + await expect( + this.token + .connect(this.holder) + .safeBatchTransferFrom( + this.holder, + receiver, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ) + .to.be.revertedWithCustomError(receiver, 'CustomError') + .withArgs(RECEIVER_SINGLE_MAGIC_VALUE); }); }); - context('with a panic', function () { - beforeEach(async function () { - this.receiver = await ERC1155ReceiverMock.new( + describe('with a panic', function () { + it('reverts', async function () { + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ RECEIVER_SINGLE_MAGIC_VALUE, RECEIVER_BATCH_MAGIC_VALUE, RevertType.Panic, - ); - }); + ]); - it('reverts', async function () { - await expectRevert.unspecified( - this.token.safeBatchTransferFrom( - multiTokenHolder, - this.receiver.address, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - { from: multiTokenHolder }, - ), - ); + await expect( + this.token + .connect(this.holder) + .safeBatchTransferFrom( + this.holder, + receiver, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ).to.be.revertedWithPanic(); }); }); }); - context('to a contract that does not implement the required function', function () { + describe('to a contract that does not implement the required function', function () { it('reverts', async function () { - const invalidReceiver = this.token; - await expectRevert.unspecified( - this.token.safeBatchTransferFrom( - multiTokenHolder, - invalidReceiver.address, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - { from: multiTokenHolder }, - ), - ); + const invalidReceiver = this.token.target; + + await expect( + this.token + .connect(this.holder) + .safeBatchTransferFrom( + this.holder, + invalidReceiver, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(invalidReceiver); }); }); }); diff --git a/test/token/ERC1155/ERC1155.test.js b/test/token/ERC1155/ERC1155.test.js index 58d747a4b..c469dd845 100644 --- a/test/token/ERC1155/ERC1155.test.js +++ b/test/token/ERC1155/ERC1155.test.js @@ -1,251 +1,212 @@ -const { BN, constants, expectEvent } = require('@openzeppelin/test-helpers'); -const { ZERO_ADDRESS } = constants; - +const { ethers } = require('hardhat'); const { expect } = require('chai'); - -const { expectRevertCustomError } = require('../../helpers/customError'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { zip } = require('../../helpers/iterate'); const { shouldBehaveLikeERC1155 } = require('./ERC1155.behavior'); -const ERC1155Mock = artifacts.require('$ERC1155'); -contract('ERC1155', function (accounts) { - const [operator, tokenHolder, tokenBatchHolder, ...otherAccounts] = accounts; +const initialURI = 'https://token-cdn-domain/{id}.json'; - const initialURI = 'https://token-cdn-domain/{id}.json'; +async function fixture() { + const [operator, holder, ...otherAccounts] = await ethers.getSigners(); + const token = await ethers.deployContract('$ERC1155', [initialURI]); + return { token, operator, holder, otherAccounts }; +} +describe('ERC1155', function () { beforeEach(async function () { - this.token = await ERC1155Mock.new(initialURI); + Object.assign(this, await loadFixture(fixture)); }); - shouldBehaveLikeERC1155(otherAccounts); + shouldBehaveLikeERC1155(); describe('internal functions', function () { - const tokenId = new BN(1990); - const mintValue = new BN(9001); - const burnValue = new BN(3000); + const tokenId = 1990n; + const mintValue = 9001n; + const burnValue = 3000n; - const tokenBatchIds = [new BN(2000), new BN(2010), new BN(2020)]; - const mintValues = [new BN(5000), new BN(10000), new BN(42195)]; - const burnValues = [new BN(5000), new BN(9001), new BN(195)]; + const tokenBatchIds = [2000n, 2010n, 2020n]; + const mintValues = [5000n, 10000n, 42195n]; + const burnValues = [5000n, 9001n, 195n]; const data = '0x12345678'; describe('_mint', function () { it('reverts with a zero destination address', async function () { - await expectRevertCustomError( - this.token.$_mint(ZERO_ADDRESS, tokenId, mintValue, data), - 'ERC1155InvalidReceiver', - [ZERO_ADDRESS], - ); + await expect(this.token.$_mint(ethers.ZeroAddress, tokenId, mintValue, data)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(ethers.ZeroAddress); }); - context('with minted tokens', function () { + describe('with minted tokens', function () { beforeEach(async function () { - this.receipt = await this.token.$_mint(tokenHolder, tokenId, mintValue, data, { from: operator }); + this.tx = await this.token.connect(this.operator).$_mint(this.holder, tokenId, mintValue, data); }); - it('emits a TransferSingle event', function () { - expectEvent(this.receipt, 'TransferSingle', { - operator, - from: ZERO_ADDRESS, - to: tokenHolder, - id: tokenId, - value: mintValue, - }); + it('emits a TransferSingle event', async function () { + await expect(this.tx) + .to.emit(this.token, 'TransferSingle') + .withArgs(this.operator.address, ethers.ZeroAddress, this.holder.address, tokenId, mintValue); }); it('credits the minted token value', async function () { - expect(await this.token.balanceOf(tokenHolder, tokenId)).to.be.bignumber.equal(mintValue); + expect(await this.token.balanceOf(this.holder, tokenId)).to.equal(mintValue); }); }); }); describe('_mintBatch', function () { it('reverts with a zero destination address', async function () { - await expectRevertCustomError( - this.token.$_mintBatch(ZERO_ADDRESS, tokenBatchIds, mintValues, data), - 'ERC1155InvalidReceiver', - [ZERO_ADDRESS], - ); + await expect(this.token.$_mintBatch(ethers.ZeroAddress, tokenBatchIds, mintValues, data)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(ethers.ZeroAddress); }); it('reverts if length of inputs do not match', async function () { - await expectRevertCustomError( - this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintValues.slice(1), data), - 'ERC1155InvalidArrayLength', - [tokenBatchIds.length, mintValues.length - 1], - ); + await expect(this.token.$_mintBatch(this.holder, tokenBatchIds, mintValues.slice(1), data)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') + .withArgs(tokenBatchIds.length, mintValues.length - 1); - await expectRevertCustomError( - this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds.slice(1), mintValues, data), - 'ERC1155InvalidArrayLength', - [tokenBatchIds.length - 1, mintValues.length], - ); + await expect(this.token.$_mintBatch(this.holder, tokenBatchIds.slice(1), mintValues, data)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') + .withArgs(tokenBatchIds.length - 1, mintValues.length); }); - context('with minted batch of tokens', function () { + describe('with minted batch of tokens', function () { beforeEach(async function () { - this.receipt = await this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintValues, data, { - from: operator, - }); + this.tx = await this.token.connect(this.operator).$_mintBatch(this.holder, tokenBatchIds, mintValues, data); }); - it('emits a TransferBatch event', function () { - expectEvent(this.receipt, 'TransferBatch', { - operator, - from: ZERO_ADDRESS, - to: tokenBatchHolder, - }); + it('emits a TransferBatch event', async function () { + await expect(this.tx) + .to.emit(this.token, 'TransferBatch') + .withArgs(this.operator.address, ethers.ZeroAddress, this.holder.address, tokenBatchIds, mintValues); }); it('credits the minted batch of tokens', async function () { const holderBatchBalances = await this.token.balanceOfBatch( - new Array(tokenBatchIds.length).fill(tokenBatchHolder), + tokenBatchIds.map(() => this.holder), tokenBatchIds, ); - for (let i = 0; i < holderBatchBalances.length; i++) { - expect(holderBatchBalances[i]).to.be.bignumber.equal(mintValues[i]); - } + expect(holderBatchBalances).to.deep.equal(mintValues); }); }); }); describe('_burn', function () { it("reverts when burning the zero account's tokens", async function () { - await expectRevertCustomError(this.token.$_burn(ZERO_ADDRESS, tokenId, mintValue), 'ERC1155InvalidSender', [ - ZERO_ADDRESS, - ]); + await expect(this.token.$_burn(ethers.ZeroAddress, tokenId, mintValue)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidSender') + .withArgs(ethers.ZeroAddress); }); it('reverts when burning a non-existent token id', async function () { - await expectRevertCustomError( - this.token.$_burn(tokenHolder, tokenId, mintValue), - 'ERC1155InsufficientBalance', - [tokenHolder, 0, mintValue, tokenId], - ); + await expect(this.token.$_burn(this.holder, tokenId, mintValue)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance') + .withArgs(this.holder.address, 0, mintValue, tokenId); }); it('reverts when burning more than available tokens', async function () { - await this.token.$_mint(tokenHolder, tokenId, mintValue, data, { from: operator }); + await this.token.connect(this.operator).$_mint(this.holder, tokenId, mintValue, data); - await expectRevertCustomError( - this.token.$_burn(tokenHolder, tokenId, mintValue.addn(1)), - 'ERC1155InsufficientBalance', - [tokenHolder, mintValue, mintValue.addn(1), tokenId], - ); + await expect(this.token.$_burn(this.holder, tokenId, mintValue + 1n)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance') + .withArgs(this.holder.address, mintValue, mintValue + 1n, tokenId); }); - context('with minted-then-burnt tokens', function () { + describe('with minted-then-burnt tokens', function () { beforeEach(async function () { - await this.token.$_mint(tokenHolder, tokenId, mintValue, data); - this.receipt = await this.token.$_burn(tokenHolder, tokenId, burnValue, { from: operator }); + await this.token.$_mint(this.holder, tokenId, mintValue, data); + this.tx = await this.token.connect(this.operator).$_burn(this.holder, tokenId, burnValue); }); - it('emits a TransferSingle event', function () { - expectEvent(this.receipt, 'TransferSingle', { - operator, - from: tokenHolder, - to: ZERO_ADDRESS, - id: tokenId, - value: burnValue, - }); + it('emits a TransferSingle event', async function () { + await expect(this.tx) + .to.emit(this.token, 'TransferSingle') + .withArgs(this.operator.address, this.holder.address, ethers.ZeroAddress, tokenId, burnValue); }); it('accounts for both minting and burning', async function () { - expect(await this.token.balanceOf(tokenHolder, tokenId)).to.be.bignumber.equal(mintValue.sub(burnValue)); + expect(await this.token.balanceOf(this.holder, tokenId)).to.equal(mintValue - burnValue); }); }); }); describe('_burnBatch', function () { it("reverts when burning the zero account's tokens", async function () { - await expectRevertCustomError( - this.token.$_burnBatch(ZERO_ADDRESS, tokenBatchIds, burnValues), - 'ERC1155InvalidSender', - [ZERO_ADDRESS], - ); + await expect(this.token.$_burnBatch(ethers.ZeroAddress, tokenBatchIds, burnValues)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidSender') + .withArgs(ethers.ZeroAddress); }); it('reverts if length of inputs do not match', async function () { - await expectRevertCustomError( - this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnValues.slice(1)), - 'ERC1155InvalidArrayLength', - [tokenBatchIds.length, burnValues.length - 1], - ); + await expect(this.token.$_burnBatch(this.holder, tokenBatchIds, burnValues.slice(1))) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') + .withArgs(tokenBatchIds.length, burnValues.length - 1); - await expectRevertCustomError( - this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds.slice(1), burnValues), - 'ERC1155InvalidArrayLength', - [tokenBatchIds.length - 1, burnValues.length], - ); + await expect(this.token.$_burnBatch(this.holder, tokenBatchIds.slice(1), burnValues)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') + .withArgs(tokenBatchIds.length - 1, burnValues.length); }); it('reverts when burning a non-existent token id', async function () { - await expectRevertCustomError( - this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnValues), - 'ERC1155InsufficientBalance', - [tokenBatchHolder, 0, tokenBatchIds[0], burnValues[0]], - ); + await expect(this.token.$_burnBatch(this.holder, tokenBatchIds, burnValues)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance') + .withArgs(this.holder.address, 0, burnValues[0], tokenBatchIds[0]); }); - context('with minted-then-burnt tokens', function () { + describe('with minted-then-burnt tokens', function () { beforeEach(async function () { - await this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintValues, data); - this.receipt = await this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnValues, { from: operator }); + await this.token.$_mintBatch(this.holder, tokenBatchIds, mintValues, data); + this.tx = await this.token.connect(this.operator).$_burnBatch(this.holder, tokenBatchIds, burnValues); }); - it('emits a TransferBatch event', function () { - expectEvent(this.receipt, 'TransferBatch', { - operator, - from: tokenBatchHolder, - to: ZERO_ADDRESS, - // ids: tokenBatchIds, - // values: burnValues, - }); + it('emits a TransferBatch event', async function () { + await expect(this.tx) + .to.emit(this.token, 'TransferBatch') + .withArgs(this.operator.address, this.holder.address, ethers.ZeroAddress, tokenBatchIds, burnValues); }); it('accounts for both minting and burning', async function () { const holderBatchBalances = await this.token.balanceOfBatch( - new Array(tokenBatchIds.length).fill(tokenBatchHolder), + tokenBatchIds.map(() => this.holder), tokenBatchIds, ); - for (let i = 0; i < holderBatchBalances.length; i++) { - expect(holderBatchBalances[i]).to.be.bignumber.equal(mintValues[i].sub(burnValues[i])); - } + expect(holderBatchBalances).to.deep.equal( + zip(mintValues, burnValues).map(([mintValue, burnValue]) => mintValue - burnValue), + ); }); }); }); }); describe('ERC1155MetadataURI', function () { - const firstTokenID = new BN('42'); - const secondTokenID = new BN('1337'); + const firstTokenID = 42n; + const secondTokenID = 1337n; it('emits no URI event in constructor', async function () { - await expectEvent.notEmitted.inConstruction(this.token, 'URI'); + await expect(this.token.deploymentTransaction()).to.not.emit(this.token, 'URI'); }); it('sets the initial URI for all token types', async function () { - expect(await this.token.uri(firstTokenID)).to.be.equal(initialURI); - expect(await this.token.uri(secondTokenID)).to.be.equal(initialURI); + expect(await this.token.uri(firstTokenID)).to.equal(initialURI); + expect(await this.token.uri(secondTokenID)).to.equal(initialURI); }); describe('_setURI', function () { const newURI = 'https://token-cdn-domain/{locale}/{id}.json'; it('emits no URI event', async function () { - const receipt = await this.token.$_setURI(newURI); - - expectEvent.notEmitted(receipt, 'URI'); + await expect(this.token.$_setURI(newURI)).to.not.emit(this.token, 'URI'); }); it('sets the new URI for all token types', async function () { await this.token.$_setURI(newURI); - expect(await this.token.uri(firstTokenID)).to.be.equal(newURI); - expect(await this.token.uri(secondTokenID)).to.be.equal(newURI); + expect(await this.token.uri(firstTokenID)).to.equal(newURI); + expect(await this.token.uri(secondTokenID)).to.equal(newURI); }); }); }); diff --git a/test/token/ERC1155/extensions/ERC1155Burnable.test.js b/test/token/ERC1155/extensions/ERC1155Burnable.test.js index fc94db052..6a75dc223 100644 --- a/test/token/ERC1155/extensions/ERC1155Burnable.test.js +++ b/test/token/ERC1155/extensions/ERC1155Burnable.test.js @@ -1,71 +1,66 @@ -const { BN } = require('@openzeppelin/test-helpers'); - +const { ethers } = require('hardhat'); const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { expectRevertCustomError } = require('../../../helpers/customError'); +const ids = [42n, 1137n]; +const values = [3000n, 9902n]; -const ERC1155Burnable = artifacts.require('$ERC1155Burnable'); +async function fixture() { + const [holder, operator, other] = await ethers.getSigners(); -contract('ERC1155Burnable', function (accounts) { - const [holder, operator, other] = accounts; + const token = await ethers.deployContract('$ERC1155Burnable', ['https://token-cdn-domain/{id}.json']); + await token.$_mint(holder, ids[0], values[0], '0x'); + await token.$_mint(holder, ids[1], values[1], '0x'); - const uri = 'https://token.com'; - - const tokenIds = [new BN('42'), new BN('1137')]; - const values = [new BN('3000'), new BN('9902')]; + return { token, holder, operator, other }; +} +describe('ERC1155Burnable', function () { beforeEach(async function () { - this.token = await ERC1155Burnable.new(uri); - - await this.token.$_mint(holder, tokenIds[0], values[0], '0x'); - await this.token.$_mint(holder, tokenIds[1], values[1], '0x'); + Object.assign(this, await loadFixture(fixture)); }); describe('burn', function () { it('holder can burn their tokens', async function () { - await this.token.burn(holder, tokenIds[0], values[0].subn(1), { from: holder }); + await this.token.connect(this.holder).burn(this.holder, ids[0], values[0] - 1n); - expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); + expect(await this.token.balanceOf(this.holder, ids[0])).to.equal(1n); }); it("approved operators can burn the holder's tokens", async function () { - await this.token.setApprovalForAll(operator, true, { from: holder }); - await this.token.burn(holder, tokenIds[0], values[0].subn(1), { from: operator }); + await this.token.connect(this.holder).setApprovalForAll(this.operator, true); + await this.token.connect(this.operator).burn(this.holder, ids[0], values[0] - 1n); - expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); + expect(await this.token.balanceOf(this.holder, ids[0])).to.equal(1n); }); it("unapproved accounts cannot burn the holder's tokens", async function () { - await expectRevertCustomError( - this.token.burn(holder, tokenIds[0], values[0].subn(1), { from: other }), - 'ERC1155MissingApprovalForAll', - [other, holder], - ); + await expect(this.token.connect(this.other).burn(this.holder, ids[0], values[0] - 1n)) + .to.be.revertedWithCustomError(this.token, 'ERC1155MissingApprovalForAll') + .withArgs(this.other.address, this.holder.address); }); }); describe('burnBatch', function () { it('holder can burn their tokens', async function () { - await this.token.burnBatch(holder, tokenIds, [values[0].subn(1), values[1].subn(2)], { from: holder }); + await this.token.connect(this.holder).burnBatch(this.holder, ids, [values[0] - 1n, values[1] - 2n]); - expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); - expect(await this.token.balanceOf(holder, tokenIds[1])).to.be.bignumber.equal('2'); + expect(await this.token.balanceOf(this.holder, ids[0])).to.equal(1n); + expect(await this.token.balanceOf(this.holder, ids[1])).to.equal(2n); }); it("approved operators can burn the holder's tokens", async function () { - await this.token.setApprovalForAll(operator, true, { from: holder }); - await this.token.burnBatch(holder, tokenIds, [values[0].subn(1), values[1].subn(2)], { from: operator }); + await this.token.connect(this.holder).setApprovalForAll(this.operator, true); + await this.token.connect(this.operator).burnBatch(this.holder, ids, [values[0] - 1n, values[1] - 2n]); - expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); - expect(await this.token.balanceOf(holder, tokenIds[1])).to.be.bignumber.equal('2'); + expect(await this.token.balanceOf(this.holder, ids[0])).to.equal(1n); + expect(await this.token.balanceOf(this.holder, ids[1])).to.equal(2n); }); it("unapproved accounts cannot burn the holder's tokens", async function () { - await expectRevertCustomError( - this.token.burnBatch(holder, tokenIds, [values[0].subn(1), values[1].subn(2)], { from: other }), - 'ERC1155MissingApprovalForAll', - [other, holder], - ); + await expect(this.token.connect(this.other).burnBatch(this.holder, ids, [values[0] - 1n, values[1] - 2n])) + .to.be.revertedWithCustomError(this.token, 'ERC1155MissingApprovalForAll') + .withArgs(this.other.address, this.holder.address); }); }); }); diff --git a/test/token/ERC1155/extensions/ERC1155Pausable.test.js b/test/token/ERC1155/extensions/ERC1155Pausable.test.js index 248ea5684..7038180bb 100644 --- a/test/token/ERC1155/extensions/ERC1155Pausable.test.js +++ b/test/token/ERC1155/extensions/ERC1155Pausable.test.js @@ -1,112 +1,104 @@ -const { BN } = require('@openzeppelin/test-helpers'); - +const { ethers } = require('hardhat'); const { expect } = require('chai'); -const { expectRevertCustomError } = require('../../../helpers/customError'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const ERC1155Pausable = artifacts.require('$ERC1155Pausable'); +async function fixture() { + const [holder, operator, receiver, other] = await ethers.getSigners(); + const token = await ethers.deployContract('$ERC1155Pausable', ['https://token-cdn-domain/{id}.json']); + return { token, holder, operator, receiver, other }; +} -contract('ERC1155Pausable', function (accounts) { - const [holder, operator, receiver, other] = accounts; - - const uri = 'https://token.com'; +contract('ERC1155Pausable', function () { + const firstTokenId = 37n; + const firstTokenValue = 42n; + const secondTokenId = 19842n; + const secondTokenValue = 23n; beforeEach(async function () { - this.token = await ERC1155Pausable.new(uri); + Object.assign(this, await loadFixture(fixture)); }); context('when token is paused', function () { - const firstTokenId = new BN('37'); - const firstTokenValue = new BN('42'); - - const secondTokenId = new BN('19842'); - const secondTokenValue = new BN('23'); - beforeEach(async function () { - await this.token.setApprovalForAll(operator, true, { from: holder }); - await this.token.$_mint(holder, firstTokenId, firstTokenValue, '0x'); - + await this.token.connect(this.holder).setApprovalForAll(this.operator, true); + await this.token.$_mint(this.holder, firstTokenId, firstTokenValue, '0x'); await this.token.$_pause(); }); it('reverts when trying to safeTransferFrom from holder', async function () { - await expectRevertCustomError( - this.token.safeTransferFrom(holder, receiver, firstTokenId, firstTokenValue, '0x', { from: holder }), - 'EnforcedPause', - [], - ); + await expect( + this.token + .connect(this.holder) + .safeTransferFrom(this.holder, this.receiver, firstTokenId, firstTokenValue, '0x'), + ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); }); it('reverts when trying to safeTransferFrom from operator', async function () { - await expectRevertCustomError( - this.token.safeTransferFrom(holder, receiver, firstTokenId, firstTokenValue, '0x', { from: operator }), - 'EnforcedPause', - [], - ); + await expect( + this.token + .connect(this.operator) + .safeTransferFrom(this.holder, this.receiver, firstTokenId, firstTokenValue, '0x'), + ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); }); it('reverts when trying to safeBatchTransferFrom from holder', async function () { - await expectRevertCustomError( - this.token.safeBatchTransferFrom(holder, receiver, [firstTokenId], [firstTokenValue], '0x', { from: holder }), - 'EnforcedPause', - [], - ); + await expect( + this.token + .connect(this.holder) + .safeBatchTransferFrom(this.holder, this.receiver, [firstTokenId], [firstTokenValue], '0x'), + ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); }); it('reverts when trying to safeBatchTransferFrom from operator', async function () { - await expectRevertCustomError( - this.token.safeBatchTransferFrom(holder, receiver, [firstTokenId], [firstTokenValue], '0x', { - from: operator, - }), - 'EnforcedPause', - [], - ); + await expect( + this.token + .connect(this.operator) + .safeBatchTransferFrom(this.holder, this.receiver, [firstTokenId], [firstTokenValue], '0x'), + ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); }); it('reverts when trying to mint', async function () { - await expectRevertCustomError( - this.token.$_mint(holder, secondTokenId, secondTokenValue, '0x'), + await expect(this.token.$_mint(this.holder, secondTokenId, secondTokenValue, '0x')).to.be.revertedWithCustomError( + this.token, 'EnforcedPause', - [], ); }); it('reverts when trying to mintBatch', async function () { - await expectRevertCustomError( - this.token.$_mintBatch(holder, [secondTokenId], [secondTokenValue], '0x'), - 'EnforcedPause', - [], - ); + await expect( + this.token.$_mintBatch(this.holder, [secondTokenId], [secondTokenValue], '0x'), + ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); }); it('reverts when trying to burn', async function () { - await expectRevertCustomError(this.token.$_burn(holder, firstTokenId, firstTokenValue), 'EnforcedPause', []); + await expect(this.token.$_burn(this.holder, firstTokenId, firstTokenValue)).to.be.revertedWithCustomError( + this.token, + 'EnforcedPause', + ); }); it('reverts when trying to burnBatch', async function () { - await expectRevertCustomError( - this.token.$_burnBatch(holder, [firstTokenId], [firstTokenValue]), - 'EnforcedPause', - [], - ); + await expect( + this.token.$_burnBatch(this.holder, [firstTokenId], [firstTokenValue]), + ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); }); describe('setApprovalForAll', function () { it('approves an operator', async function () { - await this.token.setApprovalForAll(other, true, { from: holder }); - expect(await this.token.isApprovedForAll(holder, other)).to.equal(true); + await this.token.connect(this.holder).setApprovalForAll(this.other, true); + expect(await this.token.isApprovedForAll(this.holder, this.other)).to.be.true; }); }); describe('balanceOf', function () { it('returns the token value owned by the given address', async function () { - const balance = await this.token.balanceOf(holder, firstTokenId); - expect(balance).to.be.bignumber.equal(firstTokenValue); + expect(await this.token.balanceOf(this.holder, firstTokenId)).to.equal(firstTokenValue); }); }); describe('isApprovedForAll', function () { it('returns the approval of the operator', async function () { - expect(await this.token.isApprovedForAll(holder, operator)).to.equal(true); + expect(await this.token.isApprovedForAll(this.holder, this.operator)).to.be.true; }); }); }); diff --git a/test/token/ERC1155/extensions/ERC1155Supply.test.js b/test/token/ERC1155/extensions/ERC1155Supply.test.js index bf86920f6..72736d836 100644 --- a/test/token/ERC1155/extensions/ERC1155Supply.test.js +++ b/test/token/ERC1155/extensions/ERC1155Supply.test.js @@ -1,116 +1,119 @@ -const { BN, constants } = require('@openzeppelin/test-helpers'); - +const { ethers } = require('hardhat'); const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { ZERO_ADDRESS } = constants; +async function fixture() { + const [holder] = await ethers.getSigners(); + const token = await ethers.deployContract('$ERC1155Supply', ['https://token-cdn-domain/{id}.json']); + return { token, holder }; +} -const ERC1155Supply = artifacts.require('$ERC1155Supply'); - -contract('ERC1155Supply', function (accounts) { - const [holder] = accounts; - - const uri = 'https://token.com'; - - const firstTokenId = new BN('37'); - const firstTokenValue = new BN('42'); - - const secondTokenId = new BN('19842'); - const secondTokenValue = new BN('23'); +describe('ERC1155Supply', function () { + const firstTokenId = 37n; + const firstTokenValue = 42n; + const secondTokenId = 19842n; + const secondTokenValue = 23n; beforeEach(async function () { - this.token = await ERC1155Supply.new(uri); + Object.assign(this, await loadFixture(fixture)); }); - context('before mint', function () { + describe('before mint', function () { it('exist', async function () { - expect(await this.token.exists(firstTokenId)).to.be.equal(false); + expect(await this.token.exists(firstTokenId)).to.be.false; }); it('totalSupply', async function () { - expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal('0'); - expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal('0'); + expect(await this.token.totalSupply(ethers.Typed.uint256(firstTokenId))).to.equal(0n); + expect(await this.token.totalSupply()).to.equal(0n); }); }); - context('after mint', function () { - context('single', function () { + describe('after mint', function () { + describe('single', function () { beforeEach(async function () { - await this.token.$_mint(holder, firstTokenId, firstTokenValue, '0x'); + await this.token.$_mint(this.holder, firstTokenId, firstTokenValue, '0x'); }); it('exist', async function () { - expect(await this.token.exists(firstTokenId)).to.be.equal(true); + expect(await this.token.exists(firstTokenId)).to.be.true; }); it('totalSupply', async function () { - expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal(firstTokenValue); - expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal(firstTokenValue); + expect(await this.token.totalSupply(ethers.Typed.uint256(firstTokenId))).to.equal(firstTokenValue); + expect(await this.token.totalSupply()).to.equal(firstTokenValue); }); }); - context('batch', function () { + describe('batch', function () { beforeEach(async function () { - await this.token.$_mintBatch(holder, [firstTokenId, secondTokenId], [firstTokenValue, secondTokenValue], '0x'); - }); - - it('exist', async function () { - expect(await this.token.exists(firstTokenId)).to.be.equal(true); - expect(await this.token.exists(secondTokenId)).to.be.equal(true); - }); - - it('totalSupply', async function () { - expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal(firstTokenValue); - expect(await this.token.methods['totalSupply(uint256)'](secondTokenId)).to.be.bignumber.equal(secondTokenValue); - expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal( - firstTokenValue.add(secondTokenValue), + await this.token.$_mintBatch( + this.holder, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', ); }); - }); - }); - - context('after burn', function () { - context('single', function () { - beforeEach(async function () { - await this.token.$_mint(holder, firstTokenId, firstTokenValue, '0x'); - await this.token.$_burn(holder, firstTokenId, firstTokenValue); - }); it('exist', async function () { - expect(await this.token.exists(firstTokenId)).to.be.equal(false); + expect(await this.token.exists(firstTokenId)).to.be.true; + expect(await this.token.exists(secondTokenId)).to.be.true; }); it('totalSupply', async function () { - expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal('0'); - expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal('0'); - }); - }); - - context('batch', function () { - beforeEach(async function () { - await this.token.$_mintBatch(holder, [firstTokenId, secondTokenId], [firstTokenValue, secondTokenValue], '0x'); - await this.token.$_burnBatch(holder, [firstTokenId, secondTokenId], [firstTokenValue, secondTokenValue]); - }); - - it('exist', async function () { - expect(await this.token.exists(firstTokenId)).to.be.equal(false); - expect(await this.token.exists(secondTokenId)).to.be.equal(false); - }); - - it('totalSupply', async function () { - expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal('0'); - expect(await this.token.methods['totalSupply(uint256)'](secondTokenId)).to.be.bignumber.equal('0'); - expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal('0'); + expect(await this.token.totalSupply(ethers.Typed.uint256(firstTokenId))).to.equal(firstTokenValue); + expect(await this.token.totalSupply(ethers.Typed.uint256(secondTokenId))).to.equal(secondTokenValue); + expect(await this.token.totalSupply()).to.equal(firstTokenValue + secondTokenValue); }); }); }); - context('other', function () { + describe('after burn', function () { + describe('single', function () { + beforeEach(async function () { + await this.token.$_mint(this.holder, firstTokenId, firstTokenValue, '0x'); + await this.token.$_burn(this.holder, firstTokenId, firstTokenValue); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.false; + }); + + it('totalSupply', async function () { + expect(await this.token.totalSupply(ethers.Typed.uint256(firstTokenId))).to.equal(0n); + expect(await this.token.totalSupply()).to.equal(0n); + }); + }); + + describe('batch', function () { + beforeEach(async function () { + await this.token.$_mintBatch( + this.holder, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ); + await this.token.$_burnBatch(this.holder, [firstTokenId, secondTokenId], [firstTokenValue, secondTokenValue]); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.false; + expect(await this.token.exists(secondTokenId)).to.be.false; + }); + + it('totalSupply', async function () { + expect(await this.token.totalSupply(ethers.Typed.uint256(firstTokenId))).to.equal(0n); + expect(await this.token.totalSupply(ethers.Typed.uint256(secondTokenId))).to.equal(0n); + expect(await this.token.totalSupply()).to.equal(0n); + }); + }); + }); + + describe('other', function () { it('supply unaffected by no-op', async function () { - this.token.safeTransferFrom(ZERO_ADDRESS, ZERO_ADDRESS, firstTokenId, firstTokenValue, '0x', { - from: ZERO_ADDRESS, - }); - expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal('0'); - expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal('0'); + this.token.safeTransferFrom(ethers.ZeroAddress, ethers.ZeroAddress, firstTokenId, firstTokenValue, '0x'); + expect(await this.token.totalSupply(ethers.Typed.uint256(firstTokenId))).to.equal(0n); + expect(await this.token.totalSupply()).to.equal(0n); }); }); }); diff --git a/test/token/ERC1155/extensions/ERC1155URIStorage.test.js b/test/token/ERC1155/extensions/ERC1155URIStorage.test.js index 58ac67bc6..a0d9b5704 100644 --- a/test/token/ERC1155/extensions/ERC1155URIStorage.test.js +++ b/test/token/ERC1155/extensions/ERC1155URIStorage.test.js @@ -1,66 +1,70 @@ -const { BN, expectEvent } = require('@openzeppelin/test-helpers'); - +const { ethers } = require('hardhat'); const { expect } = require('chai'); -const { artifacts } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const ERC1155URIStorage = artifacts.require('$ERC1155URIStorage'); - -contract(['ERC1155URIStorage'], function (accounts) { - const [holder] = accounts; - - const erc1155Uri = 'https://token.com/nfts/'; - const baseUri = 'https://token.com/'; - - const tokenId = new BN('1'); - const value = new BN('3000'); +const erc1155Uri = 'https://token.com/nfts/'; +const baseUri = 'https://token.com/'; +const tokenId = 1n; +const value = 3000n; +describe('ERC1155URIStorage', function () { describe('with base uri set', function () { - beforeEach(async function () { - this.token = await ERC1155URIStorage.new(erc1155Uri); - await this.token.$_setBaseURI(baseUri); + async function fixture() { + const [holder] = await ethers.getSigners(); - await this.token.$_mint(holder, tokenId, value, '0x'); + const token = await ethers.deployContract('$ERC1155URIStorage', [erc1155Uri]); + await token.$_setBaseURI(baseUri); + await token.$_mint(holder, tokenId, value, '0x'); + + return { token, holder }; + } + + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); }); it('can request the token uri, returning the erc1155 uri if no token uri was set', async function () { - const receivedTokenUri = await this.token.uri(tokenId); - - expect(receivedTokenUri).to.be.equal(erc1155Uri); + expect(await this.token.uri(tokenId)).to.equal(erc1155Uri); }); it('can request the token uri, returning the concatenated uri if a token uri was set', async function () { const tokenUri = '1234/'; - const receipt = await this.token.$_setURI(tokenId, tokenUri); - - const receivedTokenUri = await this.token.uri(tokenId); - const expectedUri = `${baseUri}${tokenUri}`; - expect(receivedTokenUri).to.be.equal(expectedUri); - expectEvent(receipt, 'URI', { value: expectedUri, id: tokenId }); + + await expect(this.token.$_setURI(ethers.Typed.uint256(tokenId), tokenUri)) + .to.emit(this.token, 'URI') + .withArgs(expectedUri, tokenId); + + expect(await this.token.uri(tokenId)).to.equal(expectedUri); }); }); describe('with base uri set to the empty string', function () { - beforeEach(async function () { - this.token = await ERC1155URIStorage.new(''); + async function fixture() { + const [holder] = await ethers.getSigners(); - await this.token.$_mint(holder, tokenId, value, '0x'); + const token = await ethers.deployContract('$ERC1155URIStorage', ['']); + await token.$_mint(holder, tokenId, value, '0x'); + + return { token, holder }; + } + + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); }); it('can request the token uri, returning an empty string if no token uri was set', async function () { - const receivedTokenUri = await this.token.uri(tokenId); - - expect(receivedTokenUri).to.be.equal(''); + expect(await this.token.uri(tokenId)).to.equal(''); }); it('can request the token uri, returning the token uri if a token uri was set', async function () { const tokenUri = 'ipfs://1234/'; - const receipt = await this.token.$_setURI(tokenId, tokenUri); - const receivedTokenUri = await this.token.uri(tokenId); + await expect(this.token.$_setURI(ethers.Typed.uint256(tokenId), tokenUri)) + .to.emit(this.token, 'URI') + .withArgs(tokenUri, tokenId); - expect(receivedTokenUri).to.be.equal(tokenUri); - expectEvent(receipt, 'URI', { value: tokenUri, id: tokenId }); + expect(await this.token.uri(tokenId)).to.equal(tokenUri); }); }); }); diff --git a/test/token/ERC1155/utils/ERC1155Holder.test.js b/test/token/ERC1155/utils/ERC1155Holder.test.js index ee818eae8..52705fc45 100644 --- a/test/token/ERC1155/utils/ERC1155Holder.test.js +++ b/test/token/ERC1155/utils/ERC1155Holder.test.js @@ -1,64 +1,56 @@ -const { BN } = require('@openzeppelin/test-helpers'); - -const ERC1155Holder = artifacts.require('$ERC1155Holder'); -const ERC1155 = artifacts.require('$ERC1155'); - +const { ethers } = require('hardhat'); const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); -contract('ERC1155Holder', function (accounts) { - const [creator] = accounts; - const uri = 'https://token-cdn-domain/{id}.json'; - const multiTokenIds = [new BN(1), new BN(2), new BN(3)]; - const multiTokenValues = [new BN(1000), new BN(2000), new BN(3000)]; - const transferData = '0x12345678'; +const ids = [1n, 2n, 3n]; +const values = [1000n, 2000n, 3000n]; +const data = '0x12345678'; +async function fixture() { + const [owner] = await ethers.getSigners(); + + const token = await ethers.deployContract('$ERC1155', ['https://token-cdn-domain/{id}.json']); + const mock = await ethers.deployContract('$ERC1155Holder'); + + await token.$_mintBatch(owner, ids, values, '0x'); + + return { owner, token, mock }; +} + +describe('ERC1155Holder', function () { beforeEach(async function () { - this.multiToken = await ERC1155.new(uri); - this.holder = await ERC1155Holder.new(); - await this.multiToken.$_mintBatch(creator, multiTokenIds, multiTokenValues, '0x'); + Object.assign(this, await loadFixture(fixture)); }); shouldSupportInterfaces(['ERC165', 'ERC1155Receiver']); it('receives ERC1155 tokens from a single ID', async function () { - await this.multiToken.safeTransferFrom( - creator, - this.holder.address, - multiTokenIds[0], - multiTokenValues[0], - transferData, - { from: creator }, - ); + await this.token.connect(this.owner).safeTransferFrom(this.owner, this.mock, ids[0], values[0], data); - expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[0])).to.be.bignumber.equal( - multiTokenValues[0], - ); + expect(await this.token.balanceOf(this.mock, ids[0])).to.equal(values[0]); - for (let i = 1; i < multiTokenIds.length; i++) { - expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[i])).to.be.bignumber.equal(new BN(0)); + for (let i = 1; i < ids.length; i++) { + expect(await this.token.balanceOf(this.mock, ids[i])).to.equal(0n); } }); it('receives ERC1155 tokens from a multiple IDs', async function () { - for (let i = 0; i < multiTokenIds.length; i++) { - expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[i])).to.be.bignumber.equal(new BN(0)); - } + expect( + await this.token.balanceOfBatch( + ids.map(() => this.mock), + ids, + ), + ).to.deep.equal(ids.map(() => 0n)); - await this.multiToken.safeBatchTransferFrom( - creator, - this.holder.address, - multiTokenIds, - multiTokenValues, - transferData, - { from: creator }, - ); + await this.token.connect(this.owner).safeBatchTransferFrom(this.owner, this.mock, ids, values, data); - for (let i = 0; i < multiTokenIds.length; i++) { - expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[i])).to.be.bignumber.equal( - multiTokenValues[i], - ); - } + expect( + await this.token.balanceOfBatch( + ids.map(() => this.mock), + ids, + ), + ).to.deep.equal(values); }); }); diff --git a/test/token/ERC721/ERC721.behavior.js b/test/token/ERC721/ERC721.behavior.js index 32d67d90d..ff441f5e6 100644 --- a/test/token/ERC721/ERC721.behavior.js +++ b/test/token/ERC721/ERC721.behavior.js @@ -5,11 +5,9 @@ const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs'); const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); const { - bigint: { Enum }, + bigint: { RevertType }, } = require('../../helpers/enums'); -const RevertType = Enum('None', 'RevertWithoutMessage', 'RevertWithMessage', 'RevertWithCustomError', 'Panic'); - const firstTokenId = 5042n; const secondTokenId = 79217n; const nonExistentTokenId = 13n;