1234567891011121314151617import {expect} from 'chai';18import type {IKeyringPair} from '@polkadot/types/types';19import {itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';20import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';21import type {IEvent, TCollectionMode} from '@unique-nft/playgrounds/types.js';22import {Pallets, requirePalletsOrSkip} from '@unique/test-utils/util.js';23import {CollectionLimitField, TokenPermissionField, CreateCollectionData} from '@unique/test-utils/eth/types.js';24import type {NormalizedEvent} from '@unique/test-utils/eth/types.js';2526let donor: IKeyringPair;2728before(async function () {29 await usingEthPlaygrounds(async (_helper, privateKey) => {30 donor = await privateKey({url: import.meta.url});31 });32});3334function clearEvents(ethEvents: NormalizedEvent[] | null, subEvents: IEvent[]) {35 if(ethEvents !== null) {36 ethEvents.splice(0);37 }38 subEvents.splice(0);39}4041async function testCollectionCreatedAndDestroy(helper: EthUniqueHelper, mode: TCollectionMode) {42 const owner = await helper.eth.createAccountWithBalance(donor);43 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionCreated', 'CollectionDestroyed']}]);44 const {collectionAddress, events: ethEvents} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();4546 await helper.wait.newBlocks(1);47 {48 expect(ethEvents).to.containSubset([49 {50 event: 'CollectionCreated',51 args: {52 owner: owner,53 collectionId: collectionAddress,54 },55 },56 ]);57 expect(subEvents).to.containSubset([{method: 'CollectionCreated'}]);58 clearEvents(ethEvents, subEvents);59 }60 {61 const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);62 const result = await collectionHelper.methods.destroyCollection(collectionAddress).send({from:owner});63 await helper.wait.newBlocks(1);64 expect(result.events).to.containSubset({65 CollectionDestroyed: {66 returnValues: {67 collectionId: collectionAddress,68 },69 },70 });71 expect(subEvents).to.containSubset([{method: 'CollectionDestroyed'}]);72 }73 unsubscribe();74}7576async function testCollectionPropertySetAndDeleted(helper: EthUniqueHelper, mode: TCollectionMode) {77 const owner = await helper.eth.createAccountWithBalance(donor);78 const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();79 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);80 const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);8182 const ethEvents: any = [];83 collectionHelper.events.allEvents((_: any, event: any) => {84 ethEvents.push(event);85 });86 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionPropertySet', 'CollectionPropertyDeleted']}]);87 {88 await collection.methods.setCollectionProperties([{key: 'A', value: [0,1,2,3]}]).send({from:owner});89 await helper.wait.newBlocks(1);90 expect(ethEvents).to.containSubset([91 {92 event: 'CollectionChanged',93 returnValues: {94 collectionId: collectionAddress,95 },96 },97 ]);98 expect(subEvents).to.containSubset([{method: 'CollectionPropertySet'}]);99 clearEvents(ethEvents, subEvents);100 }101 {102 await collection.methods.deleteCollectionProperties(['A']).send({from:owner});103 await helper.wait.newBlocks(1);104 expect(ethEvents).to.containSubset([105 {106 event: 'CollectionChanged',107 returnValues: {108 collectionId: collectionAddress,109 },110 },111 ]);112 expect(subEvents).to.containSubset([{method: 'CollectionPropertyDeleted'}]);113 }114 unsubscribe();115}116117async function testPropertyPermissionSet(helper: EthUniqueHelper, mode: TCollectionMode) {118 const owner = await helper.eth.createAccountWithBalance(donor);119 const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();120 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);121 const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);122 const ethEvents: any = [];123 collectionHelper.events.allEvents((_: any, event: any) => {124 ethEvents.push(event);125 });126 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['PropertyPermissionSet']}]);127 await collection.methods.setTokenPropertyPermissions([128 ['A', [129 [TokenPermissionField.Mutable, true],130 [TokenPermissionField.TokenOwner, true],131 [TokenPermissionField.CollectionAdmin, true]],132 ],133 ]).send({from: owner});134 await helper.wait.newBlocks(1);135 expect(ethEvents).to.containSubset([136 {137 event: 'CollectionChanged',138 returnValues: {139 collectionId: collectionAddress,140 },141 },142 ]);143 expect(subEvents).to.containSubset([{method: 'PropertyPermissionSet'}]);144 unsubscribe();145}146147async function testAllowListAddressAddedAndRemoved(helper: EthUniqueHelper, mode: TCollectionMode) {148 const owner = await helper.eth.createAccountWithBalance(donor);149 const user = helper.ethCrossAccount.createAccount();150 const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();151 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);152 const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);153 const ethEvents: any[] = [];154 collectionHelper.events.allEvents((_: any, event: any) => {155 ethEvents.push(event);156 });157158 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['AllowListAddressAdded', 'AllowListAddressRemoved']}]);159 {160 await collection.methods.addToCollectionAllowListCross(user).send({from: owner});161 await helper.wait.newBlocks(1);162 expect(ethEvents).to.containSubset([163 {164 event: 'CollectionChanged',165 returnValues: {166 collectionId: collectionAddress,167 },168 },169 ]);170 expect(subEvents).to.containSubset([{method: 'AllowListAddressAdded'}]);171 clearEvents(ethEvents, subEvents);172 }173 {174 await collection.methods.removeFromCollectionAllowListCross(user).send({from: owner});175 await helper.wait.newBlocks(1);176 expect(ethEvents).to.containSubset([177 {178 event: 'CollectionChanged',179 returnValues: {180 collectionId: collectionAddress,181 },182 },183 ]);184 expect(subEvents).to.containSubset([{method: 'AllowListAddressRemoved'}]);185 }186 unsubscribe();187}188189async function testCollectionAdminAddedAndRemoved(helper: EthUniqueHelper, mode: TCollectionMode) {190 const owner = await helper.eth.createAccountWithBalance(donor);191 const user = helper.ethCrossAccount.createAccount();192 const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();193 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);194 const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);195 const ethEvents: any = [];196 collectionHelper.events.allEvents((_: any, event: any) => {197 ethEvents.push(event);198 });199 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionAdminAdded', 'CollectionAdminRemoved']}]);200 {201 await collection.methods.addCollectionAdminCross(user).send({from: owner});202 await helper.wait.newBlocks(1);203 expect(ethEvents).to.containSubset([204 {205 event: 'CollectionChanged',206 returnValues: {207 collectionId: collectionAddress,208 },209 },210 ]);211 expect(subEvents).to.containSubset([{method: 'CollectionAdminAdded'}]);212 clearEvents(ethEvents, subEvents);213 }214 {215 await collection.methods.removeCollectionAdminCross(user).send({from: owner});216 await helper.wait.newBlocks(1);217 expect(ethEvents).to.containSubset([218 {219 event: 'CollectionChanged',220 returnValues: {221 collectionId: collectionAddress,222 },223 },224 ]);225 expect(subEvents).to.containSubset([{method: 'CollectionAdminRemoved'}]);226 }227 unsubscribe();228}229230async function testCollectionLimitSet(helper: EthUniqueHelper, mode: TCollectionMode) {231 const owner = await helper.eth.createAccountWithBalance(donor);232 const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();233 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);234 const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);235 const ethEvents: any = [];236 collectionHelper.events.allEvents((_: any, event: any) => {237 ethEvents.push(event);238 });239 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionLimitSet']}]);240 {241 await collection.methods.setCollectionLimit({field: CollectionLimitField.OwnerCanTransfer, value: {status: true, value: 0}}).send({from: owner});242 await helper.wait.newBlocks(1);243 expect(ethEvents).to.containSubset([244 {245 event: 'CollectionChanged',246 returnValues: {247 collectionId: collectionAddress,248 },249 },250 ]);251 expect(subEvents).to.containSubset([{method: 'CollectionLimitSet'}]);252 }253 unsubscribe();254}255256async function testCollectionOwnerChanged(helper: EthUniqueHelper, mode: TCollectionMode) {257 const owner = await helper.eth.createAccountWithBalance(donor);258 const newOwner = helper.ethCrossAccount.createAccount();259 const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();260 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);261 const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);262 const ethEvents: any = [];263 collectionHelper.events.allEvents((_: any, event: any) => {264 ethEvents.push(event);265 });266 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionOwnerChanged']}]);267 {268 await collection.methods.changeCollectionOwnerCross(newOwner).send({from: owner});269 await helper.wait.newBlocks(1);270 expect(ethEvents).to.containSubset([271 {272 event: 'CollectionChanged',273 returnValues: {274 collectionId: collectionAddress,275 },276 },277 ]);278 expect(subEvents).to.containSubset([{method: 'CollectionOwnerChanged'}]);279 }280 unsubscribe();281}282283async function testCollectionPermissionSet(helper: EthUniqueHelper, mode: TCollectionMode) {284 const owner = await helper.eth.createAccountWithBalance(donor);285 const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();286 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);287 const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);288 const ethEvents: any = [];289 collectionHelper.events.allEvents((_: any, event: any) => {290 ethEvents.push(event);291 });292 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionPermissionSet']}]);293 {294 await collection.methods.setCollectionMintMode(true).send({from: owner});295 await helper.wait.newBlocks(1);296 expect(ethEvents).to.containSubset([297 {298 event: 'CollectionChanged',299 returnValues: {300 collectionId: collectionAddress,301 },302 },303 ]);304 expect(subEvents).to.containSubset([{method: 'CollectionPermissionSet'}]);305 clearEvents(ethEvents, subEvents);306 }307 {308 await collection.methods.setCollectionAccess(1).send({from: owner});309 await helper.wait.newBlocks(1);310 expect(ethEvents).to.containSubset([311 {312 event: 'CollectionChanged',313 returnValues: {314 collectionId: collectionAddress,315 },316 },317 ]);318 expect(subEvents).to.containSubset([{method: 'CollectionPermissionSet'}]);319 }320 unsubscribe();321}322323async function testCollectionSponsorSetAndConfirmedAndThenRemoved(helper: EthUniqueHelper, mode: TCollectionMode) {324 const owner = await helper.eth.createAccountWithBalance(donor);325 const sponsor = await helper.ethCrossAccount.createAccountWithBalance(donor);326 const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();327 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);328 const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);329 const ethEvents: any = [];330 collectionHelper.events.allEvents((_: any, event: any) => {331 ethEvents.push(event);332 });333 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{334 section: 'common', names: ['CollectionSponsorSet', 'SponsorshipConfirmed', 'CollectionSponsorRemoved',335 ]}]);336 {337 await collection.methods.setCollectionSponsorCross(sponsor).send({from: owner});338 await helper.wait.newBlocks(1);339 expect(ethEvents).to.containSubset([{340 event: 'CollectionChanged',341 returnValues: {342 collectionId: collectionAddress,343 },344 }]);345 expect(subEvents).to.containSubset([{method: 'CollectionSponsorSet'}]);346 clearEvents(ethEvents, subEvents);347 }348 {349 await collection.methods.confirmCollectionSponsorship().send({from: sponsor.eth});350 await helper.wait.newBlocks(1);351 expect(ethEvents).to.containSubset([352 {353 event: 'CollectionChanged',354 returnValues: {355 collectionId: collectionAddress,356 },357 },358 ]);359 expect(subEvents).to.containSubset([{method: 'SponsorshipConfirmed'}]);360 clearEvents(ethEvents, subEvents);361 }362 {363 await collection.methods.removeCollectionSponsor().send({from: owner});364 await helper.wait.newBlocks(1);365 expect(ethEvents).to.containSubset([366 {367 event: 'CollectionChanged',368 returnValues: {369 collectionId: collectionAddress,370 },371 },372 ]);373 expect(subEvents).to.containSubset([{method: 'CollectionSponsorRemoved'}]);374 }375 unsubscribe();376}377378async function testTokenPropertySetAndDeleted(helper: EthUniqueHelper, mode: TCollectionMode) {379 const owner = await helper.eth.createAccountWithBalance(donor);380 const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();381 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);382 const result = await collection.methods.mint(owner).send({from: owner});383 const tokenId = result.events.Transfer.returnValues.tokenId;384 await collection.methods.setTokenPropertyPermissions([385 ['A', [386 [TokenPermissionField.Mutable, true],387 [TokenPermissionField.TokenOwner, true],388 [TokenPermissionField.CollectionAdmin, true]],389 ],390 ]).send({from: owner});391392 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['TokenPropertySet', 'TokenPropertyDeleted']}]);393 {394 const result = await collection.methods.setProperties(tokenId, [{key: 'A', value: [1,2,3]}]).send({from: owner});395 await helper.wait.newBlocks(1);396 expect(result.events.TokenChanged).to.be.like({397 event: 'TokenChanged',398 returnValues: {399 tokenId: tokenId,400 },401 });402 expect(subEvents).to.containSubset([{method: 'TokenPropertySet'}]);403 clearEvents(null, subEvents);404 }405 {406 const result = await collection.methods.deleteProperties(tokenId, ['A']).send({from: owner});407 await helper.wait.newBlocks(1);408 expect(result.events.TokenChanged).to.be.like({409 event: 'TokenChanged',410 returnValues: {411 tokenId: tokenId,412 },413 });414 expect(subEvents).to.containSubset([{method: 'TokenPropertyDeleted'}]);415 }416 unsubscribe();417}418419describe('[FT] Sync sub & eth events', () => {420 const mode: TCollectionMode = 'ft';421422 itEth('CollectionCreated and CollectionDestroyed events', async ({helper}) => {423 await testCollectionCreatedAndDestroy(helper, mode);424 });425426 itEth('CollectionChanged event for CollectionPropertySet and CollectionPropertyDeleted', async ({helper}) => {427 await testCollectionPropertySetAndDeleted(helper, mode);428 });429430 itEth('CollectionChanged event for AllowListAddressAdded, AllowListAddressRemoved', async ({helper}) => {431 await testAllowListAddressAddedAndRemoved(helper, mode);432 });433434 itEth('CollectionChanged event for CollectionAdminAdded, CollectionAdminRemoved', async ({helper}) => {435 await testCollectionAdminAddedAndRemoved(helper, mode);436 });437438 itEth('CollectionChanged event for CollectionLimitSet', async ({helper}) => {439 await testCollectionLimitSet(helper, mode);440 });441442 itEth('CollectionChanged event for CollectionOwnerChanged', async ({helper}) => {443 await testCollectionOwnerChanged(helper, mode);444 });445446 itEth('CollectionChanged event for CollectionPermissionSet', async ({helper}) => {447 await testCollectionPermissionSet(helper, mode);448 });449450 itEth('CollectionChanged event for CollectionSponsorSet, SponsorshipConfirmed, CollectionSponsorRemoved', async ({helper}) => {451 await testCollectionSponsorSetAndConfirmedAndThenRemoved(helper, mode);452 });453});454455describe('[NFT] Sync sub & eth events', () => {456 const mode: TCollectionMode = 'nft';457458 itEth('CollectionCreated and CollectionDestroyed events', async ({helper}) => {459 await testCollectionCreatedAndDestroy(helper, mode);460 });461462 itEth('CollectionChanged event for CollectionPropertySet and CollectionPropertyDeleted', async ({helper}) => {463 await testCollectionPropertySetAndDeleted(helper, mode);464 });465466 itEth('CollectionChanged event for PropertyPermissionSet', async ({helper}) => {467 await testPropertyPermissionSet(helper, mode);468 });469470 itEth('CollectionChanged event for AllowListAddressAdded, AllowListAddressRemoved', async ({helper}) => {471 await testAllowListAddressAddedAndRemoved(helper, mode);472 });473474 itEth('CollectionChanged event for CollectionAdminAdded, CollectionAdminRemoved', async ({helper}) => {475 await testCollectionAdminAddedAndRemoved(helper, mode);476 });477478 itEth('CollectionChanged event for CollectionLimitSet', async ({helper}) => {479 await testCollectionLimitSet(helper, mode);480 });481482 itEth('CollectionChanged event for CollectionOwnerChanged', async ({helper}) => {483 await testCollectionOwnerChanged(helper, mode);484 });485486 itEth('CollectionChanged event for CollectionPermissionSet', async ({helper}) => {487 await testCollectionPermissionSet(helper, mode);488 });489490 itEth('CollectionChanged event for CollectionSponsorSet, SponsorshipConfirmed, CollectionSponsorRemoved', async ({helper}) => {491 await testCollectionSponsorSetAndConfirmedAndThenRemoved(helper, mode);492 });493494 itEth('CollectionChanged event for TokenPropertySet, TokenPropertyDeleted', async ({helper}) => {495 await testTokenPropertySetAndDeleted(helper, mode);496 });497});498499describe('[RFT] Sync sub & eth events', () => {500 const mode: TCollectionMode = 'rft';501502 before(async function() {503 await usingEthPlaygrounds((helper) => {504 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);505 return Promise.resolve();506 });507 });508509 itEth('CollectionCreated and CollectionDestroyed events', async ({helper}) => {510 await testCollectionCreatedAndDestroy(helper, mode);511 });512513 itEth('CollectionChanged event for CollectionPropertySet and CollectionPropertyDeleted', async ({helper}) => {514 await testCollectionPropertySetAndDeleted(helper, mode);515 });516517 itEth('CollectionChanged event for PropertyPermissionSet', async ({helper}) => {518 await testPropertyPermissionSet(helper, mode);519 });520521 itEth('CollectionChanged event for AllowListAddressAdded, AllowListAddressRemoved', async ({helper}) => {522 await testAllowListAddressAddedAndRemoved(helper, mode);523 });524525 itEth('CollectionChanged event for CollectionAdminAdded, CollectionAdminRemoved', async ({helper}) => {526 await testCollectionAdminAddedAndRemoved(helper, mode);527 });528529 itEth('CollectionChanged event for CollectionLimitSet', async ({helper}) => {530 await testCollectionLimitSet(helper, mode);531 });532533 itEth('CollectionChanged event for CollectionOwnerChanged', async ({helper}) => {534 await testCollectionOwnerChanged(helper, mode);535 });536537 itEth('CollectionChanged event for CollectionPermissionSet', async ({helper}) => {538 await testCollectionPermissionSet(helper, mode);539 });540541 itEth('CollectionChanged event for CollectionSponsorSet, SponsorshipConfirmed, CollectionSponsorRemoved', async ({helper}) => {542 await testCollectionSponsorSetAndConfirmedAndThenRemoved(helper, mode);543 });544545 itEth('CollectionChanged event for TokenPropertySet, TokenPropertyDeleted', async ({helper}) => {546 await testTokenPropertySetAndDeleted(helper, mode);547 });548});