1234567891011121314151617import {expect} from 'chai';18import {IKeyringPair} from '@polkadot/types/types';19import {EthUniqueHelper, itEth, usingEthPlaygrounds} from './util';20import {IEvent, TCollectionMode} from '../util/playgrounds/types';21import {Pallets, requirePalletsOrSkip} from '../util';22import {CollectionLimitField, TokenPermissionField, NormalizedEvent} from './util/playgrounds/types';2324let donor: IKeyringPair;2526before(async function () {27 await usingEthPlaygrounds(async (_helper, privateKey) => {28 donor = await privateKey({filename: __filename});29 });30});3132function clearEvents(ethEvents: NormalizedEvent[] | null, subEvents: IEvent[]) {33 if (ethEvents !== null) {34 ethEvents.splice(0);35 }36 subEvents.splice(0);37}3839async function testCollectionCreatedAndDestroy(helper: EthUniqueHelper, mode: TCollectionMode) {40 const owner = await helper.eth.createAccountWithBalance(donor);41 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionCreated', 'CollectionDestroyed']}]);42 const {collectionAddress, events: ethEvents} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');43 await helper.wait.newBlocks(1);44 {45 expect(ethEvents).to.containSubset([46 {47 event: 'CollectionCreated',48 args: {49 owner: owner,50 collectionId: collectionAddress,51 },52 },53 ]);54 expect(subEvents).to.containSubset([{method: 'CollectionCreated'}]);55 clearEvents(ethEvents, subEvents);56 }57 {58 const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);59 const result = await collectionHelper.methods.destroyCollection(collectionAddress).send({from:owner});60 await helper.wait.newBlocks(1);61 expect(result.events).to.containSubset({62 CollectionDestroyed: {63 returnValues: {64 collectionId: collectionAddress,65 },66 },67 });68 expect(subEvents).to.containSubset([{method: 'CollectionDestroyed'}]);69 }70 unsubscribe();71}7273async function testCollectionPropertySetAndDeleted(helper: EthUniqueHelper, mode: TCollectionMode) {74 const owner = await helper.eth.createAccountWithBalance(donor);75 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');76 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);77 const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);7879 const ethEvents: any = [];80 collectionHelper.events.allEvents((_: any, event: any) => {81 ethEvents.push(event);82 });83 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionPropertySet', 'CollectionPropertyDeleted']}]);84 {85 await collection.methods.setCollectionProperties([{key: 'A', value: [0,1,2,3]}]).send({from:owner});86 await helper.wait.newBlocks(1);87 expect(ethEvents).to.containSubset([88 {89 event: 'CollectionChanged',90 returnValues: {91 collectionId: collectionAddress,92 },93 },94 ]);95 expect(subEvents).to.containSubset([{method: 'CollectionPropertySet'}]);96 clearEvents(ethEvents, subEvents);97 }98 {99 await collection.methods.deleteCollectionProperties(['A']).send({from:owner});100 await helper.wait.newBlocks(1);101 expect(ethEvents).to.containSubset([102 {103 event: 'CollectionChanged',104 returnValues: {105 collectionId: collectionAddress,106 },107 },108 ]);109 expect(subEvents).to.containSubset([{method: 'CollectionPropertyDeleted'}]);110 }111 unsubscribe();112}113114async function testPropertyPermissionSet(helper: EthUniqueHelper, mode: TCollectionMode) {115 const owner = await helper.eth.createAccountWithBalance(donor);116 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');117 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);118 const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);119 const ethEvents: any = [];120 collectionHelper.events.allEvents((_: any, event: any) => {121 ethEvents.push(event);122 });123 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['PropertyPermissionSet']}]);124 await collection.methods.setTokenPropertyPermissions([125 ['A', [126 [TokenPermissionField.Mutable, true],127 [TokenPermissionField.TokenOwner, true],128 [TokenPermissionField.CollectionAdmin, true]],129 ],130 ]).send({from: owner});131 await helper.wait.newBlocks(1);132 expect(ethEvents).to.containSubset([133 {134 event: 'CollectionChanged',135 returnValues: {136 collectionId: collectionAddress,137 },138 },139 ]);140 expect(subEvents).to.containSubset([{method: 'PropertyPermissionSet'}]);141 unsubscribe();142}143144async function testAllowListAddressAddedAndRemoved(helper: EthUniqueHelper, mode: TCollectionMode) {145 const owner = await helper.eth.createAccountWithBalance(donor);146 const user = helper.ethCrossAccount.createAccount();147 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');148 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);149 const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);150 const ethEvents: any[] = [];151 collectionHelper.events.allEvents((_: any, event: any) => {152 ethEvents.push(event);153 });154155 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['AllowListAddressAdded', 'AllowListAddressRemoved']}]);156 {157 await collection.methods.addToCollectionAllowListCross(user).send({from: owner});158 await helper.wait.newBlocks(1);159 expect(ethEvents).to.containSubset([160 {161 event: 'CollectionChanged',162 returnValues: {163 collectionId: collectionAddress,164 },165 },166 ]);167 expect(subEvents).to.containSubset([{method: 'AllowListAddressAdded'}]);168 clearEvents(ethEvents, subEvents);169 }170 {171 await collection.methods.removeFromCollectionAllowListCross(user).send({from: owner});172 await helper.wait.newBlocks(1);173 expect(ethEvents).to.containSubset([174 {175 event: 'CollectionChanged',176 returnValues: {177 collectionId: collectionAddress,178 },179 },180 ]);181 expect(subEvents).to.containSubset([{method: 'AllowListAddressRemoved'}]);182 }183 unsubscribe();184}185186async function testCollectionAdminAddedAndRemoved(helper: EthUniqueHelper, mode: TCollectionMode) {187 const owner = await helper.eth.createAccountWithBalance(donor);188 const user = helper.ethCrossAccount.createAccount();189 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');190 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);191 const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);192 const ethEvents: any = [];193 collectionHelper.events.allEvents((_: any, event: any) => {194 ethEvents.push(event);195 });196 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionAdminAdded', 'CollectionAdminRemoved']}]);197 {198 await collection.methods.addCollectionAdminCross(user).send({from: owner});199 await helper.wait.newBlocks(1);200 expect(ethEvents).to.containSubset([201 {202 event: 'CollectionChanged',203 returnValues: {204 collectionId: collectionAddress,205 },206 },207 ]);208 expect(subEvents).to.containSubset([{method: 'CollectionAdminAdded'}]);209 clearEvents(ethEvents, subEvents);210 }211 {212 await collection.methods.removeCollectionAdminCross(user).send({from: owner});213 await helper.wait.newBlocks(1);214 expect(ethEvents).to.containSubset([215 {216 event: 'CollectionChanged',217 returnValues: {218 collectionId: collectionAddress,219 },220 },221 ]);222 expect(subEvents).to.containSubset([{method: 'CollectionAdminRemoved'}]);223 }224 unsubscribe();225}226227async function testCollectionLimitSet(helper: EthUniqueHelper, mode: TCollectionMode) {228 const owner = await helper.eth.createAccountWithBalance(donor);229 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');230 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);231 const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);232 const ethEvents: any = [];233 collectionHelper.events.allEvents((_: any, event: any) => {234 ethEvents.push(event);235 });236 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionLimitSet']}]);237 {238 await collection.methods.setCollectionLimit({field: CollectionLimitField.OwnerCanTransfer, value: {status: true, value: 0}}).send({from: owner});239 await helper.wait.newBlocks(1);240 expect(ethEvents).to.containSubset([241 {242 event: 'CollectionChanged',243 returnValues: {244 collectionId: collectionAddress,245 },246 },247 ]);248 expect(subEvents).to.containSubset([{method: 'CollectionLimitSet'}]);249 }250 unsubscribe();251}252253async function testCollectionOwnerChanged(helper: EthUniqueHelper, mode: TCollectionMode) {254 const owner = await helper.eth.createAccountWithBalance(donor);255 const newOwner = helper.ethCrossAccount.createAccount();256 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');257 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);258 const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);259 const ethEvents: any = [];260 collectionHelper.events.allEvents((_: any, event: any) => {261 ethEvents.push(event);262 });263 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionOwnerChanged']}]);264 {265 await collection.methods.changeCollectionOwnerCross(newOwner).send({from: owner});266 await helper.wait.newBlocks(1);267 expect(ethEvents).to.containSubset([268 {269 event: 'CollectionChanged',270 returnValues: {271 collectionId: collectionAddress,272 },273 },274 ]);275 expect(subEvents).to.containSubset([{method: 'CollectionOwnerChanged'}]);276 }277 unsubscribe();278}279280async function testCollectionPermissionSet(helper: EthUniqueHelper, mode: TCollectionMode) {281 const owner = await helper.eth.createAccountWithBalance(donor);282 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');283 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);284 const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);285 const ethEvents: any = [];286 collectionHelper.events.allEvents((_: any, event: any) => {287 ethEvents.push(event);288 });289 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionPermissionSet']}]);290 {291 await collection.methods.setCollectionMintMode(true).send({from: owner});292 await helper.wait.newBlocks(1);293 expect(ethEvents).to.containSubset([294 {295 event: 'CollectionChanged',296 returnValues: {297 collectionId: collectionAddress,298 },299 },300 ]);301 expect(subEvents).to.containSubset([{method: 'CollectionPermissionSet'}]);302 clearEvents(ethEvents, subEvents);303 }304 {305 await collection.methods.setCollectionAccess(1).send({from: owner});306 await helper.wait.newBlocks(1);307 expect(ethEvents).to.containSubset([308 {309 event: 'CollectionChanged',310 returnValues: {311 collectionId: collectionAddress,312 },313 },314 ]);315 expect(subEvents).to.containSubset([{method: 'CollectionPermissionSet'}]);316 }317 unsubscribe();318}319320async function testCollectionSponsorSetAndConfirmedAndThenRemoved(helper: EthUniqueHelper, mode: TCollectionMode) {321 const owner = await helper.eth.createAccountWithBalance(donor);322 const sponsor = await helper.ethCrossAccount.createAccountWithBalance(donor);323 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');324 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);325 const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);326 const ethEvents: any = [];327 collectionHelper.events.allEvents((_: any, event: any) => {328 ethEvents.push(event);329 });330 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{331 section: 'common', names: ['CollectionSponsorSet', 'SponsorshipConfirmed', 'CollectionSponsorRemoved',332 ]}]);333 {334 await collection.methods.setCollectionSponsorCross(sponsor).send({from: owner});335 await helper.wait.newBlocks(1);336 expect(ethEvents).to.containSubset([{337 event: 'CollectionChanged',338 returnValues: {339 collectionId: collectionAddress,340 },341 }]);342 expect(subEvents).to.containSubset([{method: 'CollectionSponsorSet'}]);343 clearEvents(ethEvents, subEvents);344 }345 {346 await collection.methods.confirmCollectionSponsorship().send({from: sponsor.eth});347 await helper.wait.newBlocks(1);348 expect(ethEvents).to.containSubset([349 {350 event: 'CollectionChanged',351 returnValues: {352 collectionId: collectionAddress,353 },354 },355 ]);356 expect(subEvents).to.containSubset([{method: 'SponsorshipConfirmed'}]);357 clearEvents(ethEvents, subEvents);358 }359 {360 await collection.methods.removeCollectionSponsor().send({from: owner});361 await helper.wait.newBlocks(1);362 expect(ethEvents).to.containSubset([363 {364 event: 'CollectionChanged',365 returnValues: {366 collectionId: collectionAddress,367 },368 },369 ]);370 expect(subEvents).to.containSubset([{method: 'CollectionSponsorRemoved'}]);371 }372 unsubscribe();373}374375async function testTokenPropertySetAndDeleted(helper: EthUniqueHelper, mode: TCollectionMode) {376 const owner = await helper.eth.createAccountWithBalance(donor);377 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');378 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);379 const result = await collection.methods.mint(owner).send({from: owner});380 const tokenId = result.events.Transfer.returnValues.tokenId;381 await collection.methods.setTokenPropertyPermissions([382 ['A', [383 [TokenPermissionField.Mutable, true],384 [TokenPermissionField.TokenOwner, true],385 [TokenPermissionField.CollectionAdmin, true]],386 ],387 ]).send({from: owner});388389 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['TokenPropertySet', 'TokenPropertyDeleted']}]);390 {391 const result = await collection.methods.setProperties(tokenId, [{key: 'A', value: [1,2,3]}]).send({from: owner});392 await helper.wait.newBlocks(1);393 expect(result.events.TokenChanged).to.be.like({394 event: 'TokenChanged',395 returnValues: {396 collectionId: collectionAddress,397 tokenId: tokenId,398 },399 });400 expect(subEvents).to.containSubset([{method: 'TokenPropertySet'}]);401 clearEvents(null, subEvents);402 }403 {404 const result = await collection.methods.deleteProperties(tokenId, ['A']).send({from: owner});405 await helper.wait.newBlocks(1);406 expect(result.events.TokenChanged).to.be.like({407 event: 'TokenChanged',408 returnValues: {409 collectionId: collectionAddress,410 tokenId: tokenId,411 },412 });413 expect(subEvents).to.containSubset([{method: 'TokenPropertyDeleted'}]);414 }415 unsubscribe();416}417418describe('[FT] Sync sub & eth events', () => {419 const mode: TCollectionMode = 'ft';420421 itEth('CollectionCreated and CollectionDestroyed events', async ({helper}) => {422 await testCollectionCreatedAndDestroy(helper, mode);423 });424425 itEth('CollectionChanged event for CollectionPropertySet and CollectionPropertyDeleted', async ({helper}) => {426 await testCollectionPropertySetAndDeleted(helper, mode);427 });428429 itEth('CollectionChanged event for AllowListAddressAdded, AllowListAddressRemoved', async ({helper}) => {430 await testAllowListAddressAddedAndRemoved(helper, mode);431 });432433 itEth('CollectionChanged event for CollectionAdminAdded, CollectionAdminRemoved', async ({helper}) => {434 await testCollectionAdminAddedAndRemoved(helper, mode);435 });436437 itEth('CollectionChanged event for CollectionLimitSet', async ({helper}) => {438 await testCollectionLimitSet(helper, mode);439 });440441 itEth('CollectionChanged event for CollectionOwnerChanged', async ({helper}) => {442 await testCollectionOwnerChanged(helper, mode);443 });444445 itEth('CollectionChanged event for CollectionPermissionSet', async ({helper}) => {446 await testCollectionPermissionSet(helper, mode);447 });448449 itEth('CollectionChanged event for CollectionSponsorSet, SponsorshipConfirmed, CollectionSponsorRemoved', async ({helper}) => {450 await testCollectionSponsorSetAndConfirmedAndThenRemoved(helper, mode);451 });452});453454describe('[NFT] Sync sub & eth events', () => {455 const mode: TCollectionMode = 'nft';456457 itEth('CollectionCreated and CollectionDestroyed events', async ({helper}) => {458 await testCollectionCreatedAndDestroy(helper, mode);459 });460461 itEth('CollectionChanged event for CollectionPropertySet and CollectionPropertyDeleted', async ({helper}) => {462 await testCollectionPropertySetAndDeleted(helper, mode);463 });464465 itEth('CollectionChanged event for PropertyPermissionSet', async ({helper}) => {466 await testPropertyPermissionSet(helper, mode);467 });468469 itEth('CollectionChanged event for AllowListAddressAdded, AllowListAddressRemoved', async ({helper}) => {470 await testAllowListAddressAddedAndRemoved(helper, mode);471 });472473 itEth('CollectionChanged event for CollectionAdminAdded, CollectionAdminRemoved', async ({helper}) => {474 await testCollectionAdminAddedAndRemoved(helper, mode);475 });476477 itEth('CollectionChanged event for CollectionLimitSet', async ({helper}) => {478 await testCollectionLimitSet(helper, mode);479 });480481 itEth('CollectionChanged event for CollectionOwnerChanged', async ({helper}) => {482 await testCollectionOwnerChanged(helper, mode);483 });484485 itEth('CollectionChanged event for CollectionPermissionSet', async ({helper}) => {486 await testCollectionPermissionSet(helper, mode);487 });488489 itEth('CollectionChanged event for CollectionSponsorSet, SponsorshipConfirmed, CollectionSponsorRemoved', async ({helper}) => {490 await testCollectionSponsorSetAndConfirmedAndThenRemoved(helper, mode);491 });492493 itEth('CollectionChanged event for TokenPropertySet, TokenPropertyDeleted', async ({helper}) => {494 await testTokenPropertySetAndDeleted(helper, mode);495 });496});497498describe('[RFT] Sync sub & eth events', () => {499 const mode: TCollectionMode = 'rft';500501 before(async function() {502 await usingEthPlaygrounds(async (helper, privateKey) => {503 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);504 const _donor = await privateKey({filename: __filename});505 });506 });507508 itEth('CollectionCreated and CollectionDestroyed events', async ({helper}) => {509 await testCollectionCreatedAndDestroy(helper, mode);510 });511512 itEth('CollectionChanged event for CollectionPropertySet and CollectionPropertyDeleted', async ({helper}) => {513 await testCollectionPropertySetAndDeleted(helper, mode);514 });515516 itEth('CollectionChanged event for PropertyPermissionSet', async ({helper}) => {517 await testPropertyPermissionSet(helper, mode);518 });519520 itEth('CollectionChanged event for AllowListAddressAdded, AllowListAddressRemoved', async ({helper}) => {521 await testAllowListAddressAddedAndRemoved(helper, mode);522 });523524 itEth('CollectionChanged event for CollectionAdminAdded, CollectionAdminRemoved', async ({helper}) => {525 await testCollectionAdminAddedAndRemoved(helper, mode);526 });527528 itEth('CollectionChanged event for CollectionLimitSet', async ({helper}) => {529 await testCollectionLimitSet(helper, mode);530 });531532 itEth('CollectionChanged event for CollectionOwnerChanged', async ({helper}) => {533 await testCollectionOwnerChanged(helper, mode);534 });535536 itEth('CollectionChanged event for CollectionPermissionSet', async ({helper}) => {537 await testCollectionPermissionSet(helper, mode);538 });539540 itEth('CollectionChanged event for CollectionSponsorSet, SponsorshipConfirmed, CollectionSponsorRemoved', async ({helper}) => {541 await testCollectionSponsorSetAndConfirmedAndThenRemoved(helper, mode);542 });543544 itEth('CollectionChanged event for TokenPropertySet, TokenPropertyDeleted', async ({helper}) => {545 await testTokenPropertySetAndDeleted(helper, mode);546 });547});