difftreelog
fix(tests) repair createMultipleItem + ..Ex, remove features made obsolete by properties
in: master
9 files changed
tests/src/contracts.test.tsdiffbeforeafterboth--- a/tests/src/contracts.test.ts
+++ b/tests/src/contracts.test.ts
@@ -139,9 +139,9 @@
await addToAllowListExpectSuccess(alice, collectionId, bob.address);
const transferTx = contract.tx.createMultipleItems(value, gasLimit, bob.address, collectionId, [
- {Nft: {const_data: '0x010203'}},
- {Nft: {const_data: '0x010204'}},
- {Nft: {const_data: '0x010205'}},
+ {NFT: {/*const_data: '0x010203'*/}},
+ {NFT: {/*const_data: '0x010204'*/}},
+ {NFT: {/*const_data: '0x010205'*/}},
]);
const events = await submitTransactionAsync(alice, transferTx);
const result = getGenericResult(events);
@@ -153,15 +153,15 @@
expect(tokensAfter).to.be.deep.equal([
{
Owner: bob.address,
- ConstData: '0x010203',
+ //ConstData: '0x010203',
},
{
Owner: bob.address,
- ConstData: '0x010204',
+ //ConstData: '0x010204',
},
{
Owner: bob.address,
- ConstData: '0x010205',
+ //ConstData: '0x010205',
},
]);
});
tests/src/createCollection.test.tsdiffbeforeafterboth--- a/tests/src/createCollection.test.ts
+++ b/tests/src/createCollection.test.ts
@@ -63,17 +63,17 @@
const bob = privateKey('//Bob');
const tx = api.tx.unique.createCollectionEx({
mode: {Fungible: 8},
- access: 'AllowList',
+ //access: 'AllowList',
name: [1],
description: [2],
tokenPrefix: '0x000000',
- offchainSchema: '0x111111',
- schemaVersion: 'Unique',
+ //offchainSchema: '0x111111',
+ //schemaVersion: 'Unique',
pendingSponsor: bob.address,
limits: {
accountTokenOwnershipLimit: 3,
},
- constOnChainSchema: '0x333333',
+ //constOnChainSchema: '0x333333',
});
const events = await submitTransactionAsync(alice, tx);
const result = getCreateCollectionResult(events);
@@ -81,15 +81,15 @@
const collection = (await getDetailedCollectionInfo(api, result.collectionId))!;
expect(collection.owner.toString()).to.equal(alice.address);
expect(collection.mode.asFungible.toNumber()).to.equal(8);
- expect(collection.access.isAllowList).to.be.true;
+ //expect(collection.access.isAllowList).to.be.true;
expect(collection.name.map(v => v.toNumber())).to.deep.equal([1]);
expect(collection.description.map(v => v.toNumber())).to.deep.equal([2]);
expect(collection.tokenPrefix.toString()).to.equal('0x000000');
- expect(collection.offchainSchema.toString()).to.equal('0x111111');
- expect(collection.schemaVersion.isUnique).to.be.true;
+ //expect(collection.offchainSchema.toString()).to.equal('0x111111');
+ //expect(collection.schemaVersion.isUnique).to.be.true;
expect(collection.sponsorship.asUnconfirmed.toString()).to.equal(bob.address);
expect(collection.limits.accountTokenOwnershipLimit.unwrap().toNumber()).to.equal(3);
- expect(collection.constOnChainSchema.toString()).to.equal('0x333333');
+ //expect(collection.constOnChainSchema.toString()).to.equal('0x333333');
});
});
});
tests/src/createMultipleItems.test.tsdiffbeforeafterboth--- a/tests/src/createMultipleItems.test.ts
+++ b/tests/src/createMultipleItems.test.ts
@@ -30,29 +30,34 @@
getBalance,
getTokenOwner,
getLastTokenId,
- getConstMetadata,
getCreatedCollectionCount,
createCollectionWithPropsExpectSuccess,
- getCreateItemsResult,
createMultipleItemsWithPropsExpectSuccess,
- createMultipleItemsWithPropsExpectFailure,
+ getTokenProperties,
} from './util/helpers';
chai.use(chaiAsPromised);
const expect = chai.expect;
describe('Integration Test createMultipleItems(collection_id, owner, items_data):', () => {
- it('Create 0x31, 0x32, 0x33 items in active NFT collection and verify tokens data in chain', async () => {
+ it('Create 0x31, 0x32, 0x33 items in active NFT collection and verify tokens data in chain', async () => {
await usingApi(async (api: ApiPromise) => {
const collectionId = await createCollectionExpectSuccess();
const itemsListIndexBefore = await getLastTokenId(api, collectionId);
expect(itemsListIndexBefore).to.be.equal(0);
+
const alice = privateKey('//Alice');
- const args = [{Nft: {const_data: '0x31'}},
- {Nft: {const_data: '0x32'}},
- {Nft: {const_data: '0x33'}}];
- const createMultipleItemsTx = api.tx.unique
- .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
+ await submitTransactionAsync(
+ alice,
+ api.tx.unique.setPropertyPermissions(collectionId, [{key: 'data', permission: {tokenOwner: true}}])
+ );
+
+ const args = [
+ {NFT: {properties: [{key: 'data', value: '1'}]}},
+ {NFT: {properties: [{key: 'data', value: '2'}]}},
+ {NFT: {properties: [{key: 'data', value: '3'}]}}
+ ];
+ const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
await submitTransactionAsync(alice, createMultipleItemsTx);
const itemsListIndexAfter = await getLastTokenId(api, collectionId);
expect(itemsListIndexAfter).to.be.equal(3);
@@ -61,13 +66,13 @@
expect(await getTokenOwner(api, collectionId, 2)).to.be.deep.equal(normalizeAccountId(alice.address));
expect(await getTokenOwner(api, collectionId, 3)).to.be.deep.equal(normalizeAccountId(alice.address));
- expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
- expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
- expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
+ expect((await getTokenProperties(api, collectionId, 1, ['data']))[0].value).to.be.equal('1');
+ expect((await getTokenProperties(api, collectionId, 2, ['data']))[0].value).to.be.equal('2');
+ expect((await getTokenProperties(api, collectionId, 3, ['data']))[0].value).to.be.equal('3');
});
});
- it('Create 0x01, 0x02, 0x03 items in active Fungible collection and verify tokens data in chain', async () => {
+ it('Create 0x01, 0x02, 0x03 items in active Fungible collection and verify tokens data in chain', async () => {
await usingApi(async (api: ApiPromise) => {
const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
const itemsListIndexBefore = await getLastTokenId(api, collectionId);
@@ -87,16 +92,16 @@
});
});
- it('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async () => {
+ it('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async () => {
await usingApi(async (api: ApiPromise) => {
const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
const itemsListIndexBefore = await getLastTokenId(api, collectionId);
expect(itemsListIndexBefore).to.be.equal(0);
const alice = privateKey('//Alice');
const args = [
- {ReFungible: {const_data: [0x31], pieces: 1}},
- {ReFungible: {const_data: [0x32], pieces: 1}},
- {ReFungible: {const_data: [0x33], pieces: 1}},
+ {ReFungible: {pieces: 1}},
+ {ReFungible: {pieces: 2}},
+ {ReFungible: {pieces: 3}},
];
const createMultipleItemsTx = api.tx.unique
.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
@@ -105,12 +110,8 @@
expect(itemsListIndexAfter).to.be.equal(3);
expect(await getBalance(api, collectionId, alice.address, 1)).to.be.equal(1n);
- expect(await getBalance(api, collectionId, alice.address, 2)).to.be.equal(1n);
- expect(await getBalance(api, collectionId, alice.address, 3)).to.be.equal(1n);
-
- expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
- expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
- expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
+ expect(await getBalance(api, collectionId, alice.address, 2)).to.be.equal(2n);
+ expect(await getBalance(api, collectionId, alice.address, 3)).to.be.equal(3n);
});
});
@@ -123,8 +124,8 @@
tokenLimit: 2,
});
const args = [
- {NFT: {const_data: 'A'}},
- {NFT: {const_data: 'B'}},
+ {NFT: {}},
+ {NFT: {}},
];
const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
const events = await submitTransactionAsync(alice, createMultipleItemsTx);
@@ -133,16 +134,17 @@
});
});
- it('Create 0x31, 0x32, 0x33 items in active NFT with property Admin', async () => {
+ it('Create 0x31, 0x32, 0x33 items in active NFT with property Admin', async () => {
await usingApi(async (api: ApiPromise) => {
const collectionId = await createCollectionWithPropsExpectSuccess({propPerm: [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: false}}]});
const itemsListIndexBefore = await getLastTokenId(api, collectionId);
expect(itemsListIndexBefore).to.be.equal(0);
const alice = privateKey('//Alice');
- const bob = privateKey('//Bob');
- const args = [{Nft: {const_data: '0x31', properties: [{key: 'k', value: 'v1'}]}},
- {Nft: {const_data: '0x32', properties: [{key: 'k', value: 'v2'}]}},
- {Nft: {const_data: '0x33', properties: [{key: 'k', value: 'v3'}]}}];
+ const args = [
+ {NFT: {properties: [{key: 'k', value: 'v1'}]}},
+ {NFT: {properties: [{key: 'k', value: 'v2'}]}},
+ {NFT: {properties: [{key: 'k', value: 'v3'}]}}
+ ];
await createMultipleItemsWithPropsExpectSuccess(alice, collectionId, args);
const itemsListIndexAfter = await getLastTokenId(api, collectionId);
@@ -152,13 +154,13 @@
expect(await getTokenOwner(api, collectionId, 2)).to.be.deep.equal(normalizeAccountId(alice.address));
expect(await getTokenOwner(api, collectionId, 3)).to.be.deep.equal(normalizeAccountId(alice.address));
- expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
- expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
- expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
+ expect((await getTokenProperties(api, collectionId, 1, ['k']))[0].value).to.be.equal('v1');
+ expect((await getTokenProperties(api, collectionId, 2, ['k']))[0].value).to.be.equal('v2');
+ expect((await getTokenProperties(api, collectionId, 3, ['k']))[0].value).to.be.equal('v3');
});
});
- it('Create 0x31, 0x32, 0x33 items in active NFT with property AdminConst', async () => {
+ it('Create 0x31, 0x32, 0x33 items in active NFT with property AdminConst', async () => {
await usingApi(async (api: ApiPromise) => {
const collectionId = await createCollectionWithPropsExpectSuccess({propPerm: [{key: 'k', permission: {mutable: false, collectionAdmin: true, tokenOwner: false}}]});
const itemsListIndexBefore = await getLastTokenId(api, collectionId);
@@ -166,9 +168,11 @@
const alice = privateKey('//Alice');
const bob = privateKey('//Bob');
await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
- const args = [{Nft: {const_data: '0x31', properties: [{key: 'k', value: 'v1'}]}},
- {Nft: {const_data: '0x32', properties: [{key: 'k', value: 'v2'}]}},
- {Nft: {const_data: '0x33', properties: [{key: 'k', value: 'v3'}]}}];
+ const args = [
+ {NFT: {properties: [{key: 'k', value: 'v1'}]}},
+ {NFT: {properties: [{key: 'k', value: 'v2'}]}},
+ {NFT: {properties: [{key: 'k', value: 'v3'}]}}
+ ];
await createMultipleItemsWithPropsExpectSuccess(alice, collectionId, args);
const itemsListIndexAfter = await getLastTokenId(api, collectionId);
@@ -178,22 +182,25 @@
expect(await getTokenOwner(api, collectionId, 2)).to.be.deep.equal(normalizeAccountId(alice.address));
expect(await getTokenOwner(api, collectionId, 3)).to.be.deep.equal(normalizeAccountId(alice.address));
- expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
- expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
- expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
+ expect((await getTokenProperties(api, collectionId, 1, ['k']))[0].value).to.be.equal('v1');
+ expect((await getTokenProperties(api, collectionId, 2, ['k']))[0].value).to.be.equal('v2');
+ expect((await getTokenProperties(api, collectionId, 3, ['k']))[0].value).to.be.equal('v3');
});
});
- it('Create 0x31, 0x32, 0x33 items in active NFT with property itemOwnerOrAdmin', async () => {
+ it('Create 0x31, 0x32, 0x33 items in active NFT with property itemOwnerOrAdmin', async () => {
await usingApi(async (api: ApiPromise) => {
- const collectionId = await createCollectionWithPropsExpectSuccess({propPerm: [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}]});
+ const collectionId = await createCollectionWithPropsExpectSuccess(
+ {propPerm: [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}]}
+ );
const itemsListIndexBefore = await getLastTokenId(api, collectionId);
expect(itemsListIndexBefore).to.be.equal(0);
const alice = privateKey('//Alice');
- const bob = privateKey('//Bob');
- const args = [{Nft: {const_data: '0x31', properties: [{key: 'k', value: 'v1'}]}},
- {Nft: {const_data: '0x32', properties: [{key: 'k', value: 'v2'}]}},
- {Nft: {const_data: '0x33', properties: [{key: 'k', value: 'v3'}]}}];
+ const args = [
+ {NFT: {properties: [{key: 'k', value: 'v1'}]}},
+ {NFT: {properties: [{key: 'k', value: 'v2'}]}},
+ {NFT: {properties: [{key: 'k', value: 'v3'}]}}
+ ];
await createMultipleItemsWithPropsExpectSuccess(alice, collectionId, args);
const itemsListIndexAfter = await getLastTokenId(api, collectionId);
@@ -203,15 +210,14 @@
expect(await getTokenOwner(api, collectionId, 2)).to.be.deep.equal(normalizeAccountId(alice.address));
expect(await getTokenOwner(api, collectionId, 3)).to.be.deep.equal(normalizeAccountId(alice.address));
- expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
- expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
- expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
+ expect((await getTokenProperties(api, collectionId, 1, ['k']))[0].value).to.be.equal('v1');
+ expect((await getTokenProperties(api, collectionId, 2, ['k']))[0].value).to.be.equal('v2');
+ expect((await getTokenProperties(api, collectionId, 3, ['k']))[0].value).to.be.equal('v3');
});
});
});
describe('Integration Test createMultipleItems(collection_id, owner, items_data) with collection admin permissions:', () => {
-
let alice: IKeyringPair;
let bob: IKeyringPair;
@@ -222,15 +228,19 @@
});
});
- it('Create 0x31, 0x32, 0x33 items in active NFT collection and verify tokens data in chain', async () => {
+ it('Create 0x31, 0x32, 0x33 items in active NFT collection and verify tokens data in chain', async () => {
await usingApi(async (api: ApiPromise) => {
- const collectionId = await createCollectionExpectSuccess();
+ const collectionId = await createCollectionWithPropsExpectSuccess(
+ {propPerm: [{key: 'data', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}]}
+ );
const itemsListIndexBefore = await getLastTokenId(api, collectionId);
expect(itemsListIndexBefore).to.be.equal(0);
await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
- const args = [{Nft: {const_data: '0x31'}},
- {Nft: {const_data: '0x32'}},
- {Nft: {const_data: '0x33'}}];
+ const args = [
+ {NFT: {properties: [{key: 'data', value: 'v1'}]}},
+ {NFT: {properties: [{key: 'data', value: 'v2'}]}},
+ {NFT: {properties: [{key: 'data', value: 'v3'}]}}
+ ];
const createMultipleItemsTx = api.tx.unique
.createMultipleItems(collectionId, normalizeAccountId(bob.address), args);
await submitTransactionAsync(bob, createMultipleItemsTx);
@@ -241,13 +251,13 @@
expect(await getTokenOwner(api, collectionId, 2)).to.be.deep.equal(normalizeAccountId(bob.address));
expect(await getTokenOwner(api, collectionId, 3)).to.be.deep.equal(normalizeAccountId(bob.address));
- expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
- expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
- expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
+ expect((await getTokenProperties(api, collectionId, 1, ['data']))[0].value).to.be.equal('v1');
+ expect((await getTokenProperties(api, collectionId, 2, ['data']))[0].value).to.be.equal('v2');
+ expect((await getTokenProperties(api, collectionId, 3, ['data']))[0].value).to.be.equal('v3');
});
});
- it('Create 0x01, 0x02, 0x03 items in active Fungible collection and verify tokens data in chain', async () => {
+ it('Create 0x01, 0x02, 0x03 items in active Fungible collection and verify tokens data in chain', async () => {
await usingApi(async (api: ApiPromise) => {
const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
const itemsListIndexBefore = await getLastTokenId(api, collectionId);
@@ -267,16 +277,16 @@
});
});
- it('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async () => {
+ it('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async () => {
await usingApi(async (api: ApiPromise) => {
const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
const itemsListIndexBefore = await getLastTokenId(api, collectionId);
expect(itemsListIndexBefore).to.be.equal(0);
await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
const args = [
- {ReFungible: {const_data: [0x31], pieces: 1}},
- {ReFungible: {const_data: [0x32], pieces: 1}},
- {ReFungible: {const_data: [0x33], pieces: 1}},
+ {ReFungible: {pieces: 1}},
+ {ReFungible: {pieces: 2}},
+ {ReFungible: {pieces: 3}},
];
const createMultipleItemsTx = api.tx.unique
.createMultipleItems(collectionId, normalizeAccountId(bob.address), args);
@@ -285,18 +295,13 @@
expect(itemsListIndexAfter).to.be.equal(3);
expect(await getBalance(api, collectionId, bob.address, 1)).to.be.equal(1n);
- expect(await getBalance(api, collectionId, bob.address, 2)).to.be.equal(1n);
- expect(await getBalance(api, collectionId, bob.address, 3)).to.be.equal(1n);
-
- expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
- expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
- expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
+ expect(await getBalance(api, collectionId, bob.address, 2)).to.be.equal(2n);
+ expect(await getBalance(api, collectionId, bob.address, 3)).to.be.equal(3n);
});
});
});
describe('Negative Integration Test createMultipleItems(collection_id, owner, items_data):', () => {
-
let alice: IKeyringPair;
let bob: IKeyringPair;
@@ -312,12 +317,11 @@
const collectionId = await createCollectionExpectSuccess();
const itemsListIndexBefore = await getLastTokenId(api, collectionId);
expect(itemsListIndexBefore).to.be.equal(0);
- const args = [{Nft: {const_data: '0x31'}},
- {Nft: {const_data: '0x32'}},
- {Nft: {const_data: '0x33'}}];
- const createMultipleItemsTx = api.tx.unique
- .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
- await expect(submitTransactionAsync(bob, createMultipleItemsTx)).to.be.rejected;
+ const args = [{NFT: {}},
+ {NFT: {}},
+ {NFT: {}}];
+ const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
+ await expect(executeTransaction(api, bob, createMultipleItemsTx)).to.be.rejectedWith(/common\.PublicMintingNotAllowed/);
});
});
@@ -331,9 +335,8 @@
{Fungible: {value: 2}},
{Fungible: {value: 3}},
];
- const createMultipleItemsTx = api.tx.unique
- .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
- await expect(submitTransactionAsync(bob, createMultipleItemsTx)).to.be.rejected;
+ const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
+ await expect(executeTransaction(api, bob, createMultipleItemsTx)).to.be.rejectedWith(/common\.PublicMintingNotAllowed/);
});
});
@@ -343,37 +346,38 @@
const itemsListIndexBefore = await getLastTokenId(api, collectionId);
expect(itemsListIndexBefore).to.be.equal(0);
const args = [
- {ReFungible: {const_data: [0x31], pieces: 1}},
- {ReFungible: {const_data: [0x32], pieces: 1}},
- {ReFungible: {const_data: [0x33], pieces: 1}},
+ {ReFungible: {pieces: 1}},
+ {ReFungible: {pieces: 1}},
+ {ReFungible: {pieces: 1}},
];
- const createMultipleItemsTx = api.tx.unique
- .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
- await expect(submitTransactionAsync(bob, createMultipleItemsTx)).to.be.rejected;
+ const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
+ await expect(executeTransaction(api, bob, createMultipleItemsTx)).to.be.rejectedWith(/common\.PublicMintingNotAllowed/);
});
});
it('Create token in not existing collection', async () => {
await usingApi(async (api: ApiPromise) => {
const collectionId = await getCreatedCollectionCount(api) + 1;
- const createMultipleItemsTx = api.tx.unique
- .createMultipleItems(collectionId, normalizeAccountId(alice.address), ['NFT', 'NFT', 'NFT']);
- await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected;
+ const createMultipleItemsTx = api.tx.unique.createMultipleItems(
+ collectionId, normalizeAccountId(alice.address), ['NFT', 'NFT', 'NFT']
+ );
+ await expect(executeTransaction(api, alice, createMultipleItemsTx)).to.be.rejectedWith(/common\.CollectionNotFound/);
});
});
it('Create NFT and Re-fungible tokens that has reached the maximum data limit', async () => {
await usingApi(async (api: ApiPromise) => {
// NFT
- const collectionId = await createCollectionExpectSuccess();
+ const collectionId = await createCollectionWithPropsExpectSuccess({
+ propPerm: [{key: 'key', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}]
+ });
const alice = privateKey('//Alice');
const args = [
- {NFT: {const_data: 'A'.repeat(2049)}},
- {NFT: {const_data: 'B'.repeat(2049)}},
- {NFT: {const_data: 'C'.repeat(2049)}},
+ {NFT: {properties: [{key: 'key', value: 'A'.repeat(32769)}]}},
+ {NFT: {properties: [{key: 'key', value: 'B'.repeat(32769)}]}},
+ {NFT: {properties: [{key: 'key', value: 'C'.repeat(32769)}]}},
];
- const createMultipleItemsTx = api.tx.unique
- .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
+ const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected;
// ReFungible
@@ -395,68 +399,61 @@
const collectionId = await createCollectionExpectSuccess();
const createMultipleItemsTx = api.tx.unique
.createMultipleItems(collectionId, normalizeAccountId(alice.address), ['NFT', 'Fungible', 'ReFungible']);
- await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected;
- // garbage collection :-D
+ await expect(
+ executeTransaction(api, alice, createMultipleItemsTx)
+ ).to.be.rejectedWith(
+ /nonfungible\.NotNonfungibleDataUsedToMintFungibleCollectionToken/
+ );
+ // garbage collection :-D // lol
await destroyCollectionExpectSuccess(collectionId);
});
});
it('Create tokens with different data limits <> maximum data limit', async () => {
await usingApi(async (api: ApiPromise) => {
- const collectionId = await createCollectionExpectSuccess();
+ const collectionId = await createCollectionWithPropsExpectSuccess({
+ propPerm: [{key: 'key', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}]
+ });
const args = [
- {NFT: {const_data: 'A'}},
- {NFT: {const_data: 'B'.repeat(2049)}},
+ {NFT: {properties: [{key: 'key', value: 'A'}]}},
+ {NFT: {properties: [{key: 'key', value: 'B'.repeat(32769)}]}},
];
- const createMultipleItemsTx = await api.tx.unique
- .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
+ const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected;
});
});
it('Fails when minting tokens exceeds collectionLimits amount', async () => {
await usingApi(async (api) => {
-
const collectionId = await createCollectionExpectSuccess();
await setCollectionLimitsExpectSuccess(alice, collectionId, {
tokenLimit: 1,
});
const args = [
- {NFT: {const_data: 'A'}},
- {NFT: {const_data: 'B'}},
+ {NFT: {}},
+ {NFT: {}},
];
const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
- await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected;
- });
- });
-
- it('No editing rights', async () => {
- await usingApi(async (api: ApiPromise) => {
- const collectionId = await createCollectionWithPropsExpectSuccess({properties: [{key: 'key1', value: 'v'}],
- propPerm: [{key: 'key1', permission: {mutable: false, collectionAdmin: false, tokenOwner: true}}]});
- const itemsListIndexBefore = await getLastTokenId(api, collectionId);
- expect(itemsListIndexBefore).to.be.equal(0);
- await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
- const args = [{Nft: {const_data: '0x31', properties: [{key: 'key1', value: 'v2'}]}},
- {Nft: {const_data: '0x32'}},
- {Nft: {const_data: '0x33'}}];
-
- await createMultipleItemsWithPropsExpectFailure(bob, collectionId, args);
+ await expect(executeTransaction(api, alice, createMultipleItemsTx)).to.be.rejectedWith(/common\.CollectionTokenLimitExceeded/);
});
});
it('User doesnt have editing rights', async () => {
await usingApi(async (api: ApiPromise) => {
- const collectionId = await createCollectionWithPropsExpectSuccess({properties: [{key: 'key1', value: 'v'}],
- propPerm: [{key: 'key1', permission: {mutable: true, collectionAdmin: false, tokenOwner: false}}]});
+ const collectionId = await createCollectionWithPropsExpectSuccess({
+ propPerm: [{key: 'key1', permission: {mutable: true, collectionAdmin: false, tokenOwner: false}}]
+ });
const itemsListIndexBefore = await getLastTokenId(api, collectionId);
expect(itemsListIndexBefore).to.be.equal(0);
await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
- const args = [{Nft: {const_data: '0x31', properties: [{key: 'key1', value: 'v2'}]}},
- {Nft: {const_data: '0x32'}},
- {Nft: {const_data: '0x33'}}];
+ const args = [
+ {NFT: {properties: [{key: 'key1', value: 'v2'}]}},
+ {NFT: {}},
+ {NFT: {}}
+ ];
- await createMultipleItemsWithPropsExpectFailure(bob, collectionId, args);
+ const tx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(bob.address), args);
+ await expect(executeTransaction(api, bob, tx)).to.be.rejectedWith(/common\.NoPermission/);
});
});
@@ -466,18 +463,27 @@
const itemsListIndexBefore = await getLastTokenId(api, collectionId);
await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
expect(itemsListIndexBefore).to.be.equal(0);
- const args = [{Nft: {const_data: '0x31', properties: [{key: 'k', value: 'v'}]}},
- {Nft: {const_data: '0x32'}},
- {Nft: {const_data: '0x33'}}];
+ const args = [{NFT: {properties: [{key: 'k', value: 'v'}]}},
+ {NFT: {}},
+ {NFT: {}}];
- await createMultipleItemsWithPropsExpectFailure(bob, collectionId, args);
+ const tx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(bob.address), args);
+ await expect(executeTransaction(api, bob, tx)).to.be.rejectedWith(/common\.NoPermission/);
});
});
it('Adding more than 64 prps', async () => {
await usingApi(async (api: ApiPromise) => {
- const collectionId = await createCollectionWithPropsExpectSuccess({properties: [{key: 'key1', value: 'v'}],
- propPerm: [{key: 'key1', permission: {mutable: true, collectionAdmin: true, tokenOwner: false}}]});
+ const propPerms = [{key: 'key', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}];
+ for (let i = 0; i < 65; i++) {
+ propPerms.push({key: `key${i}`, permission: {mutable: true, collectionAdmin: true, tokenOwner: true}});
+ }
+
+ const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+
+ const tx1 = api.tx.unique.setPropertyPermissions(collectionId, propPerms);
+ await expect(executeTransaction(api, alice, tx1)).to.be.rejectedWith(/common\.PropertyLimitReached/);
+
const itemsListIndexBefore = await getLastTokenId(api, collectionId);
expect(itemsListIndexBefore).to.be.equal(0);
await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
@@ -488,24 +494,31 @@
prps.push({key: `key${i}`, value: `value${i}`});
}
- const args = [{Nft: {const_data: '0x31', properties: prps}},
- {Nft: {const_data: '0x32', properties: prps}},
- {Nft: {const_data: '0x33', properties: prps}}];
+ const args = [
+ {NFT: {properties: prps}},
+ {NFT: {properties: prps}},
+ {NFT: {properties: prps}}
+ ];
- createMultipleItemsWithPropsExpectFailure(alice, collectionId, args);
+ // there are no permissions, but will fail anyway because of too much weight for a block
+ const tx2 = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);;
+ await expect(submitTransactionExpectFailAsync(alice, tx2)).to.be.rejected;
});
});
it('Trying to add bigger property than allowed', async () => {
await usingApi(async (api: ApiPromise) => {
- const collectionId = await createCollectionWithPropsExpectSuccess({propPerm: [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}]});
+ const collectionId = await createCollectionWithPropsExpectSuccess({
+ propPerm: [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}]
+ });
const itemsListIndexBefore = await getLastTokenId(api, collectionId);
expect(itemsListIndexBefore).to.be.equal(0);
- const args = [{Nft: {const_data: '0x31', properties: [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}]}},
- {Nft: {const_data: '0x32', properties: [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}]}},
- {Nft: {const_data: '0x33', properties: [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}]}}];
+ const args = [{NFT: {properties: [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}]}},
+ {NFT: {properties: [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}]}},
+ {NFT: {properties: [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}]}}];
- createMultipleItemsWithPropsExpectFailure(alice, collectionId, args);
+ const tx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
+ await expect(executeTransaction(api, alice, tx)).to.be.rejectedWith(/common\.NoPermission/);
});
});
});
tests/src/createMultipleItemsEx.test.tsdiffbeforeafterboth--- a/tests/src/createMultipleItemsEx.test.ts
+++ b/tests/src/createMultipleItemsEx.test.ts
@@ -29,13 +29,13 @@
const data = [
{
owner: {substrate: alice.address},
- constData: '0x0000',
+ // constData: '0x0000',
}, {
owner: {substrate: bob.address},
- constData: '0x2222',
+ // constData: '0x2222',
}, {
owner: {substrate: charlie.address},
- constData: '0x4444',
+ // constData: '0x4444',
},
];
@@ -57,15 +57,15 @@
const data = [
{
owner: {substrate: alice.address},
- constData: '0x1111',
+ // constData: '0x1111',
properties: [{key: 'k', value: 'v1'}],
}, {
owner: {substrate: bob.address},
- constData: '0x2222',
+ // constData: '0x2222',
properties: [{key: 'k', value: 'v2'}],
}, {
owner: {substrate: charlie.address},
- constData: '0x4444',
+ // constData: '0x4444',
properties: [{key: 'k', value: 'v3'}],
},
];
@@ -88,15 +88,15 @@
const data = [
{
owner: {substrate: alice.address},
- constData: '0x0000',
+ // constData: '0x0000',
properties: [{key: 'k', value: 'v1'}],
}, {
owner: {substrate: bob.address},
- constData: '0x2222',
+ // constData: '0x2222',
properties: [{key: 'k', value: 'v2'}],
}, {
owner: {substrate: charlie.address},
- constData: '0x4444',
+ // constData: '0x4444',
properties: [{key: 'k', value: 'v3'}],
},
];
@@ -119,15 +119,15 @@
const data = [
{
owner: {substrate: alice.address},
- constData: '0x0000',
+ // constData: '0x0000',
properties: [{key: 'k', value: 'v1'}],
}, {
owner: {substrate: bob.address},
- constData: '0x2222',
+ // constData: '0x2222',
properties: [{key: 'k', value: 'v2'}],
}, {
owner: {substrate: charlie.address},
- constData: '0x4444',
+ // constData: '0x4444',
properties: [{key: 'k', value: 'v3'}],
},
];
@@ -154,10 +154,10 @@
owner: {substrate: alice.address},
properties: [{key: 'key1', value: 'v2'}],
}, {
- owner: {substrate: alice.address},
+ owner: {substrate: bob.address},
properties: [{key: 'key1', value: 'v2'}],
}, {
- owner: {substrate: alice.address},
+ owner: {substrate: charlie.address},
properties: [{key: 'key1', value: 'v2'}],
},
];
@@ -165,7 +165,8 @@
const tx = api.tx.unique.createMultipleItemsEx(collection, {NFT: data});
// await executeTransaction(api, alice, tx);
- await submitTransactionExpectFailAsync(alice, tx);
+ //await submitTransactionExpectFailAsync(alice, tx);
+ await expect(executeTransaction(api, alice, tx)).to.be.rejectedWith(/common\.NoPermission/);
});
});
@@ -193,7 +194,8 @@
const tx = api.tx.unique.createMultipleItemsEx(collection, {NFT: data});
// await executeTransaction(api, alice, tx);
- await submitTransactionExpectFailAsync(alice, tx);
+ //await submitTransactionExpectFailAsync(alice, tx);
+ await expect(executeTransaction(api, alice, tx)).to.be.rejectedWith(/common\.NoPermission/);
});
});
@@ -219,41 +221,24 @@
const tx = api.tx.unique.createMultipleItemsEx(collection, {NFT: data});
- await submitTransactionExpectFailAsync(alice, tx);
+ await expect(executeTransaction(api, alice, tx)).to.be.rejectedWith(/common\.NoPermission/);
+ //await submitTransactionExpectFailAsync(alice, tx);
});
});
- it('Adding more than 64 prps', async () => {
- const prps = [{key: 'key', value: 'v'}];
- const propPerm = [{key: 'key', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}];
+ it('Adding more than 64 properties', async () => {
+ const propPerms = [{key: 'key', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}];
for (let i = 0; i < 65; i++) {
- prps.push({key: `key${i}`, value: `value${i}`});
- propPerm.push({key: `key${i}`, permission: {mutable: true, collectionAdmin: true, tokenOwner: true}});
+ propPerms.push({key: `key${i}`, permission: {mutable: true, collectionAdmin: true, tokenOwner: true}});
}
- const collection = await createCollectionWithPropsExpectSuccess({propPerm: propPerm});
const alice = privateKey('//Alice');
- const bob = privateKey('//Bob');
- const charlie = privateKey('//Charlie');
- await addCollectionAdminExpectSuccess(alice, collection, bob.address);
+ const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
await usingApi(async (api) => {
- const data = [
- {
- owner: {substrate: alice.address},
- properties: prps,
- }, {
- owner: {substrate: alice.address},
- properties: prps,
- }, {
- owner: {substrate: alice.address},
- properties: prps,
- },
- ];
-
- const tx = api.tx.unique.createMultipleItemsEx(collection, {NFT: data});
-
- await submitTransactionExpectFailAsync(alice, tx);
+ await expect(
+ executeTransaction(api, alice, api.tx.unique.setPropertyPermissions(collection, propPerms))
+ ).to.be.rejectedWith(/common\.PropertyLimitReached/);
});
});
@@ -276,7 +261,8 @@
const tx = api.tx.unique.createMultipleItemsEx(collection, {NFT: data});
- await submitTransactionExpectFailAsync(alice, tx);
+ //await submitTransactionExpectFailAsync(alice, tx);
+ await expect(executeTransaction(api, alice, tx)).to.be.rejectedWith(/common\.NoPermission/);
});
});
@@ -289,13 +275,13 @@
const data = [
{
owner: {substrate: alice.address},
- constData: '0x0000',
+ // constData: '0x0000',
}, {
owner: {substrate: bob.address},
- constData: '0x2222',
+ // constData: '0x2222',
}, {
owner: {substrate: charlie.address},
- constData: '0x4444',
+ // constData: '0x4444',
},
];
@@ -317,13 +303,13 @@
const data = [
{
owner: {substrate: alice.address},
- constData: '0x0000',
+ // constData: '0x0000',
}, {
owner: {substrate: bob.address},
- constData: '0x2222',
+ // constData: '0x2222',
}, {
owner: {substrate: charlie.address},
- constData: '0x4444',
+ // constData: '0x4444',
},
];
tests/src/nesting/properties.test.tsdiffbeforeafterboth1import {expect} from 'chai';2import privateKey from '../substrate/privateKey';3import usingApi, {executeTransaction} from '../substrate/substrate-api';4import {5 addCollectionAdminExpectSuccess,6 createCollectionExpectSuccess,7 createItemExpectSuccess,8 getCreateCollectionResult,9 transferExpectSuccess,10} from '../util/helpers';11import {IKeyringPair} from '@polkadot/types/types';1213let alice: IKeyringPair;14let bob: IKeyringPair;15let charlie: IKeyringPair;1617describe('Composite Properties Test', () => {18 before(async () => {19 await usingApi(async () => {20 alice = privateKey('//Alice');21 bob = privateKey('//Bob');22 });23 });2425 it('Makes sure collectionById supplies required fields', async () => {26 await usingApi(async api => {27 const collectionId = await createCollectionExpectSuccess();2829 const collectionOption = await api.rpc.unique.collectionById(collectionId);30 expect(collectionOption.isSome).to.be.true;31 let collection = collectionOption.unwrap();32 expect(collection.tokenPropertyPermissions.toHuman()).to.be.empty;33 expect(collection.properties.toHuman()).to.be.empty;3435 const propertyPermissions = [36 {key: 'mindgame', permission: {collectionAdmin: true, mutable: false, tokenOwner: true}},37 {key: 'skullduggery', permission: {collectionAdmin: false, mutable: true, tokenOwner: false}},38 ];39 await expect(executeTransaction(40 api, 41 alice, 42 api.tx.unique.setPropertyPermissions(collectionId, propertyPermissions), 43 )).to.not.be.rejected;4445 const collectionProperties = [46 {key: 'black_hole', value: 'LIGO'},47 {key: 'electron', value: 'come bond'}, 48 ];49 await expect(executeTransaction(50 api, 51 alice, 52 api.tx.unique.setCollectionProperties(collectionId, collectionProperties), 53 )).to.not.be.rejected;5455 collection = (await api.rpc.unique.collectionById(collectionId)).unwrap();56 expect(collection.tokenPropertyPermissions.toHuman()).to.be.deep.equal(propertyPermissions);57 expect(collection.properties.toHuman()).to.be.deep.equal(collectionProperties);58 });59 });60});6162// ---------- COLLECTION PROPERTIES6364describe('Integration Test: Collection Properties', () => {65 before(async () => {66 await usingApi(async () => {67 alice = privateKey('//Alice');68 bob = privateKey('//Bob');69 });70 });7172 it('Reads properties from a collection', async () => {73 await usingApi(async api => {74 const collection = await createCollectionExpectSuccess();75 const properties = (await api.query.common.collectionProperties(collection)).toJSON();76 expect(properties.map).to.be.empty;77 expect(properties.consumedSpace).to.equal(0);78 });79 });8081 it('Sets properties for a collection', async () => {82 await usingApi(async api => {83 const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: 'NFT'}));84 const {collectionId} = getCreateCollectionResult(events);8586 // As owner87 await expect(executeTransaction(88 api, 89 bob, 90 api.tx.unique.setCollectionProperties(collectionId, [{key: 'electron', value: 'come bond'}]), 91 )).to.not.be.rejected;9293 await addCollectionAdminExpectSuccess(bob, collectionId, alice.address);9495 // As administrator96 await expect(executeTransaction(97 api, 98 alice, 99 api.tx.unique.setCollectionProperties(collectionId, [{key: 'black_hole'}]), 100 )).to.not.be.rejected;101102 const properties = (await api.rpc.unique.collectionProperties(collectionId, ['electron', 'black_hole'])).toHuman();103 expect(properties).to.be.deep.equal([104 {key: 'electron', value: 'come bond'},105 {key: 'black_hole', value: ''},106 ]);107 });108 });109110 it('Changes properties of a collection', async () => {111 await usingApi(async api => {112 const collection = await createCollectionExpectSuccess();113114 await expect(executeTransaction(115 api, 116 alice, 117 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole'}]), 118 )).to.not.be.rejected;119120 // Mutate the properties121 await expect(executeTransaction(122 api, 123 alice, 124 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'bonded'}, {key: 'black_hole', value: 'LIGO'}]), 125 )).to.not.be.rejected;126127 const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();128 expect(properties).to.be.deep.equal([129 {key: 'electron', value: 'bonded'},130 {key: 'black_hole', value: 'LIGO'},131 ]);132 });133 });134135 it('Deletes properties of a collection', async () => {136 await usingApi(async api => {137 const collection = await createCollectionExpectSuccess();138139 await expect(executeTransaction(140 api, 141 alice, 142 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]), 143 )).to.not.be.rejected;144145 await expect(executeTransaction(146 api, 147 alice, 148 api.tx.unique.deleteCollectionProperties(collection, ['electron']), 149 )).to.not.be.rejected;150151 const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();152 expect(properties).to.be.deep.equal([153 {key: 'black_hole', value: 'LIGO'},154 ]);155 });156 });157});158159describe('Negative Integration Test: Collection Properties', () => {160 before(async () => {161 await usingApi(async () => {162 alice = privateKey('//Alice');163 bob = privateKey('//Bob');164 });165 });166 167 it('Fails to set properties in a collection if not its onwer/administrator', async () => {168 await usingApi(async api => {169 const collection = await createCollectionExpectSuccess();170171 await expect(executeTransaction(172 api, 173 bob, 174 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]), 175 )).to.be.rejectedWith(/common\.NoPermission/);176 177 const properties = (await api.query.common.collectionProperties(collection)).toJSON();178 expect(properties.map).to.be.empty;179 expect(properties.consumedSpace).to.equal(0);180 });181 });182 183 it('Fails to set properties that exceed the limits', async () => {184 await usingApi(async api => {185 const collection = await createCollectionExpectSuccess();186 const spaceLimit = (await api.query.common.collectionProperties(collection)).toJSON().spaceLimit as number; 187188 // Mute the general tx parsing error, too many bytes to process189 {190 console.error = () => {};191 await expect(executeTransaction(192 api, 193 alice, 194 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 9))}]), 195 )).to.be.rejected;196 }197198 let properties = (await api.rpc.unique.collectionProperties(collection, ['electron'])).toJSON();199 expect(properties).to.be.empty;200201 await expect(executeTransaction(202 api, 203 alice, 204 api.tx.unique.setCollectionProperties(collection, [205 {key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 18))}, 206 {key: 'black_hole', value: '0'.repeat(Math.ceil(spaceLimit! / 2))}, 207 ]), 208 )).to.be.rejectedWith(/common\.NoSpaceForProperty/);209210 properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black hole'])).toJSON();211 expect(properties).to.be.empty;212 });213 });214 215 it('Fails to set more properties than it is allowed', async () => {216 await usingApi(async api => {217 const collection = await createCollectionExpectSuccess();218219 const propertiesToBeSet = [];220 for (let i = 0; i < 65; i++) {221 propertiesToBeSet.push({222 key: 'electron_' + i,223 value: Math.random() > 0.5 ? 'high' : 'low',224 });225 }226227 await expect(executeTransaction(228 api, 229 alice, 230 api.tx.unique.setCollectionProperties(collection, propertiesToBeSet), 231 )).to.be.rejectedWith(/common\.PropertyLimitReached/);232233 const properties = (await api.query.common.collectionProperties(collection)).toJSON();234 expect(properties.map).to.be.empty;235 expect(properties.consumedSpace).to.equal(0);236 });237 });238239 it('Fails to set properties with invalid names', async () => {240 await usingApi(async api => {241 const collection = await createCollectionExpectSuccess();242243 const invalidProperties = [244 [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}],245 [{key: 'Mr.Sandman', value: 'Bring me a gene'}],246 [{key: 'déjà vu', value: 'hmm...'}],247 ];248249 for (let i = 0; i < invalidProperties.length; i++) {250 await expect(executeTransaction(251 api, 252 alice, 253 api.tx.unique.setCollectionProperties(collection, invalidProperties[i]), 254 ), `on rejecting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);255 }256257 await expect(executeTransaction(258 api, 259 alice, 260 api.tx.unique.setCollectionProperties(collection, [{key: '', value: 'nothing must not exist'}]), 261 ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);262263 await expect(executeTransaction(264 api, 265 alice, 266 api.tx.unique.setCollectionProperties(collection, [267 {key: 'CRISPR-Cas9', value: 'rewriting nature!'},268 ]), 269 ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;270271 const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat('CRISPR-Cas9').concat('');272273 const properties = (await api.rpc.unique.collectionProperties(collection, keys)).toHuman();274 expect(properties).to.be.deep.equal([275 {key: 'CRISPR-Cas9', value: 'rewriting nature!'},276 ]);277278 for (let i = 0; i < invalidProperties.length; i++) {279 await expect(executeTransaction(280 api, 281 alice, 282 api.tx.unique.deleteCollectionProperties(collection, invalidProperties[i].map(propertySet => propertySet.key)), 283 ), `on trying to delete the non-existent badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);284 }285 });286 });287});288289// ---------- ACCESS RIGHTS290291describe('Integration Test: Access Rights to Token Properties', () => {292 before(async () => {293 await usingApi(async () => {294 alice = privateKey('//Alice');295 bob = privateKey('//Bob');296 });297 });298 299 it('Reads access rights to properties of a collection', async () => {300 await usingApi(async api => {301 const collection = await createCollectionExpectSuccess();302 const propertyRights = (await api.query.common.collectionPropertyPermissions(collection)).toJSON();303 expect(propertyRights).to.be.empty;304 });305 });306 307 it('Sets access rights to properties of a collection', async () => {308 await usingApi(async api => {309 const collection = await createCollectionExpectSuccess();310311 await expect(executeTransaction(312 api, 313 alice, 314 api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true}}]), 315 )).to.not.be.rejected;316317 await addCollectionAdminExpectSuccess(alice, collection, bob.address);318319 await expect(executeTransaction(320 api, 321 alice, 322 api.tx.unique.setPropertyPermissions(collection, [{key: 'mindgame', permission: {collectionAdmin: true, tokenOwner: false}}]), 323 )).to.not.be.rejected;324325 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery', 'mindgame'])).toHuman();326 expect(propertyRights).to.be.deep.equal([327 {key: 'skullduggery', permission: {'mutable': true, 'collectionAdmin': false, 'tokenOwner': false}},328 {key: 'mindgame', permission: {'mutable': false, 'collectionAdmin': true, 'tokenOwner': false}},329 ]);330 });331 });332 333 it('Changes access rights to properties of a collection', async () => {334 await usingApi(async api => {335 const collection = await createCollectionExpectSuccess();336337 await expect(executeTransaction(338 api, 339 alice, 340 api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, collectionAdmin: true}}]), 341 )).to.not.be.rejected;342343 await expect(executeTransaction(344 api, 345 alice, 346 api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 347 )).to.not.be.rejected;348349 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();350 expect(propertyRights).to.be.deep.equal([351 {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},352 ]);353 });354 });355});356357describe('Negative Integration Test: Access Rights to Token Properties', () => {358 before(async () => {359 await usingApi(async () => {360 alice = privateKey('//Alice');361 bob = privateKey('//Bob');362 });363 });364365 it('Prevents from setting access rights to properties of a collection if not an onwer/admin', async () => {366 await usingApi(async api => {367 const collection = await createCollectionExpectSuccess();368369 await expect(executeTransaction(370 api, 371 bob, 372 api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, tokenOwner: true}}]), 373 )).to.be.rejectedWith(/common\.NoPermission/);374375 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toJSON();376 expect(propertyRights).to.be.empty;377 });378 });379380 it('Prevents from adding too many possible properties', async () => {381 await usingApi(async api => {382 const collection = await createCollectionExpectSuccess();383384 const constitution = [];385 for (let i = 0; i < 65; i++) {386 constitution.push({387 key: 'property_' + i,388 permission: Math.random() > 0.5 ? {mutable: true, collectionAdmin: true, tokenOwner: true} : {},389 });390 }391392 await expect(executeTransaction(393 api, 394 alice, 395 api.tx.unique.setPropertyPermissions(collection, constitution), 396 )).to.be.rejectedWith(/common\.PropertyLimitReached/);397398 const propertyRights = (await api.query.common.collectionPropertyPermissions(collection)).toJSON();399 expect(propertyRights).to.be.empty;400 });401 });402403 it('Prevents access rights to be modified if constant', async () => {404 await usingApi(async api => {405 const collection = await createCollectionExpectSuccess();406407 await expect(executeTransaction(408 api, 409 alice, 410 api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 411 )).to.not.be.rejected;412413 await expect(executeTransaction(414 api, 415 alice, 416 api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {}}]), 417 )).to.be.rejectedWith(/common\.NoPermission/);418419 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();420 expect(propertyRights).to.deep.equal([421 {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},422 ]);423 });424 });425426 it('Prevents adding properties with invalid names', async () => {427 await usingApi(async api => {428 const collection = await createCollectionExpectSuccess();429430 const invalidProperties = [431 [{key: 'skullduggery', permission: {tokenOwner: true}}, {key: 'im possible', permission: {collectionAdmin: true}}],432 [{key: 'G#4', permission: {tokenOwner: true}}],433 [{key: 'HÆMILTON', permission: {mutable: false, collectionAdmin: true, tokenOwner: true}}],434 ];435436 for (let i = 0; i < invalidProperties.length; i++) {437 await expect(executeTransaction(438 api, 439 alice, 440 api.tx.unique.setPropertyPermissions(collection, invalidProperties[i]), 441 ), `on setting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);442 }443444 await expect(executeTransaction(445 api, 446 alice, 447 api.tx.unique.setPropertyPermissions(collection, [{key: '', permission: {}}]), 448 ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);449450 const correctKey = '--0x03116e387820CA05'; // PolkadotJS would parse this as an already encoded hex-string451 await expect(executeTransaction(452 api, 453 alice, 454 api.tx.unique.setPropertyPermissions(collection, [455 {key: correctKey, permission: {collectionAdmin: true}},456 ]), 457 ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;458459 const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat(correctKey).concat('');460461 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, keys)).toHuman();462 expect(propertyRights).to.be.deep.equal([463 {key: correctKey, permission: {mutable: false, collectionAdmin: true, tokenOwner: false}},464 ]);465 });466 });467});468469// ---------- TOKEN PROPERTIES470471describe('Integration Test: Token Properties', () => {472 let collection: number;473 let token: number;474 let permissions: {permission: any, signers: IKeyringPair[]}[];475476 before(async () => {477 await usingApi(async () => {478 alice = privateKey('//Alice');479 bob = privateKey('//Bob');480 charlie = privateKey('//Charlie');481482 permissions = [483 {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob]},484 {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob]},485 {permission: {mutable: true, tokenOwner: true}, signers: [charlie]},486 {permission: {mutable: false, tokenOwner: true}, signers: [charlie]},487 {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},488 {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},489 ];490 });491 });492493 beforeEach(async () => {494 await usingApi(async () => {495 collection = await createCollectionExpectSuccess();496 token = await createItemExpectSuccess(alice, collection, 'NFT');497 await addCollectionAdminExpectSuccess(alice, collection, bob.address);498 await transferExpectSuccess(collection, token, alice, charlie);499 });500 });501 502 it('Reads yet empty properties of a token', async () => {503 await usingApi(async api => {504 const collection = await createCollectionExpectSuccess();505 const token = await createItemExpectSuccess(alice, collection, 'NFT');506 507 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();508 expect(properties.map).to.be.empty;509 expect(properties.consumedSpace).to.be.equal(0);510511 const tokenData = (await api.rpc.unique.tokenData(collection, token, ['anything'])).toJSON().properties;512 expect(tokenData).to.be.empty;513 });514 });515516 it('Assigns properties to a token according to permissions', async () => {517 await usingApi(async api => {518 const propertyKeys: string[] = [];519 let i = 0;520 for (const permission of permissions) {521 for (const signer of permission.signers) {522 const key = i + '_' + signer.address;523 propertyKeys.push(key);524525 await expect(executeTransaction(526 api, 527 alice, 528 api.tx.unique.setPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 529 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;530531 await expect(executeTransaction(532 api, 533 signer, 534 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 535 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;536 }537538 i++;539 }540541 const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toHuman() as any[];542 const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toHuman().properties as any[];543 for (let i = 0; i < properties.length; i++) {544 expect(properties[i].value).to.be.equal('Serotonin increase');545 expect(tokensData[i].value).to.be.equal('Serotonin increase');546 }547 });548 });549550 it('Changes properties of a token according to permissions', async () => {551 await usingApi(async api => {552 const propertyKeys: string[] = [];553 let i = 0;554 for (const permission of permissions) {555 if (!permission.permission.mutable) continue;556 557 for (const signer of permission.signers) {558 const key = i + '_' + signer.address;559 propertyKeys.push(key);560561 await expect(executeTransaction(562 api, 563 alice, 564 api.tx.unique.setPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 565 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;566567 await expect(executeTransaction(568 api, 569 signer, 570 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 571 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;572573 await expect(executeTransaction(574 api, 575 signer, 576 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin stable'}]), 577 ), `on changing property ${i} by ${signer.address}`).to.not.be.rejected;578 }579580 i++;581 }582583 const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toHuman() as any[];584 const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toHuman().properties as any[];585 for (let i = 0; i < properties.length; i++) {586 expect(properties[i].value).to.be.equal('Serotonin stable');587 expect(tokensData[i].value).to.be.equal('Serotonin stable');588 }589 });590 });591592 it('Deletes properties of a token according to permissions', async () => {593 await usingApi(async api => {594 const propertyKeys: string[] = [];595 let i = 0;596597 for (const permission of permissions) {598 if (!permission.permission.mutable) continue;599 600 for (const signer of permission.signers) {601 const key = i + '_' + signer.address;602 propertyKeys.push(key);603604 await expect(executeTransaction(605 api, 606 alice, 607 api.tx.unique.setPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 608 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;609610 await expect(executeTransaction(611 api, 612 signer, 613 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 614 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;615616 await expect(executeTransaction(617 api, 618 signer, 619 api.tx.unique.deleteTokenProperties(collection, token, [key]), 620 ), `on deleting property ${i} by ${signer.address}`).to.not.be.rejected;621 }622 623 i++;624 }625626 const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toJSON() as any[];627 expect(properties).to.be.empty;628 const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toJSON().properties as any[];629 expect(tokensData).to.be.empty;630 expect((await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace).to.be.equal(0);631 });632 });633});634635describe('Negative Integration Test: Token Properties', () => {636 let collection: number;637 let token: number;638 let originalSpace: number;639 let constitution: {permission: any, signers: IKeyringPair[], sinner: IKeyringPair}[];640641 before(async () => {642 await usingApi(async () => {643 alice = privateKey('//Alice');644 bob = privateKey('//Bob');645 charlie = privateKey('//Charlie');646 const dave = privateKey('//Dave');647648 constitution = [649 {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},650 {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},651 {permission: {mutable: true, tokenOwner: true}, signers: [charlie], sinner: alice},652 {permission: {mutable: false, tokenOwner: true}, signers: [charlie], sinner: alice},653 {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},654 {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},655 ];656 });657 });658659 beforeEach(async () => {660 collection = await createCollectionExpectSuccess();661 token = await createItemExpectSuccess(alice, collection, 'NFT');662 await addCollectionAdminExpectSuccess(alice, collection, bob.address);663 await transferExpectSuccess(collection, token, alice, charlie);664 665 await usingApi(async api => {666 let i = 0;667 for (const passage of constitution) {668 const signer = passage.signers[0];669 670 await expect(executeTransaction(671 api, 672 alice, 673 api.tx.unique.setPropertyPermissions(collection, [{key: `${i}`, permission: passage.permission}]), 674 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;675676 await expect(executeTransaction(677 api, 678 signer, 679 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin increase'}]), 680 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;681682 i++;683 }684685 originalSpace = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace as number;686 });687 });688689 it('Forbids changing/deleting properties of a token if the user is outside of permissions', async () => {690 await usingApi(async api => {691 let i = -1;692 for (const forbiddance of constitution) {693 i++;694 if (!forbiddance.permission.mutable) continue;695696 await expect(executeTransaction(697 api, 698 forbiddance.sinner, 699 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 700 ), `on failing to change property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);701702 await expect(executeTransaction(703 api, 704 forbiddance.sinner, 705 api.tx.unique.deleteTokenProperties(collection, token, [`${i}`]), 706 ), `on failing to delete property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);707 }708709 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();710 expect(properties.consumedSpace).to.be.equal(originalSpace);711 });712 });713714 it('Forbids changing/deleting properties of a token if the property is permanent (immutable)', async () => {715 await usingApi(async api => {716 let i = -1;717 for (const permission of constitution) {718 i++;719 if (permission.permission.mutable) continue;720721 await expect(executeTransaction(722 api, 723 permission.signers[0], 724 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 725 ), `on failing to change property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);726727 await expect(executeTransaction(728 api, 729 permission.signers[0], 730 api.tx.unique.deleteTokenProperties(collection, token, [i.toString()]), 731 ), `on failing to delete property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);732 }733734 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();735 expect(properties.consumedSpace).to.be.equal(originalSpace);736 });737 });738739 it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission', async () => {740 await usingApi(async api => {741 await expect(executeTransaction(742 api, 743 alice, 744 api.tx.unique.setTokenProperties(collection, token, [{key: 'non-existent', value: 'I exist!'}]), 745 ), 'on failing to add a previously non-existent property').to.be.rejectedWith(/common\.NoPermission/);746 747 await expect(executeTransaction(748 api, 749 alice, 750 api.tx.unique.setPropertyPermissions(collection, [{key: 'now-existent', permission: {}}]), 751 ), 'on setting a new non-permitted property').to.not.be.rejected;752753 await expect(executeTransaction(754 api, 755 alice, 756 api.tx.unique.setTokenProperties(collection, token, [{key: 'now-existent', value: 'I exist!'}]), 757 ), 'on failing to add a property forbidden by the \'None\' permission').to.be.rejectedWith(/common\.NoPermission/);758759 expect((await api.rpc.unique.tokenProperties(collection, token, ['non-existent', 'now-existent'])).toJSON()).to.be.empty;760 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();761 expect(properties.consumedSpace).to.be.equal(originalSpace);762 });763 });764765 it('Forbids adding too many properties to a token', async () => {766 await usingApi(async api => {767 await expect(executeTransaction(768 api, 769 alice, 770 api.tx.unique.setPropertyPermissions(collection, [771 {key: 'a_holy_book', permission: {collectionAdmin: true, tokenOwner: true}}, 772 {key: 'young_years', permission: {collectionAdmin: true, tokenOwner: true}},773 ]), 774 ), 'on setting a new non-permitted property').to.not.be.rejected;775776 // Mute the general tx parsing error777 {778 console.error = () => {};779 await expect(executeTransaction(780 api, 781 alice, 782 api.tx.unique.setCollectionProperties(collection, [{key: 'a_holy_book', value: 'word '.repeat(6554)}]), 783 )).to.be.rejected;784 }785786 await expect(executeTransaction(787 api, 788 alice, 789 api.tx.unique.setTokenProperties(collection, token, [790 {key: 'a_holy_book', value: 'word '.repeat(3277)}, 791 {key: 'young_years', value: 'neverending'.repeat(1490)},792 ]), 793 )).to.be.rejectedWith(/common\.NoSpaceForProperty/);794795 expect((await api.rpc.unique.tokenProperties(collection, token, ['a_holy_book', 'young years'])).toJSON()).to.be.empty;796 const propertiesMap = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();797 expect(propertiesMap.consumedSpace).to.be.equal(originalSpace);798 });799 });800});1import {expect} from 'chai';2import privateKey from '../substrate/privateKey';3import usingApi, {executeTransaction} from '../substrate/substrate-api';4import {5 addCollectionAdminExpectSuccess,6 createCollectionExpectSuccess,7 createItemExpectSuccess,8 getCreateCollectionResult,9 transferExpectSuccess,10} from '../util/helpers';11import {IKeyringPair} from '@polkadot/types/types';1213let alice: IKeyringPair;14let bob: IKeyringPair;15let charlie: IKeyringPair;1617describe('Composite Properties Test', () => {18 before(async () => {19 await usingApi(async () => {20 alice = privateKey('//Alice');21 bob = privateKey('//Bob');22 });23 });2425 it('Makes sure collectionById supplies required fields', async () => {26 await usingApi(async api => {27 const collectionId = await createCollectionExpectSuccess();2829 const collectionOption = await api.rpc.unique.collectionById(collectionId);30 expect(collectionOption.isSome).to.be.true;31 let collection = collectionOption.unwrap();32 expect(collection.tokenPropertyPermissions.toHuman()).to.be.empty;33 expect(collection.properties.toHuman()).to.be.empty;3435 const propertyPermissions = [36 {key: 'mindgame', permission: {collectionAdmin: true, mutable: false, tokenOwner: true}},37 {key: 'skullduggery', permission: {collectionAdmin: false, mutable: true, tokenOwner: false}},38 ];39 await expect(executeTransaction(40 api, 41 alice, 42 api.tx.unique.setPropertyPermissions(collectionId, propertyPermissions), 43 )).to.not.be.rejected;4445 const collectionProperties = [46 {key: 'black_hole', value: 'LIGO'},47 {key: 'electron', value: 'come bond'}, 48 ];49 await expect(executeTransaction(50 api, 51 alice, 52 api.tx.unique.setCollectionProperties(collectionId, collectionProperties), 53 )).to.not.be.rejected;5455 collection = (await api.rpc.unique.collectionById(collectionId)).unwrap();56 expect(collection.tokenPropertyPermissions.toHuman()).to.be.deep.equal(propertyPermissions);57 expect(collection.properties.toHuman()).to.be.deep.equal(collectionProperties);58 });59 });60});6162// ---------- COLLECTION PROPERTIES6364describe('Integration Test: Collection Properties', () => {65 before(async () => {66 await usingApi(async () => {67 alice = privateKey('//Alice');68 bob = privateKey('//Bob');69 });70 });7172 it('Reads properties from a collection', async () => {73 await usingApi(async api => {74 const collection = await createCollectionExpectSuccess();75 const properties = (await api.query.common.collectionProperties(collection)).toJSON();76 expect(properties.map).to.be.empty;77 expect(properties.consumedSpace).to.equal(0);78 });79 });8081 it('Sets properties for a collection', async () => {82 await usingApi(async api => {83 const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: 'NFT'}));84 const {collectionId} = getCreateCollectionResult(events);8586 // As owner87 await expect(executeTransaction(88 api, 89 bob, 90 api.tx.unique.setCollectionProperties(collectionId, [{key: 'electron', value: 'come bond'}]), 91 )).to.not.be.rejected;9293 await addCollectionAdminExpectSuccess(bob, collectionId, alice.address);9495 // As administrator96 await expect(executeTransaction(97 api, 98 alice, 99 api.tx.unique.setCollectionProperties(collectionId, [{key: 'black_hole'}]), 100 )).to.not.be.rejected;101102 const properties = (await api.rpc.unique.collectionProperties(collectionId, ['electron', 'black_hole'])).toHuman();103 expect(properties).to.be.deep.equal([104 {key: 'electron', value: 'come bond'},105 {key: 'black_hole', value: ''},106 ]);107 });108 });109110 it('Changes properties of a collection', async () => {111 await usingApi(async api => {112 const collection = await createCollectionExpectSuccess();113114 await expect(executeTransaction(115 api, 116 alice, 117 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole'}]), 118 )).to.not.be.rejected;119120 // Mutate the properties121 await expect(executeTransaction(122 api, 123 alice, 124 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'bonded'}, {key: 'black_hole', value: 'LIGO'}]), 125 )).to.not.be.rejected;126127 const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();128 expect(properties).to.be.deep.equal([129 {key: 'electron', value: 'bonded'},130 {key: 'black_hole', value: 'LIGO'},131 ]);132 });133 });134135 it('Deletes properties of a collection', async () => {136 await usingApi(async api => {137 const collection = await createCollectionExpectSuccess();138139 await expect(executeTransaction(140 api, 141 alice, 142 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]), 143 )).to.not.be.rejected;144145 await expect(executeTransaction(146 api, 147 alice, 148 api.tx.unique.deleteCollectionProperties(collection, ['electron']), 149 )).to.not.be.rejected;150151 const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();152 expect(properties).to.be.deep.equal([153 {key: 'black_hole', value: 'LIGO'},154 ]);155 });156 });157});158159describe('Negative Integration Test: Collection Properties', () => {160 before(async () => {161 await usingApi(async () => {162 alice = privateKey('//Alice');163 bob = privateKey('//Bob');164 });165 });166 167 it('Fails to set properties in a collection if not its onwer/administrator', async () => {168 await usingApi(async api => {169 const collection = await createCollectionExpectSuccess();170171 await expect(executeTransaction(172 api, 173 bob, 174 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]), 175 )).to.be.rejectedWith(/common\.NoPermission/);176 177 const properties = (await api.query.common.collectionProperties(collection)).toJSON();178 expect(properties.map).to.be.empty;179 expect(properties.consumedSpace).to.equal(0);180 });181 });182 183 it('Fails to set properties that exceed the limits', async () => {184 await usingApi(async api => {185 const collection = await createCollectionExpectSuccess();186 const spaceLimit = (await api.query.common.collectionProperties(collection)).toJSON().spaceLimit as number; 187188 // Mute the general tx parsing error, too many bytes to process189 {190 console.error = () => {};191 await expect(executeTransaction(192 api, 193 alice, 194 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 9))}]), 195 )).to.be.rejected;196 }197198 let properties = (await api.rpc.unique.collectionProperties(collection, ['electron'])).toJSON();199 expect(properties).to.be.empty;200201 await expect(executeTransaction(202 api, 203 alice, 204 api.tx.unique.setCollectionProperties(collection, [205 {key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 18))}, 206 {key: 'black_hole', value: '0'.repeat(Math.ceil(spaceLimit! / 2))}, 207 ]), 208 )).to.be.rejectedWith(/common\.NoSpaceForProperty/);209210 properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black hole'])).toJSON();211 expect(properties).to.be.empty;212 });213 });214 215 it('Fails to set more properties than it is allowed', async () => {216 await usingApi(async api => {217 const collection = await createCollectionExpectSuccess();218219 const propertiesToBeSet = [];220 for (let i = 0; i < 65; i++) {221 propertiesToBeSet.push({222 key: 'electron_' + i,223 value: Math.random() > 0.5 ? 'high' : 'low',224 });225 }226227 await expect(executeTransaction(228 api, 229 alice, 230 api.tx.unique.setCollectionProperties(collection, propertiesToBeSet), 231 )).to.be.rejectedWith(/common\.PropertyLimitReached/);232233 const properties = (await api.query.common.collectionProperties(collection)).toJSON();234 expect(properties.map).to.be.empty;235 expect(properties.consumedSpace).to.equal(0);236 });237 });238239 it('Fails to set properties with invalid names', async () => {240 await usingApi(async api => {241 const collection = await createCollectionExpectSuccess();242243 const invalidProperties = [244 [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}],245 [{key: 'Mr.Sandman', value: 'Bring me a gene'}],246 [{key: 'déjà vu', value: 'hmm...'}],247 ];248249 for (let i = 0; i < invalidProperties.length; i++) {250 await expect(executeTransaction(251 api, 252 alice, 253 api.tx.unique.setCollectionProperties(collection, invalidProperties[i]), 254 ), `on rejecting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);255 }256257 await expect(executeTransaction(258 api, 259 alice, 260 api.tx.unique.setCollectionProperties(collection, [{key: '', value: 'nothing must not exist'}]), 261 ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);262263 await expect(executeTransaction(264 api, 265 alice, 266 api.tx.unique.setCollectionProperties(collection, [267 {key: 'CRISPR-Cas9', value: 'rewriting nature!'},268 ]), 269 ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;270271 const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat('CRISPR-Cas9').concat('');272273 const properties = (await api.rpc.unique.collectionProperties(collection, keys)).toHuman();274 expect(properties).to.be.deep.equal([275 {key: 'CRISPR-Cas9', value: 'rewriting nature!'},276 ]);277278 for (let i = 0; i < invalidProperties.length; i++) {279 await expect(executeTransaction(280 api, 281 alice, 282 api.tx.unique.deleteCollectionProperties(collection, invalidProperties[i].map(propertySet => propertySet.key)), 283 ), `on trying to delete the non-existent badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);284 }285 });286 });287});288289// ---------- ACCESS RIGHTS290291describe('Integration Test: Access Rights to Token Properties', () => {292 before(async () => {293 await usingApi(async () => {294 alice = privateKey('//Alice');295 bob = privateKey('//Bob');296 });297 });298 299 it('Reads access rights to properties of a collection', async () => {300 await usingApi(async api => {301 const collection = await createCollectionExpectSuccess();302 const propertyRights = (await api.query.common.collectionPropertyPermissions(collection)).toJSON();303 expect(propertyRights).to.be.empty;304 });305 });306 307 it('Sets access rights to properties of a collection', async () => {308 await usingApi(async api => {309 const collection = await createCollectionExpectSuccess();310311 await expect(executeTransaction(312 api, 313 alice, 314 api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true}}]), 315 )).to.not.be.rejected;316317 await addCollectionAdminExpectSuccess(alice, collection, bob.address);318319 await expect(executeTransaction(320 api, 321 alice, 322 api.tx.unique.setPropertyPermissions(collection, [{key: 'mindgame', permission: {collectionAdmin: true, tokenOwner: false}}]), 323 )).to.not.be.rejected;324325 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery', 'mindgame'])).toHuman();326 expect(propertyRights).to.be.deep.equal([327 {key: 'skullduggery', permission: {'mutable': true, 'collectionAdmin': false, 'tokenOwner': false}},328 {key: 'mindgame', permission: {'mutable': false, 'collectionAdmin': true, 'tokenOwner': false}},329 ]);330 });331 });332 333 it('Changes access rights to properties of a collection', async () => {334 await usingApi(async api => {335 const collection = await createCollectionExpectSuccess();336337 await expect(executeTransaction(338 api, 339 alice, 340 api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, collectionAdmin: true}}]), 341 )).to.not.be.rejected;342343 await expect(executeTransaction(344 api, 345 alice, 346 api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 347 )).to.not.be.rejected;348349 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();350 expect(propertyRights).to.be.deep.equal([351 {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},352 ]);353 });354 });355});356357describe('Negative Integration Test: Access Rights to Token Properties', () => {358 before(async () => {359 await usingApi(async () => {360 alice = privateKey('//Alice');361 bob = privateKey('//Bob');362 });363 });364365 it('Prevents from setting access rights to properties of a collection if not an onwer/admin', async () => {366 await usingApi(async api => {367 const collection = await createCollectionExpectSuccess();368369 await expect(executeTransaction(370 api, 371 bob, 372 api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, tokenOwner: true}}]), 373 )).to.be.rejectedWith(/common\.NoPermission/);374375 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toJSON();376 expect(propertyRights).to.be.empty;377 });378 });379380 it('Prevents from adding too many possible properties', async () => {381 await usingApi(async api => {382 const collection = await createCollectionExpectSuccess();383384 const constitution = [];385 for (let i = 0; i < 65; i++) {386 constitution.push({387 key: 'property_' + i,388 permission: Math.random() > 0.5 ? {mutable: true, collectionAdmin: true, tokenOwner: true} : {},389 });390 }391392 await expect(executeTransaction(393 api, 394 alice, 395 api.tx.unique.setPropertyPermissions(collection, constitution), 396 )).to.be.rejectedWith(/common\.PropertyLimitReached/);397398 const propertyRights = (await api.query.common.collectionPropertyPermissions(collection)).toJSON();399 expect(propertyRights).to.be.empty;400 });401 });402403 it('Prevents access rights to be modified if constant', async () => {404 await usingApi(async api => {405 const collection = await createCollectionExpectSuccess();406407 await expect(executeTransaction(408 api, 409 alice, 410 api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 411 )).to.not.be.rejected;412413 await expect(executeTransaction(414 api, 415 alice, 416 api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {}}]), 417 )).to.be.rejectedWith(/common\.NoPermission/);418419 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();420 expect(propertyRights).to.deep.equal([421 {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},422 ]);423 });424 });425426 it('Prevents adding properties with invalid names', async () => {427 await usingApi(async api => {428 const collection = await createCollectionExpectSuccess();429430 const invalidProperties = [431 [{key: 'skullduggery', permission: {tokenOwner: true}}, {key: 'im possible', permission: {collectionAdmin: true}}],432 [{key: 'G#4', permission: {tokenOwner: true}}],433 [{key: 'HÆMILTON', permission: {mutable: false, collectionAdmin: true, tokenOwner: true}}],434 ];435436 for (let i = 0; i < invalidProperties.length; i++) {437 await expect(executeTransaction(438 api, 439 alice, 440 api.tx.unique.setPropertyPermissions(collection, invalidProperties[i]), 441 ), `on setting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);442 }443444 await expect(executeTransaction(445 api, 446 alice, 447 api.tx.unique.setPropertyPermissions(collection, [{key: '', permission: {}}]), 448 ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);449450 const correctKey = '--0x03116e387820CA05'; // PolkadotJS would parse this as an already encoded hex-string451 await expect(executeTransaction(452 api, 453 alice, 454 api.tx.unique.setPropertyPermissions(collection, [455 {key: correctKey, permission: {collectionAdmin: true}},456 ]), 457 ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;458459 const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat(correctKey).concat('');460461 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, keys)).toHuman();462 expect(propertyRights).to.be.deep.equal([463 {key: correctKey, permission: {mutable: false, collectionAdmin: true, tokenOwner: false}},464 ]);465 });466 });467});468469// ---------- TOKEN PROPERTIES470471describe('Integration Test: Token Properties', () => {472 let collection: number;473 let token: number;474 let permissions: {permission: any, signers: IKeyringPair[]}[];475476 before(async () => {477 await usingApi(async () => {478 alice = privateKey('//Alice');479 bob = privateKey('//Bob');480 charlie = privateKey('//Charlie');481482 permissions = [483 {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob]},484 {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob]},485 {permission: {mutable: true, tokenOwner: true}, signers: [charlie]},486 {permission: {mutable: false, tokenOwner: true}, signers: [charlie]},487 {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},488 {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},489 ];490 });491 });492493 beforeEach(async () => {494 await usingApi(async () => {495 collection = await createCollectionExpectSuccess();496 token = await createItemExpectSuccess(alice, collection, 'NFT');497 await addCollectionAdminExpectSuccess(alice, collection, bob.address);498 await transferExpectSuccess(collection, token, alice, charlie);499 });500 });501 502 it('Reads yet empty properties of a token', async () => {503 await usingApi(async api => {504 const collection = await createCollectionExpectSuccess();505 const token = await createItemExpectSuccess(alice, collection, 'NFT');506 507 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();508 expect(properties.map).to.be.empty;509 expect(properties.consumedSpace).to.be.equal(0);510511 const tokenData = (await api.rpc.unique.tokenData(collection, token, ['anything'])).toJSON().properties;512 expect(tokenData).to.be.empty;513 });514 });515516 it('Assigns properties to a token according to permissions', async () => {517 await usingApi(async api => {518 const propertyKeys: string[] = [];519 let i = 0;520 for (const permission of permissions) {521 for (const signer of permission.signers) {522 const key = i + '_' + signer.address;523 propertyKeys.push(key);524525 await expect(executeTransaction(526 api, 527 alice, 528 api.tx.unique.setPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 529 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;530531 await expect(executeTransaction(532 api, 533 signer, 534 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 535 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;536 }537538 i++;539 }540541 const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toHuman() as any[];542 const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toHuman().properties as any[];543 for (let i = 0; i < properties.length; i++) {544 expect(properties[i].value).to.be.equal('Serotonin increase');545 expect(tokensData[i].value).to.be.equal('Serotonin increase');546 }547 });548 });549550 it('Changes properties of a token according to permissions', async () => {551 await usingApi(async api => {552 const propertyKeys: string[] = [];553 let i = 0;554 for (const permission of permissions) {555 if (!permission.permission.mutable) continue;556 557 for (const signer of permission.signers) {558 const key = i + '_' + signer.address;559 propertyKeys.push(key);560561 await expect(executeTransaction(562 api, 563 alice, 564 api.tx.unique.setPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 565 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;566567 await expect(executeTransaction(568 api, 569 signer, 570 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 571 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;572573 await expect(executeTransaction(574 api, 575 signer, 576 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin stable'}]), 577 ), `on changing property ${i} by ${signer.address}`).to.not.be.rejected;578 }579580 i++;581 }582583 const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toHuman() as any[];584 const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toHuman().properties as any[];585 for (let i = 0; i < properties.length; i++) {586 expect(properties[i].value).to.be.equal('Serotonin stable');587 expect(tokensData[i].value).to.be.equal('Serotonin stable');588 }589 });590 });591592 it('Deletes properties of a token according to permissions', async () => {593 await usingApi(async api => {594 const propertyKeys: string[] = [];595 let i = 0;596597 for (const permission of permissions) {598 if (!permission.permission.mutable) continue;599 600 for (const signer of permission.signers) {601 const key = i + '_' + signer.address;602 propertyKeys.push(key);603604 await expect(executeTransaction(605 api, 606 alice, 607 api.tx.unique.setPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 608 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;609610 await expect(executeTransaction(611 api, 612 signer, 613 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 614 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;615616 await expect(executeTransaction(617 api, 618 signer, 619 api.tx.unique.deleteTokenProperties(collection, token, [key]), 620 ), `on deleting property ${i} by ${signer.address}`).to.not.be.rejected;621 }622 623 i++;624 }625626 const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toJSON() as any[];627 expect(properties).to.be.empty;628 const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toJSON().properties as any[];629 expect(tokensData).to.be.empty;630 expect((await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace).to.be.equal(0);631 });632 });633});634635describe('Negative Integration Test: Token Properties', () => {636 let collection: number;637 let token: number;638 let originalSpace: number;639 let constitution: {permission: any, signers: IKeyringPair[], sinner: IKeyringPair}[];640641 before(async () => {642 await usingApi(async () => {643 alice = privateKey('//Alice');644 bob = privateKey('//Bob');645 charlie = privateKey('//Charlie');646 const dave = privateKey('//Dave');647648 constitution = [649 {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},650 {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},651 {permission: {mutable: true, tokenOwner: true}, signers: [charlie], sinner: alice},652 {permission: {mutable: false, tokenOwner: true}, signers: [charlie], sinner: alice},653 {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},654 {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},655 ];656 });657 });658659 beforeEach(async () => {660 collection = await createCollectionExpectSuccess();661 token = await createItemExpectSuccess(alice, collection, 'NFT');662 await addCollectionAdminExpectSuccess(alice, collection, bob.address);663 await transferExpectSuccess(collection, token, alice, charlie);664 665 await usingApi(async api => {666 let i = 0;667 for (const passage of constitution) {668 const signer = passage.signers[0];669 670 await expect(executeTransaction(671 api, 672 alice, 673 api.tx.unique.setPropertyPermissions(collection, [{key: `${i}`, permission: passage.permission}]), 674 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;675676 await expect(executeTransaction(677 api, 678 signer, 679 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin increase'}]), 680 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;681682 i++;683 }684685 originalSpace = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace as number;686 });687 });688689 it('Forbids changing/deleting properties of a token if the user is outside of permissions', async () => {690 await usingApi(async api => {691 let i = -1;692 for (const forbiddance of constitution) {693 i++;694 if (!forbiddance.permission.mutable) continue;695696 await expect(executeTransaction(697 api, 698 forbiddance.sinner, 699 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 700 ), `on failing to change property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);701702 await expect(executeTransaction(703 api, 704 forbiddance.sinner, 705 api.tx.unique.deleteTokenProperties(collection, token, [`${i}`]), 706 ), `on failing to delete property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);707 }708709 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();710 expect(properties.consumedSpace).to.be.equal(originalSpace);711 });712 });713714 it('Forbids changing/deleting properties of a token if the property is permanent (immutable)', async () => {715 await usingApi(async api => {716 let i = -1;717 for (const permission of constitution) {718 i++;719 if (permission.permission.mutable) continue;720721 await expect(executeTransaction(722 api, 723 permission.signers[0], 724 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 725 ), `on failing to change property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);726727 await expect(executeTransaction(728 api, 729 permission.signers[0], 730 api.tx.unique.deleteTokenProperties(collection, token, [i.toString()]), 731 ), `on failing to delete property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);732 }733734 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();735 expect(properties.consumedSpace).to.be.equal(originalSpace);736 });737 });738739 it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission', async () => {740 await usingApi(async api => {741 await expect(executeTransaction(742 api, 743 alice, 744 api.tx.unique.setTokenProperties(collection, token, [{key: 'non-existent', value: 'I exist!'}]), 745 ), 'on failing to add a previously non-existent property').to.be.rejectedWith(/common\.NoPermission/);746 747 await expect(executeTransaction(748 api, 749 alice, 750 api.tx.unique.setPropertyPermissions(collection, [{key: 'now-existent', permission: {}}]), 751 ), 'on setting a new non-permitted property').to.not.be.rejected;752753 await expect(executeTransaction(754 api, 755 alice, 756 api.tx.unique.setTokenProperties(collection, token, [{key: 'now-existent', value: 'I exist!'}]), 757 ), 'on failing to add a property forbidden by the \'None\' permission').to.be.rejectedWith(/common\.NoPermission/);758759 expect((await api.rpc.unique.tokenProperties(collection, token, ['non-existent', 'now-existent'])).toJSON()).to.be.empty;760 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();761 expect(properties.consumedSpace).to.be.equal(originalSpace);762 });763 });764765 it('Forbids adding too many properties to a token', async () => {766 await usingApi(async api => {767 await expect(executeTransaction(768 api, 769 alice, 770 api.tx.unique.setPropertyPermissions(collection, [771 {key: 'a_holy_book', permission: {collectionAdmin: true, tokenOwner: true}}, 772 {key: 'young_years', permission: {collectionAdmin: true, tokenOwner: true}},773 ]), 774 ), 'on setting a new non-permitted property').to.not.be.rejected;775776 // Mute the general tx parsing error777 {778 console.error = () => {};779 await expect(executeTransaction(780 api, 781 alice, 782 api.tx.unique.setCollectionProperties(collection, [{key: 'a_holy_book', value: 'word '.repeat(6554)}]), 783 )).to.be.rejected;784 }785786 await expect(executeTransaction(787 api, 788 alice, 789 api.tx.unique.setTokenProperties(collection, token, [790 {key: 'a_holy_book', value: 'word '.repeat(3277)}, 791 {key: 'young_years', value: 'neverending'.repeat(1490)},792 ]), 793 )).to.be.rejectedWith(/common\.NoSpaceForProperty/);794795 expect((await api.rpc.unique.tokenProperties(collection, token, ['a_holy_book', 'young_years'])).toJSON()).to.be.empty;796 const propertiesMap = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();797 expect(propertiesMap.consumedSpace).to.be.equal(originalSpace);798 });799 });800});tests/src/setConstOnChainSchema.test.tsdiffbeforeafterboth--- a/tests/src/setConstOnChainSchema.test.ts
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {Keyring} from '@polkadot/api';
-import {IKeyringPair} from '@polkadot/types/types';
-import chai from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-import {default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync} from './substrate/substrate-api';
-import {
- createCollectionExpectSuccess,
- destroyCollectionExpectSuccess,
- addCollectionAdminExpectSuccess,
- queryCollectionExpectSuccess,
- getCreatedCollectionCount,
-} from './util/helpers';
-
-chai.use(chaiAsPromised);
-const expect = chai.expect;
-
-let alice: IKeyringPair;
-let bob: IKeyringPair;
-let schema: any;
-let largeSchema: any;
-
-before(async () => {
- await usingApi(async () => {
- const keyring = new Keyring({type: 'sr25519'});
- alice = keyring.addFromUri('//Alice');
- bob = keyring.addFromUri('//Bob');
- schema = '0x31';
- largeSchema = new Array(1024 * 1024 + 10).fill(0xff);
- });
-});
-describe('Integration Test ext. setConstOnChainSchema()', () => {
-
- it('Run extrinsic with parameters of the collection id, set the scheme', async () => {
- await usingApi(async (api) => {
- const collectionId = await createCollectionExpectSuccess();
- const collection = await queryCollectionExpectSuccess(api, collectionId);
- expect(collection.owner.toString()).to.be.eq(alice.address);
- const setSchema = api.tx.unique.setConstOnChainSchema(collectionId, schema);
- await submitTransactionAsync(alice, setSchema);
- });
- });
-
- it('Collection admin can set the scheme', async () => {
- await usingApi(async (api) => {
- const collectionId = await createCollectionExpectSuccess();
- const collection = await queryCollectionExpectSuccess(api, collectionId);
- expect(collection.owner.toString()).to.be.eq(alice.address);
- await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
- const setSchema = api.tx.unique.setConstOnChainSchema(collectionId, schema);
- await submitTransactionAsync(bob, setSchema);
- });
- });
-
- it('Checking collection data using the ConstOnChainSchema parameter', async () => {
- await usingApi(async (api) => {
- const collectionId = await createCollectionExpectSuccess();
- const setSchema = api.tx.unique.setConstOnChainSchema(collectionId, schema);
- await submitTransactionAsync(alice, setSchema);
- const collection = await queryCollectionExpectSuccess(api, collectionId);
- expect(collection.constOnChainSchema.toString()).to.be.eq(schema);
- });
- });
-});
-
-describe('Negative Integration Test ext. setConstOnChainSchema()', () => {
-
- it('Set a non-existent collection', async () => {
- await usingApi(async (api) => {
- // tslint:disable-next-line: radix
- const collectionId = await getCreatedCollectionCount(api) + 1;
- const setSchema = api.tx.unique.setConstOnChainSchema(collectionId, schema);
- await expect(submitTransactionExpectFailAsync(alice, setSchema)).to.be.rejected;
- });
- });
-
- it('Set a previously deleted collection', async () => {
- await usingApi(async (api) => {
- const collectionId = await createCollectionExpectSuccess();
- await destroyCollectionExpectSuccess(collectionId);
- const setSchema = api.tx.unique.setConstOnChainSchema(collectionId, schema);
- await expect(submitTransactionExpectFailAsync(alice, setSchema)).to.be.rejected;
- });
- });
-
- it('Set invalid data in schema (size too large:> 1MB)', async () => {
- await usingApi(async (api) => {
- const collectionId = await createCollectionExpectSuccess();
- const setSchema = api.tx.unique.setConstOnChainSchema(collectionId, largeSchema);
- await expect(submitTransactionExpectFailAsync(alice, setSchema)).to.be.rejected;
- });
- });
-
- it('Execute method not on behalf of the collection owner', async () => {
- await usingApi(async (api) => {
- const collectionId = await createCollectionExpectSuccess();
- const collection = await queryCollectionExpectSuccess(api, collectionId);
- expect(collection.owner.toString()).to.be.eq(alice.address);
- const setSchema = api.tx.unique.setConstOnChainSchema(collectionId, schema);
- await expect(submitTransactionExpectFailAsync(bob, setSchema)).to.be.rejected;
- });
- });
-
-});
tests/src/setOffchainSchema.test.tsdiffbeforeafterboth--- a/tests/src/setOffchainSchema.test.ts
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {IKeyringPair} from '@polkadot/types/types';
-import chai from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-import privateKey from './substrate/privateKey';
-import usingApi from './substrate/substrate-api';
-import {
- createCollectionExpectSuccess,
- destroyCollectionExpectSuccess,
- findNotExistingCollection,
- queryCollectionExpectSuccess,
- setOffchainSchemaExpectFailure,
- setOffchainSchemaExpectSuccess,
- addCollectionAdminExpectSuccess,
-} from './util/helpers';
-
-chai.use(chaiAsPromised);
-const expect = chai.expect;
-
-const DATA = [1, 2, 3, 4];
-
-describe('Integration Test setOffchainSchema', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingApi(async () => {
- alice = privateKey('//Alice');
- bob = privateKey('//Bob');
- });
- });
-
- it('execute setOffchainSchema, verify data was set', async () => {
- await usingApi(async api => {
- const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
- await setOffchainSchemaExpectSuccess(alice, collectionId, DATA);
- const collection = await queryCollectionExpectSuccess(api, collectionId);
-
- expect('0x' + Buffer.from(collection.offchainSchema).toString('hex')).to.be.equal('0x' + Buffer.from(DATA).toString('hex'));
- });
- });
-
- it('execute setOffchainSchema (collection admin), verify data was set', async () => {
- await usingApi(async api => {
- const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
- await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
- await setOffchainSchemaExpectSuccess(bob, collectionId, DATA);
- const collection = await queryCollectionExpectSuccess(api, collectionId);
-
- expect('0x' + Buffer.from(collection.offchainSchema).toString('hex')).to.be.equal('0x' + Buffer.from(DATA).toString('hex'));
- });
- });
-});
-
-describe('Negative Integration Test setOffchainSchema', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- let validCollectionId: number;
-
- before(async () => {
- await usingApi(async () => {
- alice = privateKey('//Alice');
- bob = privateKey('//Bob');
-
- validCollectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
- });
- });
-
- it('fails on not existing collection id', async () => {
- const nonExistingCollectionId = await usingApi(findNotExistingCollection);
-
- await setOffchainSchemaExpectFailure(alice, nonExistingCollectionId, DATA);
- });
-
- it('fails on destroyed collection id', async () => {
- const destroyedCollectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
- await destroyCollectionExpectSuccess(destroyedCollectionId);
-
- await setOffchainSchemaExpectFailure(alice, destroyedCollectionId, DATA);
- });
-
- it('fails on too long data', async () => {
- const tooLongData = new Array(8 * 1024 + 10).fill(0xff);
-
- await setOffchainSchemaExpectFailure(alice, validCollectionId, tooLongData);
- });
-
- it('fails on execution by non-owner', async () => {
- await setOffchainSchemaExpectFailure(bob, validCollectionId, DATA);
- });
-});
tests/src/setSchemaVersion.test.tsdiffbeforeafterboth--- a/tests/src/setSchemaVersion.test.ts
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-// https://unique-network.readthedocs.io/en/latest/jsapi.html#setschemaversion
-import {ApiPromise, Keyring} from '@polkadot/api';
-import {IKeyringPair} from '@polkadot/types/types';
-import chai from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-import usingApi, {submitTransactionAsync, submitTransactionExpectFailAsync} from './substrate/substrate-api';
-import {
- createCollectionExpectSuccess,
- destroyCollectionExpectSuccess,
- getCreatedCollectionCount,
- getCreateItemResult,
- getDetailedCollectionInfo,
- addCollectionAdminExpectSuccess,
-} from './util/helpers';
-
-chai.use(chaiAsPromised);
-const expect = chai.expect;
-
-let alice: IKeyringPair;
-let bob: IKeyringPair;
-let charlie: IKeyringPair;
-
-/*
-1. We create collection.
-2. Save just created collection id.
-3. Use this id for setSchemaVersion.
-*/
-describe('setSchemaVersion positive', () => {
- let tx;
- before(async () => {
- await usingApi(async () => {
- const keyring = new Keyring({type: 'sr25519'});
- alice = keyring.addFromUri('//Alice');
- });
- });
- it('execute setSchemaVersion with image url and unique ', async () => {
- await usingApi(async (api: ApiPromise) => {
- const collectionIdForTesting = await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}});
- tx = api.tx.unique.setSchemaVersion(collectionIdForTesting, 'Unique');
- const events = await submitTransactionAsync(alice, tx);
- const result = getCreateItemResult(events);
- const collectionInfo = await getDetailedCollectionInfo(api, collectionIdForTesting);
- // tslint:disable-next-line:no-unused-expression
- expect(result.success).to.be.true;
- // tslint:disable-next-line:no-unused-expression
- expect(collectionInfo).to.be.exist;
- // tslint:disable-next-line:no-unused-expression
- expect(collectionInfo ? collectionInfo.schemaVersion.toString() : '').to.be.equal('Unique');
- });
- });
-});
-
-describe('Collection admin setSchemaVersion positive', () => {
- let tx;
- let collectionIdForTesting: any;
-
- before(async () => {
- await usingApi(async () => {
- const keyring = new Keyring({type: 'sr25519'});
- alice = keyring.addFromUri('//Alice');
- bob = keyring.addFromUri('//Bob');
- collectionIdForTesting = await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}});
- await addCollectionAdminExpectSuccess(alice, collectionIdForTesting, bob.address);
- });
- });
- it('execute setSchemaVersion with image url and unique ', async () => {
- await usingApi(async (api: ApiPromise) => {
- tx = api.tx.unique.setSchemaVersion(collectionIdForTesting, 'Unique');
- const events = await submitTransactionAsync(bob, tx);
- const result = getCreateItemResult(events);
- const collectionInfo = await getDetailedCollectionInfo(api, collectionIdForTesting);
- // tslint:disable-next-line:no-unused-expression
- expect(result.success).to.be.true;
- // tslint:disable-next-line:no-unused-expression
- expect(collectionInfo).to.be.exist;
- // tslint:disable-next-line:no-unused-expression
- expect(collectionInfo ? collectionInfo.schemaVersion.toString() : '').to.be.equal('Unique');
- });
- });
-
- it('validate schema version with just entered data', async () => {
- await usingApi(async (api: ApiPromise) => {
- tx = api.tx.unique.setSchemaVersion(collectionIdForTesting, 'ImageURL');
- const events = await submitTransactionAsync(bob, tx);
- const result = getCreateItemResult(events);
- const collectionInfo = await getDetailedCollectionInfo(api, collectionIdForTesting);
- // tslint:disable-next-line:no-unused-expression
- expect(result.success).to.be.true;
- // tslint:disable-next-line:no-unused-expression
- expect(collectionInfo).to.be.exist;
- // tslint:disable-next-line:no-unused-expression
- expect(collectionInfo ? collectionInfo.schemaVersion.toString() : '').to.be.equal('ImageURL');
- });
- });
-});
-
-describe('setSchemaVersion negative', () => {
- let tx;
- let collectionIdForTesting: any;
- before(async () => {
- await usingApi(async () => {
- const keyring = new Keyring({type: 'sr25519'});
- alice = keyring.addFromUri('//Alice');
- charlie = keyring.addFromUri('//Charlie');
- collectionIdForTesting = await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}});
- });
- });
- it('execute setSchemaVersion for not exists collection', async () => {
- await usingApi(async (api: ApiPromise) => {
- const collectionCount = await getCreatedCollectionCount(api);
- const nonExistedCollectionId = collectionCount + 1;
- tx = api.tx.unique.setSchemaVersion(nonExistedCollectionId, 'ImageURL');
- await expect(submitTransactionExpectFailAsync(alice, tx)).to.be.rejected;
- });
- });
- it('execute setSchemaVersion for deleted collection', async () => {
- await usingApi(async (api: ApiPromise) => {
- await destroyCollectionExpectSuccess(collectionIdForTesting);
- tx = api.tx.unique.setSchemaVersion(collectionIdForTesting, 'ImageURL');
- await expect(submitTransactionExpectFailAsync(alice, tx)).to.be.rejected;
- });
- });
- it('Regular user can`t execute setSchemaVersion with image url and unique ', async () => {
- await usingApi(async (api: ApiPromise) => {
- tx = api.tx.unique.setSchemaVersion(collectionIdForTesting, 'Unique');
- await expect(submitTransactionAsync(charlie, tx)).to.be.rejected;
- });
- });
-});
tests/src/util/helpers.tsdiffbeforeafterboth--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -27,7 +27,7 @@
import privateKey from '../substrate/privateKey';
import {default as usingApi, executeTransaction, submitTransactionAsync, submitTransactionExpectFailAsync} from '../substrate/substrate-api';
import {hexToStr, strToUTF16, utf16ToStr} from './util';
-import {UpDataStructsRpcCollection, UpDataStructsCreateItemData} from '@polkadot/types/lookup';
+import {UpDataStructsRpcCollection, UpDataStructsCreateItemData, UpDataStructsProperty} from '@polkadot/types/lookup';
chai.use(chaiAsPromised);
const expect = chai.expect;
@@ -141,7 +141,6 @@
export interface IReFungibleTokenDataType {
owner: IReFungibleOwner[];
- constData: number[];
}
export function uniqueEventMessage(events: EventRecord[]): IGetMessage {
@@ -784,7 +783,7 @@
});
}
-export async function setOffchainSchemaExpectSuccess(sender: IKeyringPair, collectionId: number, data: number[]) {
+/*export async function setOffchainSchemaExpectSuccess(sender: IKeyringPair, collectionId: number, data: number[]) {
await usingApi(async (api) => {
const tx = api.tx.unique.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));
const events = await submitTransactionAsync(sender, tx);
@@ -799,7 +798,7 @@
const tx = api.tx.unique.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));
await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
});
-}
+}*/
export interface CreateFungibleData {
readonly Value: bigint;
@@ -1111,12 +1110,20 @@
): Promise<string[]> {
return (await api.rpc.unique.adminlist(collectionId)).toHuman() as any;
}
-export async function getConstMetadata(
+/*export async function getConstMetadata(
api: ApiPromise,
collectionId: number,
tokenId: number,
): Promise<number[]> {
return [...(await api.rpc.unique.constMetadata(collectionId, tokenId))];
+}*/
+export async function getTokenProperties(
+ api: ApiPromise,
+ collectionId: number,
+ tokenId: number,
+ propertyKeys: string[],
+): Promise<UpDataStructsProperty[]> {
+ return (await api.rpc.unique.tokenProperties(collectionId, tokenId, propertyKeys)).toHuman() as any;
}
export async function createFungibleItemExpectSuccess(
@@ -1150,18 +1157,6 @@
});
}
-export async function createMultipleItemsWithPropsExpectFailure(sender: IKeyringPair, collectionId: number, itemsData: any, owner: CrossAccountId | string = sender.address) {
- await usingApi(async (api) => {
- const to = normalizeAccountId(owner);
- const tx = api.tx.unique.createMultipleItems(collectionId, to, itemsData);
-
- const events = await expect(await submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
- const result = getCreateItemsResult(events);
-
- expect(result).to.be.equal(false);
- });
-}
-
export async function createMultipleItemsExWithPropsExpectSuccess(sender: IKeyringPair, collectionId: number, itemsData: any) {
await usingApi(async (api) => {
const tx = api.tx.unique.createMultipleItemsEx(collectionId, itemsData);
@@ -1187,10 +1182,10 @@
const createData = {fungible: {value: 10}};
tx = api.tx.unique.createItem(collectionId, to, createData as any);
} else if (createMode === 'ReFungible') {
- const createData = {refungible: {const_data: [], pieces: 100}};
+ const createData = {refungible: {pieces: 100}};
tx = api.tx.unique.createItem(collectionId, to, createData as any);
} else {
- const data = api.createType('UpDataStructsCreateItemData', {NFT: {constData: 'test', properties: props}});
+ const data = api.createType('UpDataStructsCreateItemData', {NFT: {properties: props}});
tx = api.tx.unique.createItem(collectionId, to, data as UpDataStructsCreateItemData);
}
@@ -1225,7 +1220,7 @@
let tx;
if (createMode === 'NFT') {
- const data = api.createType('UpDataStructsCreateItemData', {NFT: {constData: 'test', properties: props}});
+ const data = api.createType('UpDataStructsCreateItemData', {NFT: {properties: props}});
tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), data);
} else {
tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), createMode);
@@ -1251,10 +1246,10 @@
const createData = {fungible: {value: 10}};
tx = api.tx.unique.createItem(collectionId, to, createData as any);
} else if (createMode === 'ReFungible') {
- const createData = {refungible: {const_data: [], pieces: 100}};
+ const createData = {refungible: {pieces: 100}};
tx = api.tx.unique.createItem(collectionId, to, createData as any);
} else {
- const createData = {nft: {const_data: []}};
+ const createData = {nft: {}};
tx = api.tx.unique.createItem(collectionId, to, createData as any);
}