1import {expect} from 'chai';2import usingApi, {executeTransaction} from '../substrate/substrate-api';3import {4 addCollectionAdminExpectSuccess,5 createCollectionExpectSuccess,6 createItemExpectSuccess,7 getCreateCollectionResult,8 transferExpectSuccess,9} from '../util/helpers';10import {IKeyringPair} from '@polkadot/types/types';1112let alice: IKeyringPair;13let bob: IKeyringPair;14let charlie: IKeyringPair;1516describe('Composite Properties Test', () => {17 before(async () => {18 await usingApi(async (api, privateKeyWrapper) => {19 alice = privateKeyWrapper('//Alice');20 bob = privateKeyWrapper('//Bob');21 });22 });2324 it('Makes sure collectionById supplies required fields', async () => {25 await usingApi(async api => {26 const collectionId = await createCollectionExpectSuccess();2728 const collectionOption = await api.rpc.unique.collectionById(collectionId);29 expect(collectionOption.isSome).to.be.true;30 let collection = collectionOption.unwrap();31 expect(collection.tokenPropertyPermissions.toHuman()).to.be.empty;32 expect(collection.properties.toHuman()).to.be.empty;3334 const propertyPermissions = [35 {key: 'mindgame', permission: {collectionAdmin: true, mutable: false, tokenOwner: true}},36 {key: 'skullduggery', permission: {collectionAdmin: false, mutable: true, tokenOwner: false}},37 ];38 await expect(executeTransaction(39 api, 40 alice, 41 api.tx.unique.setPropertyPermissions(collectionId, propertyPermissions), 42 )).to.not.be.rejected;4344 const collectionProperties = [45 {key: 'black_hole', value: 'LIGO'},46 {key: 'electron', value: 'come bond'}, 47 ];48 await expect(executeTransaction(49 api, 50 alice, 51 api.tx.unique.setCollectionProperties(collectionId, collectionProperties), 52 )).to.not.be.rejected;5354 collection = (await api.rpc.unique.collectionById(collectionId)).unwrap();55 expect(collection.tokenPropertyPermissions.toHuman()).to.be.deep.equal(propertyPermissions);56 expect(collection.properties.toHuman()).to.be.deep.equal(collectionProperties);57 });58 });59});60616263describe('Integration Test: Collection Properties', () => {64 before(async () => {65 await usingApi(async (api, privateKeyWrapper) => {66 alice = privateKeyWrapper('//Alice');67 bob = privateKeyWrapper('//Bob');68 });69 });7071 it('Reads properties from a collection', async () => {72 await usingApi(async api => {73 const collection = await createCollectionExpectSuccess();74 const properties = (await api.query.common.collectionProperties(collection)).toJSON();75 expect(properties.map).to.be.empty;76 expect(properties.consumedSpace).to.equal(0);77 });78 });7980 it('Sets properties for a collection', async () => {81 await usingApi(async api => {82 const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: 'NFT'}));83 const {collectionId} = getCreateCollectionResult(events);8485 86 await expect(executeTransaction(87 api, 88 bob, 89 api.tx.unique.setCollectionProperties(collectionId, [{key: 'electron', value: 'come bond'}]), 90 )).to.not.be.rejected;9192 await addCollectionAdminExpectSuccess(bob, collectionId, alice.address);9394 95 await expect(executeTransaction(96 api, 97 alice, 98 api.tx.unique.setCollectionProperties(collectionId, [{key: 'black_hole'}]), 99 )).to.not.be.rejected;100101 const properties = (await api.rpc.unique.collectionProperties(collectionId, ['electron', 'black_hole'])).toHuman();102 expect(properties).to.be.deep.equal([103 {key: 'electron', value: 'come bond'},104 {key: 'black_hole', value: ''},105 ]);106 });107 });108109 it('Changes properties of a collection', async () => {110 await usingApi(async api => {111 const collection = await createCollectionExpectSuccess();112113 await expect(executeTransaction(114 api, 115 alice, 116 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole'}]), 117 )).to.not.be.rejected;118119 120 await expect(executeTransaction(121 api, 122 alice, 123 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'bonded'}, {key: 'black_hole', value: 'LIGO'}]), 124 )).to.not.be.rejected;125126 const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();127 expect(properties).to.be.deep.equal([128 {key: 'electron', value: 'bonded'},129 {key: 'black_hole', value: 'LIGO'},130 ]);131 });132 });133134 it('Deletes properties of a collection', async () => {135 await usingApi(async api => {136 const collection = await createCollectionExpectSuccess();137138 await expect(executeTransaction(139 api, 140 alice, 141 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]), 142 )).to.not.be.rejected;143144 await expect(executeTransaction(145 api, 146 alice, 147 api.tx.unique.deleteCollectionProperties(collection, ['electron']), 148 )).to.not.be.rejected;149150 const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();151 expect(properties).to.be.deep.equal([152 {key: 'black_hole', value: 'LIGO'},153 ]);154 });155 });156});157158describe('Negative Integration Test: Collection Properties', () => {159 before(async () => {160 await usingApi(async (api, privateKeyWrapper) => {161 alice = privateKeyWrapper('//Alice');162 bob = privateKeyWrapper('//Bob');163 });164 });165 166 it('Fails to set properties in a collection if not its onwer/administrator', async () => {167 await usingApi(async api => {168 const collection = await createCollectionExpectSuccess();169170 await expect(executeTransaction(171 api, 172 bob, 173 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]), 174 )).to.be.rejectedWith(/common\.NoPermission/);175 176 const properties = (await api.query.common.collectionProperties(collection)).toJSON();177 expect(properties.map).to.be.empty;178 expect(properties.consumedSpace).to.equal(0);179 });180 });181 182 it('Fails to set properties that exceed the limits', async () => {183 await usingApi(async api => {184 const collection = await createCollectionExpectSuccess();185 const spaceLimit = (await api.query.common.collectionProperties(collection)).toJSON().spaceLimit as number; 186187 188 {189 console.error = () => {};190 await expect(executeTransaction(191 api, 192 alice, 193 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 9))}]), 194 )).to.be.rejected;195 }196197 let properties = (await api.rpc.unique.collectionProperties(collection, ['electron'])).toJSON();198 expect(properties).to.be.empty;199200 await expect(executeTransaction(201 api, 202 alice, 203 api.tx.unique.setCollectionProperties(collection, [204 {key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 18))}, 205 {key: 'black_hole', value: '0'.repeat(Math.ceil(spaceLimit! / 2))}, 206 ]), 207 )).to.be.rejectedWith(/common\.NoSpaceForProperty/);208209 properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black hole'])).toJSON();210 expect(properties).to.be.empty;211 });212 });213 214 it('Fails to set more properties than it is allowed', async () => {215 await usingApi(async api => {216 const collection = await createCollectionExpectSuccess();217218 const propertiesToBeSet = [];219 for (let i = 0; i < 65; i++) {220 propertiesToBeSet.push({221 key: 'electron_' + i,222 value: Math.random() > 0.5 ? 'high' : 'low',223 });224 }225226 await expect(executeTransaction(227 api, 228 alice, 229 api.tx.unique.setCollectionProperties(collection, propertiesToBeSet), 230 )).to.be.rejectedWith(/common\.PropertyLimitReached/);231232 const properties = (await api.query.common.collectionProperties(collection)).toJSON();233 expect(properties.map).to.be.empty;234 expect(properties.consumedSpace).to.equal(0);235 });236 });237238 it('Fails to set properties with invalid names', async () => {239 await usingApi(async api => {240 const collection = await createCollectionExpectSuccess();241242 const invalidProperties = [243 [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}],244 [{key: 'Mr.Sandman', value: 'Bring me a gene'}],245 [{key: 'déjà vu', value: 'hmm...'}],246 ];247248 for (let i = 0; i < invalidProperties.length; i++) {249 await expect(executeTransaction(250 api, 251 alice, 252 api.tx.unique.setCollectionProperties(collection, invalidProperties[i]), 253 ), `on rejecting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);254 }255256 await expect(executeTransaction(257 api, 258 alice, 259 api.tx.unique.setCollectionProperties(collection, [{key: '', value: 'nothing must not exist'}]), 260 ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);261262 await expect(executeTransaction(263 api, 264 alice, 265 api.tx.unique.setCollectionProperties(collection, [266 {key: 'CRISPR-Cas9', value: 'rewriting nature!'},267 ]), 268 ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;269270 const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat('CRISPR-Cas9').concat('');271272 const properties = (await api.rpc.unique.collectionProperties(collection, keys)).toHuman();273 expect(properties).to.be.deep.equal([274 {key: 'CRISPR-Cas9', value: 'rewriting nature!'},275 ]);276277 for (let i = 0; i < invalidProperties.length; i++) {278 await expect(executeTransaction(279 api, 280 alice, 281 api.tx.unique.deleteCollectionProperties(collection, invalidProperties[i].map(propertySet => propertySet.key)), 282 ), `on trying to delete the non-existent badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);283 }284 });285 });286});287288289290describe('Integration Test: Access Rights to Token Properties', () => {291 before(async () => {292 await usingApi(async (api, privateKeyWrapper) => {293 alice = privateKeyWrapper('//Alice');294 bob = privateKeyWrapper('//Bob');295 });296 });297 298 it('Reads access rights to properties of a collection', async () => {299 await usingApi(async api => {300 const collection = await createCollectionExpectSuccess();301 const propertyRights = (await api.query.common.collectionPropertyPermissions(collection)).toJSON();302 expect(propertyRights).to.be.empty;303 });304 });305 306 it('Sets access rights to properties of a collection', async () => {307 await usingApi(async api => {308 const collection = await createCollectionExpectSuccess();309310 await expect(executeTransaction(311 api, 312 alice, 313 api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true}}]), 314 )).to.not.be.rejected;315316 await addCollectionAdminExpectSuccess(alice, collection, bob.address);317318 await expect(executeTransaction(319 api, 320 alice, 321 api.tx.unique.setPropertyPermissions(collection, [{key: 'mindgame', permission: {collectionAdmin: true, tokenOwner: false}}]), 322 )).to.not.be.rejected;323324 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery', 'mindgame'])).toHuman();325 expect(propertyRights).to.be.deep.equal([326 {key: 'skullduggery', permission: {'mutable': true, 'collectionAdmin': false, 'tokenOwner': false}},327 {key: 'mindgame', permission: {'mutable': false, 'collectionAdmin': true, 'tokenOwner': false}},328 ]);329 });330 });331 332 it('Changes access rights to properties of a collection', async () => {333 await usingApi(async api => {334 const collection = await createCollectionExpectSuccess();335336 await expect(executeTransaction(337 api, 338 alice, 339 api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, collectionAdmin: true}}]), 340 )).to.not.be.rejected;341342 await expect(executeTransaction(343 api, 344 alice, 345 api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 346 )).to.not.be.rejected;347348 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();349 expect(propertyRights).to.be.deep.equal([350 {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},351 ]);352 });353 });354});355356describe('Negative Integration Test: Access Rights to Token Properties', () => {357 before(async () => {358 await usingApi(async (api, privateKeyWrapper) => {359 alice = privateKeyWrapper('//Alice');360 bob = privateKeyWrapper('//Bob');361 });362 });363364 it('Prevents from setting access rights to properties of a collection if not an onwer/admin', async () => {365 await usingApi(async api => {366 const collection = await createCollectionExpectSuccess();367368 await expect(executeTransaction(369 api, 370 bob, 371 api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, tokenOwner: true}}]), 372 )).to.be.rejectedWith(/common\.NoPermission/);373374 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toJSON();375 expect(propertyRights).to.be.empty;376 });377 });378379 it('Prevents from adding too many possible properties', async () => {380 await usingApi(async api => {381 const collection = await createCollectionExpectSuccess();382383 const constitution = [];384 for (let i = 0; i < 65; i++) {385 constitution.push({386 key: 'property_' + i,387 permission: Math.random() > 0.5 ? {mutable: true, collectionAdmin: true, tokenOwner: true} : {},388 });389 }390391 await expect(executeTransaction(392 api, 393 alice, 394 api.tx.unique.setPropertyPermissions(collection, constitution), 395 )).to.be.rejectedWith(/common\.PropertyLimitReached/);396397 const propertyRights = (await api.query.common.collectionPropertyPermissions(collection)).toJSON();398 expect(propertyRights).to.be.empty;399 });400 });401402 it('Prevents access rights to be modified if constant', async () => {403 await usingApi(async api => {404 const collection = await createCollectionExpectSuccess();405406 await expect(executeTransaction(407 api, 408 alice, 409 api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 410 )).to.not.be.rejected;411412 await expect(executeTransaction(413 api, 414 alice, 415 api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {}}]), 416 )).to.be.rejectedWith(/common\.NoPermission/);417418 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();419 expect(propertyRights).to.deep.equal([420 {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},421 ]);422 });423 });424425 it('Prevents adding properties with invalid names', async () => {426 await usingApi(async api => {427 const collection = await createCollectionExpectSuccess();428429 const invalidProperties = [430 [{key: 'skullduggery', permission: {tokenOwner: true}}, {key: 'im possible', permission: {collectionAdmin: true}}],431 [{key: 'G#4', permission: {tokenOwner: true}}],432 [{key: 'HÆMILTON', permission: {mutable: false, collectionAdmin: true, tokenOwner: true}}],433 ];434435 for (let i = 0; i < invalidProperties.length; i++) {436 await expect(executeTransaction(437 api, 438 alice, 439 api.tx.unique.setPropertyPermissions(collection, invalidProperties[i]), 440 ), `on setting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);441 }442443 await expect(executeTransaction(444 api, 445 alice, 446 api.tx.unique.setPropertyPermissions(collection, [{key: '', permission: {}}]), 447 ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);448449 const correctKey = '--0x03116e387820CA05'; 450 await expect(executeTransaction(451 api, 452 alice, 453 api.tx.unique.setPropertyPermissions(collection, [454 {key: correctKey, permission: {collectionAdmin: true}},455 ]), 456 ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;457458 const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat(correctKey).concat('');459460 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, keys)).toHuman();461 expect(propertyRights).to.be.deep.equal([462 {key: correctKey, permission: {mutable: false, collectionAdmin: true, tokenOwner: false}},463 ]);464 });465 });466});467468469470describe('Integration Test: Token Properties', () => {471 let collection: number;472 let token: number;473 let permissions: {permission: any, signers: IKeyringPair[]}[];474475 before(async () => {476 await usingApi(async (api, privateKeyWrapper) => {477 alice = privateKeyWrapper('//Alice');478 bob = privateKeyWrapper('//Bob');479 charlie = privateKeyWrapper('//Charlie');480481 permissions = [482 {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob]},483 {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob]},484 {permission: {mutable: true, tokenOwner: true}, signers: [charlie]},485 {permission: {mutable: false, tokenOwner: true}, signers: [charlie]},486 {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},487 {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},488 ];489 });490 });491492 beforeEach(async () => {493 await usingApi(async () => {494 collection = await createCollectionExpectSuccess();495 token = await createItemExpectSuccess(alice, collection, 'NFT');496 await addCollectionAdminExpectSuccess(alice, collection, bob.address);497 await transferExpectSuccess(collection, token, alice, charlie);498 });499 });500 501 it('Reads yet empty properties of a token', async () => {502 await usingApi(async api => {503 const collection = await createCollectionExpectSuccess();504 const token = await createItemExpectSuccess(alice, collection, 'NFT');505 506 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();507 expect(properties.map).to.be.empty;508 expect(properties.consumedSpace).to.be.equal(0);509510 const tokenData = (await api.rpc.unique.tokenData(collection, token, ['anything'])).toJSON().properties;511 expect(tokenData).to.be.empty;512 });513 });514515 it('Assigns properties to a token according to permissions', async () => {516 await usingApi(async api => {517 const propertyKeys: string[] = [];518 let i = 0;519 for (const permission of permissions) {520 for (const signer of permission.signers) {521 const key = i + '_' + signer.address;522 propertyKeys.push(key);523524 await expect(executeTransaction(525 api, 526 alice, 527 api.tx.unique.setPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 528 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;529530 await expect(executeTransaction(531 api, 532 signer, 533 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 534 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;535 }536537 i++;538 }539540 const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toHuman() as any[];541 const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toHuman().properties as any[];542 for (let i = 0; i < properties.length; i++) {543 expect(properties[i].value).to.be.equal('Serotonin increase');544 expect(tokensData[i].value).to.be.equal('Serotonin increase');545 }546 });547 });548549 it('Changes properties of a token according to permissions', async () => {550 await usingApi(async api => {551 const propertyKeys: string[] = [];552 let i = 0;553 for (const permission of permissions) {554 if (!permission.permission.mutable) continue;555 556 for (const signer of permission.signers) {557 const key = i + '_' + signer.address;558 propertyKeys.push(key);559560 await expect(executeTransaction(561 api, 562 alice, 563 api.tx.unique.setPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 564 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;565566 await expect(executeTransaction(567 api, 568 signer, 569 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 570 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;571572 await expect(executeTransaction(573 api, 574 signer, 575 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin stable'}]), 576 ), `on changing property ${i} by ${signer.address}`).to.not.be.rejected;577 }578579 i++;580 }581582 const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toHuman() as any[];583 const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toHuman().properties as any[];584 for (let i = 0; i < properties.length; i++) {585 expect(properties[i].value).to.be.equal('Serotonin stable');586 expect(tokensData[i].value).to.be.equal('Serotonin stable');587 }588 });589 });590591 it('Deletes properties of a token according to permissions', async () => {592 await usingApi(async api => {593 const propertyKeys: string[] = [];594 let i = 0;595596 for (const permission of permissions) {597 if (!permission.permission.mutable) continue;598 599 for (const signer of permission.signers) {600 const key = i + '_' + signer.address;601 propertyKeys.push(key);602603 await expect(executeTransaction(604 api, 605 alice, 606 api.tx.unique.setPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 607 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;608609 await expect(executeTransaction(610 api, 611 signer, 612 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 613 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;614615 await expect(executeTransaction(616 api, 617 signer, 618 api.tx.unique.deleteTokenProperties(collection, token, [key]), 619 ), `on deleting property ${i} by ${signer.address}`).to.not.be.rejected;620 }621 622 i++;623 }624625 const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toJSON() as any[];626 expect(properties).to.be.empty;627 const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toJSON().properties as any[];628 expect(tokensData).to.be.empty;629 expect((await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace).to.be.equal(0);630 });631 });632});633634describe('Negative Integration Test: Token Properties', () => {635 let collection: number;636 let token: number;637 let originalSpace: number;638 let constitution: {permission: any, signers: IKeyringPair[], sinner: IKeyringPair}[];639640 before(async () => {641 await usingApi(async (api, privateKeyWrapper) => {642 alice = privateKeyWrapper('//Alice');643 bob = privateKeyWrapper('//Bob');644 charlie = privateKeyWrapper('//Charlie');645 const dave = privateKeyWrapper('//Dave');646647 constitution = [648 {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},649 {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},650 {permission: {mutable: true, tokenOwner: true}, signers: [charlie], sinner: alice},651 {permission: {mutable: false, tokenOwner: true}, signers: [charlie], sinner: alice},652 {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},653 {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},654 ];655 });656 });657658 beforeEach(async () => {659 collection = await createCollectionExpectSuccess();660 token = await createItemExpectSuccess(alice, collection, 'NFT');661 await addCollectionAdminExpectSuccess(alice, collection, bob.address);662 await transferExpectSuccess(collection, token, alice, charlie);663 664 await usingApi(async api => {665 let i = 0;666 for (const passage of constitution) {667 const signer = passage.signers[0];668 669 await expect(executeTransaction(670 api, 671 alice, 672 api.tx.unique.setPropertyPermissions(collection, [{key: `${i}`, permission: passage.permission}]), 673 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;674675 await expect(executeTransaction(676 api, 677 signer, 678 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin increase'}]), 679 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;680681 i++;682 }683684 originalSpace = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace as number;685 });686 });687688 it('Forbids changing/deleting properties of a token if the user is outside of permissions', async () => {689 await usingApi(async api => {690 let i = -1;691 for (const forbiddance of constitution) {692 i++;693 if (!forbiddance.permission.mutable) continue;694695 await expect(executeTransaction(696 api, 697 forbiddance.sinner, 698 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 699 ), `on failing to change property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);700701 await expect(executeTransaction(702 api, 703 forbiddance.sinner, 704 api.tx.unique.deleteTokenProperties(collection, token, [`${i}`]), 705 ), `on failing to delete property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);706 }707708 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();709 expect(properties.consumedSpace).to.be.equal(originalSpace);710 });711 });712713 it('Forbids changing/deleting properties of a token if the property is permanent (immutable)', async () => {714 await usingApi(async api => {715 let i = -1;716 for (const permission of constitution) {717 i++;718 if (permission.permission.mutable) continue;719720 await expect(executeTransaction(721 api, 722 permission.signers[0], 723 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 724 ), `on failing to change property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);725726 await expect(executeTransaction(727 api, 728 permission.signers[0], 729 api.tx.unique.deleteTokenProperties(collection, token, [i.toString()]), 730 ), `on failing to delete property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);731 }732733 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();734 expect(properties.consumedSpace).to.be.equal(originalSpace);735 });736 });737738 it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission', async () => {739 await usingApi(async api => {740 await expect(executeTransaction(741 api, 742 alice, 743 api.tx.unique.setTokenProperties(collection, token, [{key: 'non-existent', value: 'I exist!'}]), 744 ), 'on failing to add a previously non-existent property').to.be.rejectedWith(/common\.NoPermission/);745 746 await expect(executeTransaction(747 api, 748 alice, 749 api.tx.unique.setPropertyPermissions(collection, [{key: 'now-existent', permission: {}}]), 750 ), 'on setting a new non-permitted property').to.not.be.rejected;751752 await expect(executeTransaction(753 api, 754 alice, 755 api.tx.unique.setTokenProperties(collection, token, [{key: 'now-existent', value: 'I exist!'}]), 756 ), 'on failing to add a property forbidden by the \'None\' permission').to.be.rejectedWith(/common\.NoPermission/);757758 expect((await api.rpc.unique.tokenProperties(collection, token, ['non-existent', 'now-existent'])).toJSON()).to.be.empty;759 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();760 expect(properties.consumedSpace).to.be.equal(originalSpace);761 });762 });763764 it('Forbids adding too many properties to a token', async () => {765 await usingApi(async api => {766 await expect(executeTransaction(767 api, 768 alice, 769 api.tx.unique.setPropertyPermissions(collection, [770 {key: 'a_holy_book', permission: {collectionAdmin: true, tokenOwner: true}}, 771 {key: 'young_years', permission: {collectionAdmin: true, tokenOwner: true}},772 ]), 773 ), 'on setting a new non-permitted property').to.not.be.rejected;774775 776 {777 console.error = () => {};778 await expect(executeTransaction(779 api, 780 alice, 781 api.tx.unique.setCollectionProperties(collection, [{key: 'a_holy_book', value: 'word '.repeat(6554)}]), 782 )).to.be.rejected;783 }784785 await expect(executeTransaction(786 api, 787 alice, 788 api.tx.unique.setTokenProperties(collection, token, [789 {key: 'a_holy_book', value: 'word '.repeat(3277)}, 790 {key: 'young_years', value: 'neverending'.repeat(1490)},791 ]), 792 )).to.be.rejectedWith(/common\.NoSpaceForProperty/);793794 expect((await api.rpc.unique.tokenProperties(collection, token, ['a_holy_book', 'young_years'])).toJSON()).to.be.empty;795 const propertiesMap = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();796 expect(propertiesMap.consumedSpace).to.be.equal(originalSpace);797 });798 });799});