diff --git a/test/FleekERC721.ts b/test/FleekERC721.ts index 427bde7..bc8d39c 100644 --- a/test/FleekERC721.ts +++ b/test/FleekERC721.ts @@ -1,10 +1,12 @@ import { loadFixture } from '@nomicfoundation/hardhat-network-helpers'; import { expect } from 'chai'; import { ethers } from 'hardhat'; -import web3 from 'web3'; describe('FleekERC721', () => { - const COLLECTION_OWNER_ROLE = web3.utils.keccak256('COLLECTION_OWNER_ROLE'); + const ROLES = Object.freeze({ + OWNER: 0, + CONTROLLER: 1, + }); const MINT_PARAMS = Object.freeze({ name: 'Fleek Test App', @@ -43,12 +45,6 @@ describe('FleekERC721', () => { expect(await contract.symbol()).to.equal(COLLECTION_PARAMS.symbol); }); - it('should assign the owner of the contract', async () => { - const { owner, contract } = await loadFixture(defaultFixture); - - expect(await contract.hasCollectionRole(0, owner.address)).to.equal(true); - }); - it('should support ERC721 interface', async () => { const { contract } = await loadFixture(defaultFixture); @@ -114,13 +110,15 @@ describe('FleekERC721', () => { const tokenId = response.value.toNumber(); expect(await contract.ownerOf(tokenId)).to.equal(owner.address); - expect(await contract.hasTokenRole(tokenId, 0, owner.address)).to.be.true; + expect(await contract.hasTokenRole(tokenId, ROLES.OWNER, owner.address)) + .to.be.true; expect(await contract.ownerOf(tokenId)).not.to.equal( otherAccount.address ); - expect(await contract.hasTokenRole(tokenId, 0, otherAccount.address)).to - .be.false; + expect( + await contract.hasTokenRole(tokenId, ROLES.OWNER, otherAccount.address) + ).to.be.false; }); }); @@ -217,7 +215,11 @@ describe('FleekERC721', () => { it('should match the owner role for minter', async () => { const { contract, owner } = fixture; - const hasRole = await contract.hasTokenRole(tokenId, 0, owner.address); + const hasRole = await contract.hasTokenRole( + tokenId, + ROLES.OWNER, + owner.address + ); expect(hasRole).to.be.true; }); @@ -226,16 +228,18 @@ describe('FleekERC721', () => { const { contract, owner } = fixture; await contract.grantTokenRole( tokenId, - 1, + ROLES.CONTROLLER, '0x7ED735b7095C05d78dF169F991f2b7f1A1F1A049' ); await contract.grantTokenRole( tokenId, - 1, + ROLES.CONTROLLER, '0x2FEd6Ef3c495922263B403319FA6DDB323DD49E3' ); - expect(await contract.getTokenRoleMembers(tokenId, 1)).to.eql([ + expect( + await contract.getTokenRoleMembers(tokenId, ROLES.CONTROLLER) + ).to.eql([ '0x7ED735b7095C05d78dF169F991f2b7f1A1F1A049', '0x2FEd6Ef3c495922263B403319FA6DDB323DD49E3', ]); @@ -245,7 +249,7 @@ describe('FleekERC721', () => { const { contract, otherAccount } = fixture; const hasRole = await contract.hasTokenRole( tokenId, - 0, + ROLES.OWNER, otherAccount.address ); @@ -254,27 +258,186 @@ describe('FleekERC721', () => { it('should add a new controller', async () => { const { contract, owner, otherAccount } = fixture; - await contract.grantTokenRole(tokenId, 1, otherAccount.address); + await contract.grantTokenRole( + tokenId, + ROLES.CONTROLLER, + otherAccount.address + ); - expect(await contract.hasTokenRole(tokenId, 1, otherAccount.address)).to - .be.true; + expect( + await contract.hasTokenRole( + tokenId, + ROLES.CONTROLLER, + otherAccount.address + ) + ).to.be.true; }); it('should transfer the token owner role', async () => { - // FIXME: this test is failing const { contract, owner, otherAccount } = fixture; await contract.transferFrom(owner.address, otherAccount.address, tokenId); - console.log(owner.address, otherAccount.address, tokenId); - - console.log(await contract.getTokenRoleMembers(tokenId, 0)); - console.log(await contract.getTokenRoleMembers(tokenId, 1)); - expect(await contract.ownerOf(tokenId)).to.equal(otherAccount.address); - expect(await contract.hasTokenRole(tokenId, 0, otherAccount.address)).to - .be.true; - expect(await contract.hasTokenRole(tokenId, 0, owner.address)).to.be - .false; + expect( + await contract.hasTokenRole(tokenId, ROLES.OWNER, otherAccount.address) + ).to.be.true; + expect(await contract.hasTokenRole(tokenId, ROLES.OWNER, owner.address)) + .to.be.false; + }); + + it('should clean the token controller list after transfer', async () => { + const { contract, owner, otherAccount } = fixture; + await contract.grantTokenRole( + tokenId, + ROLES.CONTROLLER, + otherAccount.address + ); + await contract.transferFrom(owner.address, otherAccount.address, tokenId); + + expect(await contract.getTokenRoleMembers(tokenId, 1)).to.eql([]); + }); + }); + + describe('Collection Roles', () => { + let fixture: Awaited>; + + beforeEach(async () => { + fixture = await loadFixture(defaultFixture); + }); + + it('should assign the owner of the contract on contract creation', async () => { + const { owner, contract } = fixture; + + expect(await contract.hasCollectionRole(ROLES.OWNER, owner.address)).to.be + .true; + }); + + it('should assign owner role to address', async () => { + const { otherAccount, contract } = fixture; + + await contract.grantCollectionRole(ROLES.OWNER, otherAccount.address); + + expect( + await contract.hasCollectionRole(ROLES.OWNER, otherAccount.address) + ).to.be.true; + }); + + it('should assign controller role to address', async () => { + const { owner, contract } = fixture; + + await contract.grantCollectionRole(ROLES.CONTROLLER, owner.address); + + expect(await contract.hasCollectionRole(ROLES.CONTROLLER, owner.address)) + .to.be.true; + }); + + it('should remove an assigned controller', async () => { + const { otherAccount, contract } = fixture; + + await contract.grantCollectionRole(ROLES.OWNER, otherAccount.address); + await contract.revokeCollectionRole(ROLES.OWNER, otherAccount.address); + + expect( + await contract.hasCollectionRole(ROLES.OWNER, otherAccount.address) + ).to.be.false; + }); + + it('should remove an assigned controller', async () => { + const { owner, contract } = fixture; + + await contract.grantCollectionRole(ROLES.CONTROLLER, owner.address); + await contract.revokeCollectionRole(ROLES.CONTROLLER, owner.address); + + expect(await contract.hasCollectionRole(ROLES.CONTROLLER, owner.address)) + .to.be.false; + }); + + it('should fetch the list of controllers', async () => { + const { owner, contract } = fixture; + + await contract.grantCollectionRole(ROLES.CONTROLLER, owner.address); + await contract.grantCollectionRole( + ROLES.CONTROLLER, + '0x7ED735b7095C05d78dF169F991f2b7f1A1F1A049' + ); + + expect(await contract.getCollectionRoleMembers(ROLES.CONTROLLER)).to.eql([ + owner.address, + '0x7ED735b7095C05d78dF169F991f2b7f1A1F1A049', + ]); + }); + + it('should fetch the list of owners', async () => { + const { owner, contract, otherAccount } = fixture; + + await contract.grantCollectionRole(ROLES.OWNER, otherAccount.address); + await contract.grantCollectionRole( + ROLES.OWNER, + '0x7ED735b7095C05d78dF169F991f2b7f1A1F1A049' + ); + + expect(await contract.getCollectionRoleMembers(ROLES.OWNER)).to.eql([ + owner.address, + otherAccount.address, + '0x7ED735b7095C05d78dF169F991f2b7f1A1F1A049', + ]); + }); + + it('should not be able to add new owner', async () => { + const { otherAccount, contract } = fixture; + + await expect( + contract + .connect(otherAccount) + .grantCollectionRole(ROLES.OWNER, otherAccount.address) + ).to.be.revertedWith('FleekAccessControl: must have collection role'); + }); + + it('should not be able to add new controller', async () => { + const { otherAccount, contract } = fixture; + + await expect( + contract + .connect(otherAccount) + .grantCollectionRole(ROLES.CONTROLLER, otherAccount.address) + ).to.be.revertedWith('FleekAccessControl: must have collection role'); + }); + + it('should be able to add roles after owner being granted', async () => { + const { otherAccount, contract } = fixture; + + await contract.grantCollectionRole(ROLES.OWNER, otherAccount.address); + + await expect( + contract + .connect(otherAccount) + .grantCollectionRole(ROLES.CONTROLLER, otherAccount.address) + ).to.not.be.reverted; + await expect( + contract + .connect(otherAccount) + .revokeCollectionRole(ROLES.CONTROLLER, otherAccount.address) + ).to.not.be.reverted; + }); + + it('should not be able to change roles for controllers', async () => { + const { owner, otherAccount, contract } = fixture; + + await contract.grantCollectionRole( + ROLES.CONTROLLER, + otherAccount.address + ); + + await expect( + contract + .connect(otherAccount) + .grantCollectionRole(ROLES.OWNER, owner.address) + ).to.be.revertedWith('FleekAccessControl: must have collection role'); + await expect( + contract + .connect(otherAccount) + .revokeCollectionRole(ROLES.OWNER, owner.address) + ).to.be.revertedWith('FleekAccessControl: must have collection role'); }); }); });