1234567891011121314151617import type {IKeyringPair} from '@polkadot/types/types';18import {usingPlaygrounds, expect, itSub} from './util/index.js';19import type {ICollectionPermissions} from '@unique/playgrounds/src/types.js';20import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/src/types.js';2122describe('Integration Test ext. Allow list tests', () => {23 let alice: IKeyringPair;24 let bob: IKeyringPair;25 let charlie: IKeyringPair;2627 before(async () => {28 await usingPlaygrounds(async (helper, privateKey) => {29 const donor = await privateKey({url: import.meta.url});30 [alice, bob, charlie] = await helper.arrange.createAccounts([30n, 10n, 10n], donor);31 });32 });3334 describe('Positive', () => {35 itSub('Owner can add address to allow list', async ({helper}) => {36 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});37 38 await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});39 const allowList = await helper.nft.getAllowList(collectionId);40 expect(allowList).to.deep.contain({Substrate: bob.address});41 });4243 itSub('Admin can add address to allow list', async ({helper}) => {44 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});45 await helper.nft.addAdmin(alice, collectionId, {Substrate: bob.address});4647 48 await helper.nft.addToAllowList(bob, collectionId, {Substrate: charlie.address});49 const allowList = await helper.nft.getAllowList(collectionId);50 expect(allowList).to.deep.contain({Substrate: charlie.address});51 });5253 itSub('If address is already added to allow list, nothing happens', async ({helper}) => {54 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});55 await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});56 await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});57 const allowList = await helper.nft.getAllowList(collectionId);58 expect(allowList).to.deep.contain({Substrate: bob.address});59 });60 });6162 describe('Negative', () => {63 itSub('Nobody can add address to allow list of non-existing collection', async ({helper}) => {64 const collectionId = NON_EXISTENT_COLLECTION_ID;65 await expect(helper.nft.addToAllowList(bob, collectionId, {Substrate: charlie.address}))66 .to.be.rejectedWith(/common\.CollectionNotFound/);67 });6869 itSub('Nobody can add address to allow list of destroyed collection', async ({helper}) => {70 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});71 await helper.collection.burn(alice, collectionId);72 await expect(helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address}))73 .to.be.rejectedWith(/common\.CollectionNotFound/);74 });7576 itSub('Non-privileged user cannot add address to allow list', async ({helper}) => {77 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});78 await expect(helper.nft.addToAllowList(bob, collectionId, {Substrate: charlie.address}))79 .to.be.rejectedWith(/common\.NoPermission/);80 });81 });82});8384describe('Integration Test ext. Remove from Allow List', () => {85 let alice: IKeyringPair;86 let bob: IKeyringPair;87 let charlie: IKeyringPair;8889 before(async () => {90 await usingPlaygrounds(async (helper, privateKey) => {91 const donor = await privateKey({url: import.meta.url});92 [alice, bob, charlie] = await helper.arrange.createAccounts([30n, 10n, 10n], donor);93 });94 });9596 describe('Positive', () => {97 itSub('Owner can remove address from allow list', async ({helper}) => {98 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});99 await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});100101 await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address});102103 const allowList = await helper.nft.getAllowList(collectionId);104105 expect(allowList).to.not.deep.contain({Substrate: bob.address});106 });107108 itSub('Admin can remove address from allow list', async ({helper}) => {109 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});110 await helper.nft.addAdmin(alice, collectionId, {Substrate: charlie.address});111 await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});112 await helper.collection.removeFromAllowList(charlie, collectionId, {Substrate: bob.address});113114 const allowList = await helper.nft.getAllowList(collectionId);115 expect(allowList).to.not.deep.contain({Substrate: bob.address});116 });117118 itSub('If address is already removed from allow list, nothing happens', async ({helper}) => {119 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});120 await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});121 await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address});122 const allowListBefore = await helper.nft.getAllowList(collectionId);123 expect(allowListBefore).to.not.deep.contain({Substrate: bob.address});124125 await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address});126127 const allowListAfter = await helper.nft.getAllowList(collectionId);128 expect(allowListAfter).to.not.deep.contain({Substrate: bob.address});129 });130 });131132 describe('Negative', () => {133 itSub('Non-privileged user cannot remove address from allow list', async ({helper}) => {134 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});135 await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});136 await expect(helper.collection.removeFromAllowList(charlie, collectionId, {Substrate: charlie.address}))137 .to.be.rejectedWith(/common\.NoPermission/);138139 const allowList = await helper.nft.getAllowList(collectionId);140 expect(allowList).to.deep.contain({Substrate: charlie.address});141 });142143 itSub('Nobody can remove address from allow list of non-existing collection', async ({helper}) => {144 const collectionId = NON_EXISTENT_COLLECTION_ID;145 await expect(helper.collection.removeFromAllowList(bob, collectionId, {Substrate: charlie.address}))146 .to.be.rejectedWith(/common\.CollectionNotFound/);147 });148149 itSub('Nobody can remove address from allow list of deleted collection', async ({helper}) => {150 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});151 await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});152 await helper.collection.burn(alice, collectionId);153154 await expect(helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address}))155 .to.be.rejectedWith(/common\.CollectionNotFound/);156 });157 });158});159160describe('Integration Test ext. Transfer if included in Allow List', () => {161 let alice: IKeyringPair;162 let bob: IKeyringPair;163 let charlie: IKeyringPair;164165 before(async () => {166 await usingPlaygrounds(async (helper, privateKey) => {167 const donor = await privateKey({url: import.meta.url});168 [alice, bob, charlie] = await helper.arrange.createAccounts([30n, 10n, 10n], donor);169 });170 });171172 describe('Positive', () => {173 itSub('If Public Access mode is set to AllowList, tokens can be transferred to a allowlisted address with transfer.', async ({helper}) => {174 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});175 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});176 await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});177 await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});178 await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});179 await helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address});180 const owner = await helper.nft.getTokenOwner(collectionId, tokenId);181 expect(owner).to.be.deep.equal({Substrate: charlie.address});182 });183184 itSub('If Public Access mode is set to AllowList, tokens can be transferred to a allowlisted address with transferFrom.', async ({helper}) => {185 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});186 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});187 await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});188 await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});189 await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});190 await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address});191192 await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: alice.address}, {Substrate: charlie.address});193 const owner = await helper.nft.getTokenOwner(collectionId, tokenId);194 expect(owner).to.be.deep.equal({Substrate: charlie.address});195 });196197 itSub('If Public Access mode is set to AllowList, tokens can be transferred from a allowlisted address with transfer', async ({helper}) => {198 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});199 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});200 await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});201 await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});202 await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});203204 await helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address});205 const owner = await helper.nft.getTokenOwner(collectionId, tokenId);206 expect(owner).to.be.deep.equal({Substrate: charlie.address});207 });208209 itSub('If Public Access mode is set to AllowList, tokens can be transferred from a allowlisted address with transferFrom', async ({helper}) => {210 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});211 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});212 await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});213 await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});214 await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});215 await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address});216217 await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: alice.address}, {Substrate: charlie.address});218 const owner = await helper.nft.getTokenOwner(collectionId, tokenId);219 expect(owner).to.be.deep.equal({Substrate: charlie.address});220 });221 });222223 describe('Negative', () => {224 itSub('If Public Access mode is set to AllowList, tokens can\'t be transferred from a non-allowlisted address with transfer or transferFrom. Test1', async ({helper}) => {225 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});226 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});227 await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});228 await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});229230 await expect(helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}))231 .to.be.rejectedWith(/common\.AddressNotInAllowlist/);232 });233234 itSub('If Public Access mode is set to AllowList, tokens can\'t be transferred from a non-allowlisted address with transfer or transferFrom. Test2', async ({helper}) => {235 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});236 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});237 await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});238 await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});239 await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});240 await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address});241 await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: alice.address});242243 await expect(helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}))244 .to.be.rejectedWith(/common\.AddressNotInAllowlist/);245 });246247 itSub('If Public Access mode is set to AllowList, tokens can\'t be transferred to a non-allowlisted address with transfer or transferFrom. Test1', async ({helper}) => {248 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});249 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});250 await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});251 await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});252253 await expect(helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}))254 .to.be.rejectedWith(/common\.AddressNotInAllowlist/);255 });256257 itSub('If Public Access mode is set to AllowList, tokens can\'t be transferred to a non-allowlisted address with transfer or transferFrom. Test2', async ({helper}) => {258 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});259 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});260 await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});261 await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});262 await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});263264 await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address});265 await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: alice.address});266267 await expect(helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}))268 .to.be.rejectedWith(/common\.AddressNotInAllowlist/);269 });270271 itSub('If Public Access mode is set to AllowList, tokens can\'t be destroyed by a non-allowlisted address (even if it owned them before enabling AllowList mode)', async ({helper}) => {272 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});273 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});274 await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});275 await expect(helper.nft.burnToken(bob, collectionId, tokenId))276 .to.be.rejectedWith(/common\.NoPermission/);277 });278279 itSub('If Public Access mode is set to AllowList, token transfers can\'t be Approved by a non-allowlisted address (see Approve method)', async ({helper}) => {280 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});281 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});282 await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});283 await expect(helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}))284 .to.be.rejectedWith(/common\.AddressNotInAllowlist/);285 });286 });287});288289describe('Integration Test ext. Mint if included in Allow List', () => {290 let alice: IKeyringPair;291 let bob: IKeyringPair;292293 before(async () => {294 await usingPlaygrounds(async (helper, privateKey) => {295 const donor = await privateKey({url: import.meta.url});296 [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);297 });298 });299300 const permissionSet: ICollectionPermissions[] = [301 {access: 'Normal', mintMode: false},302 {access: 'Normal', mintMode: true},303 {access: 'AllowList', mintMode: false},304 {access: 'AllowList', mintMode: true},305 ];306307 const testPermissionSuite = (permissions: ICollectionPermissions) => {308 const allowlistedMintingShouldFail = !permissions.mintMode!;309310 const appropriateRejectionMessage = permissions.mintMode! ? /common\.AddressNotInAllowlist/ : /common\.PublicMintingNotAllowed/;311312 const allowlistedMintingTest = () => itSub(313 `With the condtions above, tokens can${allowlistedMintingShouldFail ? '\'t' : ''} be created by allow-listed addresses`,314 async ({helper}) => {315 const collection = await helper.nft.mintCollection(alice, {});316 await collection.setPermissions(alice, permissions);317 await collection.addToAllowList(alice, {Substrate: bob.address});318319 if(allowlistedMintingShouldFail)320 await expect(collection.mintToken(bob, {Substrate: bob.address})).to.be.rejectedWith(appropriateRejectionMessage);321 else322 await expect(collection.mintToken(bob, {Substrate: bob.address})).to.not.be.rejected;323 },324 );325326327 describe(`Public Access Mode = ${permissions.access}, Mint Mode = ${permissions.mintMode}`, () => {328 describe('Positive', () => {329 itSub('With the condtions above, tokens can be created by owner', async ({helper}) => {330 const collection = await helper.nft.mintCollection(alice, {});331 await collection.setPermissions(alice, permissions);332 await expect(collection.mintToken(alice, {Substrate: alice.address})).to.not.be.rejected;333 });334335 itSub('With the condtions above, tokens can be created by admin', async ({helper}) => {336 const collection = await helper.nft.mintCollection(alice, {});337 await collection.setPermissions(alice, permissions);338 await collection.addAdmin(alice, {Substrate: bob.address});339 await expect(collection.mintToken(bob, {Substrate: bob.address})).to.not.be.rejected;340 });341342 if(!allowlistedMintingShouldFail) allowlistedMintingTest();343 });344345 describe('Negative', () => {346 itSub('With the condtions above, tokens can\'t be created by non-priviliged non-allow-listed address', async ({helper}) => {347 const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});348 await collection.setPermissions(alice, permissions);349 await expect(collection.mintToken(bob, {Substrate: bob.address}))350 .to.be.rejectedWith(appropriateRejectionMessage);351 });352353 if(allowlistedMintingShouldFail) allowlistedMintingTest();354 });355 });356 };357358 for(const permissions of permissionSet) {359 testPermissionSuite(permissions);360 }361});