difftreelog
Merge pull request #426 from UniqueNetwork/feature/token_owners
in: master
31 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5953,7 +5953,7 @@
[[package]]
name = "pallet-fungible"
-version = "0.1.0"
+version = "0.1.1"
dependencies = [
"ethereum",
"evm-coder",
@@ -6198,7 +6198,7 @@
[[package]]
name = "pallet-nonfungible"
-version = "0.1.0"
+version = "0.1.1"
dependencies = [
"ethereum",
"evm-coder",
@@ -12377,7 +12377,7 @@
[[package]]
name = "uc-rpc"
-version = "0.1.0"
+version = "0.1.1"
dependencies = [
"anyhow",
"jsonrpsee",
@@ -12682,7 +12682,7 @@
[[package]]
name = "unique-runtime-common"
-version = "0.9.24"
+version = "0.9.25"
dependencies = [
"evm-coder",
"fp-rpc",
@@ -12754,7 +12754,7 @@
[[package]]
name = "up-rpc"
-version = "0.1.0"
+version = "0.1.1"
dependencies = [
"pallet-common",
"pallet-evm",
client/rpc/CHANGELOG.mddiffbeforeafterboth--- /dev/null
+++ b/client/rpc/CHANGELOG.md
@@ -0,0 +1,11 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+
+## [0.1.1] - 2022-07-14
+
+### Added
+
+ - Implementation of RPC method `token_owners` returning 10 owners in no particular order.
+ This was an internal request to improve the web interface and support fractionalization event.
+
\ No newline at end of file
client/rpc/Cargo.tomldiffbeforeafterboth--- a/client/rpc/Cargo.toml
+++ b/client/rpc/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "uc-rpc"
-version = "0.1.0"
+version = "0.1.1"
license = "GPLv3"
edition = "2021"
client/rpc/src/lib.rsdiffbeforeafterboth--- a/client/rpc/src/lib.rs
+++ b/client/rpc/src/lib.rs
@@ -70,6 +70,16 @@
token: TokenId,
at: Option<BlockHash>,
) -> Result<Option<CrossAccountId>>;
+
+ /// Returns 10 tokens owners in no particular order.
+ #[method(name = "unique_tokenOwners")]
+ fn token_owners(
+ &self,
+ collection: CollectionId,
+ token: TokenId,
+ at: Option<BlockHash>,
+ ) -> Result<Vec<CrossAccountId>>;
+
#[method(name = "unique_topmostTokenOwner")]
fn topmost_token_owner(
&self,
@@ -473,6 +483,7 @@
pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>, unique_api);
pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>, unique_api);
pass_method!(total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<u128>, unique_api);
+ pass_method!(token_owners(collection: CollectionId, token: TokenId) -> Vec<CrossAccountId>, unique_api);
}
#[allow(deprecated)]
pallets/common/CHANGELOG.mddiffbeforeafterboth--- /dev/null
+++ b/pallets/common/CHANGELOG.md
@@ -0,0 +1,12 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+
+## [0.1.1] - 2022-07-14
+
+### Added
+
+ - Implementation of RPC method `token_owners` returning 10 owners in no particular order.
+ This was an internal request to improve the web interface and support fractionalization event.
+
+
\ No newline at end of file
pallets/common/src/lib.rsdiffbeforeafterboth--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -1748,6 +1748,11 @@
/// * `token` - The token for which you need to find out the owner.
fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;
+ /// Returns 10 tokens owners in no particular order.
+ ///
+ /// * `token` - The token for which you need to find out the owners.
+ fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId>;
+
/// Get the value of the token property by key.
///
/// * `token` - Token with the property to get.
pallets/fungible/CHANGELOG.mddiffbeforeafterboth--- /dev/null
+++ b/pallets/fungible/CHANGELOG.md
@@ -0,0 +1,13 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+
+## [0.1.1] - 2022-07-14
+
+### Added
+
+ - Implementation of RPC method `token_owners` returning 10 owners in no particular order.
+ This was an internal request to improve the web interface and support fractionalization event.
+
+
+
\ No newline at end of file
pallets/fungible/Cargo.tomldiffbeforeafterboth--- a/pallets/fungible/Cargo.toml
+++ b/pallets/fungible/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "pallet-fungible"
-version = "0.1.0"
+version = "0.1.1"
license = "GPLv3"
edition = "2021"
pallets/fungible/src/common.rsdiffbeforeafterboth--- a/pallets/fungible/src/common.rs
+++ b/pallets/fungible/src/common.rs
@@ -362,6 +362,11 @@
None
}
+ /// Returns 10 tokens owners in no particular order.
+ fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {
+ <Pallet<T>>::token_owners(self.id, token).unwrap_or_default()
+ }
+
fn token_property(&self, _token_id: TokenId, _key: &PropertyKey) -> Option<PropertyValue> {
None
}
pallets/fungible/src/lib.rsdiffbeforeafterboth--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -95,7 +95,7 @@
use pallet_evm_coder_substrate::WithRecorder;
use sp_core::H160;
use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};
-use sp_std::{collections::btree_map::BTreeMap};
+use sp_std::{collections::btree_map::BTreeMap, vec::Vec};
pub use pallet::*;
@@ -613,4 +613,26 @@
nesting_budget,
)
}
+
+ /// Returns 10 tokens owners in no particular order
+ ///
+ /// There is no direct way to get token holders in ascending order,
+ /// since `iter_prefix` returns values in no particular order.
+ /// Therefore, getting the 10 largest holders with a large value of holders
+ /// can lead to impact memory allocation + sorting with `n * log (n)`.
+ pub fn token_owners(
+ collection: CollectionId,
+ _token: TokenId,
+ ) -> Option<Vec<T::CrossAccountId>> {
+ let res: Vec<T::CrossAccountId> = <Balance<T>>::iter_prefix((collection,))
+ .map(|(owner, _amount)| owner)
+ .take(10)
+ .collect();
+
+ if res.is_empty() {
+ None
+ } else {
+ Some(res)
+ }
+ }
}
pallets/nonfungible/CHANGELOG.mddiffbeforeafterboth--- /dev/null
+++ b/pallets/nonfungible/CHANGELOG.md
@@ -0,0 +1,11 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+
+## [0.1.1] - 2022-07-14
+
+### Added
+
+- Implementation of RPC method `token_owners`.
+ For reasons of compatibility with this pallet, returns only one owner if token exists.
+ This was an internal request to improve the web interface and support fractionalization event.
\ No newline at end of file
pallets/nonfungible/Cargo.tomldiffbeforeafterboth--- a/pallets/nonfungible/Cargo.toml
+++ b/pallets/nonfungible/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "pallet-nonfungible"
-version = "0.1.0"
+version = "0.1.1"
license = "GPLv3"
edition = "2021"
pallets/nonfungible/src/common.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -26,7 +26,7 @@
weights::WeightInfo as _,
};
use sp_runtime::DispatchError;
-use sp_std::vec::Vec;
+use sp_std::{vec::Vec, vec};
use crate::{
AccountBalance, Allowance, Config, CreateItemData, Error, NonfungibleHandle, Owned, Pallet,
@@ -422,6 +422,11 @@
<TokenData<T>>::get((self.id, token)).map(|t| t.owner)
}
+ /// Returns token owners.
+ fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {
+ self.token_owner(token).map_or_else(|| vec![], |t| vec![t])
+ }
+
fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue> {
<Pallet<T>>::token_properties((self.id, token_id))
.get(key)
pallets/refungible/CHANGELOG.mddiffbeforeafterboth--- a/pallets/refungible/CHANGELOG.md
+++ b/pallets/refungible/CHANGELOG.md
@@ -1,6 +1,18 @@
-## v0.1.2 - 2022-07
+# Change Log
-### Refungible Pallet
+All notable changes to this project will be documented in this file.
+## [v0.1.2] - 2022-07-14
+
+### Other changes
+
feat(refungible-pallet): add ERC-20 EVM API for RFT token pieces ([#413](https://github.com/UniqueNetwork/unique-chain/pull/413))
-test(refungible-pallet): add tests for ERC-20 EVM API for RFT token pieces ([#413](https://github.com/UniqueNetwork/unique-chain/pull/413))
\ No newline at end of file
+test(refungible-pallet): add tests for ERC-20 EVM API for RFT token pieces ([#413](https://github.com/UniqueNetwork/unique-chain/pull/413))
+
+## [v0.1.1] - 2022-07-14
+
+### Other changes
+
+- feat: RPC method `token_owners` returning 10 owners in no particular order.
+
+This was an internal request to improve the web interface and support fractionalization event.
pallets/refungible/src/common.rsdiffbeforeafterboth--- a/pallets/refungible/src/common.rs
+++ b/pallets/refungible/src/common.rs
@@ -438,6 +438,11 @@
<Pallet<T>>::token_owner(self.id, token)
}
+ /// Returns 10 token in no particular order.
+ fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {
+ <Pallet<T>>::token_owners(self.id, token).unwrap_or_default()
+ }
+
fn token_property(&self, _token_id: TokenId, _key: &PropertyKey) -> Option<PropertyValue> {
None
}
pallets/refungible/src/lib.rsdiffbeforeafterboth--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -1235,4 +1235,26 @@
) -> DispatchResult {
<PalletCommon<T>>::set_token_property_permissions(collection, sender, property_permissions)
}
+
+ /// Returns 10 token in no particular order.
+ ///
+ /// There is no direct way to get token holders in ascending order,
+ /// since `iter_prefix` returns values in no particular order.
+ /// Therefore, getting the 10 largest holders with a large value of holders
+ /// can lead to impact memory allocation + sorting with `n * log (n)`.
+ pub fn token_owners(
+ collection_id: CollectionId,
+ token: TokenId,
+ ) -> Option<Vec<T::CrossAccountId>> {
+ let res: Vec<T::CrossAccountId> = <Balance<T>>::iter_prefix((collection_id, token))
+ .map(|(owner, _amount)| owner)
+ .take(10)
+ .collect();
+
+ if res.is_empty() {
+ None
+ } else {
+ Some(res)
+ }
+ }
}
primitives/rpc/CHANGELOG.mddiffbeforeafterboth--- /dev/null
+++ b/primitives/rpc/CHANGELOG.md
@@ -0,0 +1,10 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+
+## [0.1.1] - 2022-07-14
+
+### Added
+
+ - Implementation of RPC method `token_owners` returning 10 owners in no particular order.
+ This was an internal request to improve the web interface and support fractionalization event.
\ No newline at end of file
primitives/rpc/Cargo.tomldiffbeforeafterboth--- a/primitives/rpc/Cargo.toml
+++ b/primitives/rpc/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "up-rpc"
-version = "0.1.0"
+version = "0.1.1"
license = "GPLv3"
edition = "2021"
primitives/rpc/src/lib.rsdiffbeforeafterboth--- a/primitives/rpc/src/lib.rs
+++ b/primitives/rpc/src/lib.rs
@@ -81,5 +81,6 @@
fn next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result<Option<u64>>;
fn effective_collection_limits(collection_id: CollectionId) -> Result<Option<CollectionLimits>>;
fn total_pieces(collection_id: CollectionId, token_id: TokenId) -> Result<Option<u128>>;
+ fn token_owners(collection: CollectionId, token: TokenId) -> Result<Vec<CrossAccountId>>;
}
}
runtime/common/CHANGELOG.mddiffbeforeafterboth--- /dev/null
+++ b/runtime/common/CHANGELOG.md
@@ -0,0 +1,13 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+
+## [0.9.25] - 2022-07-14
+
+### Added
+
+ - Implementation of RPC method `token_owners` returning 10 owners in no particular order.
+ This was an internal request to improve the web interface and support fractionalization event.
+
+
+
\ No newline at end of file
runtime/common/src/runtime_apis.rsdiffbeforeafterboth--- a/runtime/common/src/runtime_apis.rs
+++ b/runtime/common/src/runtime_apis.rs
@@ -40,6 +40,11 @@
fn token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>, DispatchError> {
dispatch_unique_runtime!(collection.token_owner(token))
}
+
+ fn token_owners(collection: CollectionId, token: TokenId) -> Result<Vec::<CrossAccountId>, DispatchError> {
+ dispatch_unique_runtime!(collection.token_owners(token))
+ }
+
fn topmost_token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>, DispatchError> {
let budget = up_data_structs::budget::Value::new(10);
tests/CHANGELOG.mddiffbeforeafterboth--- /dev/null
+++ b/tests/CHANGELOG.md
@@ -0,0 +1,11 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+
+## 2022-07-14
+
+### Added
+ - Integrintegration tests of RPC method `token_owners`.
+ - Integrintegration tests of Fungible Pallet.
+
+
\ No newline at end of file
tests/package.jsondiffbeforeafterboth--- a/tests/package.json
+++ b/tests/package.json
@@ -80,6 +80,8 @@
"testLimits": "mocha --timeout 9999999 -r ts-node/register ./**/limits.test.ts",
"testEthCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createCollection.test.ts",
"testRFT": "mocha --timeout 9999999 -r ts-node/register ./**/refungible.test.ts",
+ "testFT": "mocha --timeout 9999999 -r ts-node/register ./**/fungible.test.ts",
+ "testRPC": "mocha --timeout 9999999 -r ts-node/register ./**/rpc.test.ts",
"polkadot-types-fetch-metadata": "curl -H 'Content-Type: application/json' -d '{\"id\":\"1\", \"jsonrpc\":\"2.0\", \"method\": \"state_getMetadata\", \"params\":[]}' http://localhost:9933 > src/interfaces/metadata.json",
"polkadot-types-from-defs": "ts-node ./node_modules/.bin/polkadot-types-from-defs --endpoint src/interfaces/metadata.json --input src/interfaces/ --package .",
"polkadot-types-from-chain": "ts-node ./node_modules/.bin/polkadot-types-from-chain --endpoint src/interfaces/metadata.json --output src/interfaces/ --package .",
tests/src/fungible.test.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/fungible.test.ts
@@ -0,0 +1,184 @@
+// 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 {default as usingApi} from './substrate/substrate-api';
+import {IKeyringPair} from '@polkadot/types/types';
+import {
+ getBalance,
+ createMultipleItemsExpectSuccess,
+ isTokenExists,
+ getLastTokenId,
+ getAllowance,
+ approve,
+ transferFrom,
+ createCollection,
+ transfer,
+ burnItem,
+ normalizeAccountId,
+ CrossAccountId,
+ createFungibleItemExpectSuccess,
+ U128_MAX,
+ burnFromExpectSuccess,
+} from './util/helpers';
+
+import chai from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chai.use(chaiAsPromised);
+const expect = chai.expect;
+
+let alice: IKeyringPair;
+let bob: IKeyringPair;
+
+describe('integration test: Fungible functionality:', () => {
+ before(async () => {
+ await usingApi(async (api, privateKeyWrapper) => {
+ alice = privateKeyWrapper('//Alice');
+ bob = privateKeyWrapper('//Bob');
+ });
+ });
+
+ it('Create fungible collection and token', async () => {
+ await usingApi(async api => {
+ const createCollectionResult = await createCollection(api, alice, {mode: {type: 'Fungible', decimalPoints: 0}});
+ expect(createCollectionResult.success).to.be.true;
+ const collectionId = createCollectionResult.collectionId;
+ const defaultTokenId = await getLastTokenId(api, collectionId);
+ const aliceTokenId = await createFungibleItemExpectSuccess(alice, collectionId, {Value: U128_MAX}, alice.address);
+ const aliceBalance = await getBalance(api, collectionId, alice, aliceTokenId);
+ const itemCountAfter = await getLastTokenId(api, collectionId);
+
+ // What to expect
+ // tslint:disable-next-line:no-unused-expression
+ expect(itemCountAfter).to.be.equal(defaultTokenId);
+ expect(aliceBalance).to.be.equal(U128_MAX);
+ });
+ });
+
+ it('RPC method tokenOnewrs for fungible collection and token', async () => {
+ await usingApi(async (api, privateKeyWrapper) => {
+ const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
+ const facelessCrowd = Array.from(Array(7).keys()).map(i => normalizeAccountId(privateKeyWrapper(i.toString())));
+
+ const createCollectionResult = await createCollection(api, alice, {mode: {type: 'Fungible', decimalPoints: 0}});
+ const collectionId = createCollectionResult.collectionId;
+ const aliceTokenId = await createFungibleItemExpectSuccess(alice, collectionId, {Value: U128_MAX}, alice.address);
+
+ await transfer(api, collectionId, aliceTokenId, alice, bob, 1000n);
+ await transfer(api, collectionId, aliceTokenId, alice, ethAcc, 900n);
+
+ for (let i = 0; i < 7; i++) {
+ await transfer(api, collectionId, aliceTokenId, alice, facelessCrowd[i], 1);
+ }
+
+ const owners = await api.rpc.unique.tokenOwners(collectionId, aliceTokenId);
+ const ids = (owners.toJSON() as CrossAccountId[]).map(s => normalizeAccountId(s));
+ const aliceID = normalizeAccountId(alice);
+ const bobId = normalizeAccountId(bob);
+
+ // What to expect
+ // tslint:disable-next-line:no-unused-expression
+ expect(ids).to.deep.include.members([aliceID, ethAcc, bobId, ...facelessCrowd]);
+ expect(owners.length == 10).to.be.true;
+
+ const eleven = privateKeyWrapper('11');
+ expect(await transfer(api, collectionId, aliceTokenId, alice, eleven, 10n)).to.be.true;
+ expect((await api.rpc.unique.tokenOwners(collectionId, aliceTokenId)).length).to.be.equal(10);
+ });
+ });
+
+ it('Transfer token', async () => {
+ await usingApi(async api => {
+ const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
+ const collectionId = (await createCollection(api, alice, {mode: {type: 'Fungible', decimalPoints: 0}})).collectionId;
+ const tokenId = await createFungibleItemExpectSuccess(alice, collectionId, {Value: 500n}, alice.address);
+
+ expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(500n);
+ expect(await transfer(api, collectionId, tokenId, alice, bob, 60n)).to.be.true;
+ expect(await transfer(api, collectionId, tokenId, alice, ethAcc, 140n)).to.be.true;
+
+ expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(300n);
+ expect(await getBalance(api, collectionId, bob, tokenId)).to.be.equal(60n);
+ expect(await getBalance(api, collectionId, ethAcc, tokenId)).to.be.equal(140n);
+ await expect(transfer(api, collectionId, tokenId, alice, bob, 350n)).to.eventually.be.rejected;
+ });
+ });
+
+ it('Tokens multiple creation', async () => {
+ await usingApi(async api => {
+ const collectionId = (await createCollection(api, alice, {mode: {type: 'Fungible', decimalPoints: 0}})).collectionId;
+
+ const args = [
+ {Fungible: {Value: 500n}},
+ {Fungible: {Value: 400n}},
+ {Fungible: {Value: 300n}},
+ ];
+
+ await createMultipleItemsExpectSuccess(alice, collectionId, args);
+ expect(await getBalance(api, collectionId, alice, 0)).to.be.equal(1200n);
+ });
+ });
+
+ it('Burn some tokens ', async () => {
+ await usingApi(async api => {
+ const collectionId = (await createCollection(api, alice, {mode: {type: 'Fungible', decimalPoints: 0}})).collectionId;
+ const tokenId = (await createFungibleItemExpectSuccess(alice, collectionId, {Value: 500n}, alice.address));
+ expect(await isTokenExists(api, collectionId, tokenId)).to.be.true;
+ expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(500n);
+ expect(await burnItem(api, alice, collectionId, tokenId, 499n)).to.be.true;
+ expect(await isTokenExists(api, collectionId, tokenId)).to.be.true;
+ expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(1n);
+ });
+ });
+
+ it('Burn all tokens ', async () => {
+ await usingApi(async api => {
+ const collectionId = (await createCollection(api, alice, {mode: {type: 'Fungible', decimalPoints: 0}})).collectionId;
+ const tokenId = (await createFungibleItemExpectSuccess(alice, collectionId, {Value: 500n}, alice.address));
+ expect(await isTokenExists(api, collectionId, tokenId)).to.be.true;
+ expect(await burnItem(api, alice, collectionId, tokenId, 500n)).to.be.true;
+ expect(await isTokenExists(api, collectionId, tokenId)).to.be.true;
+
+ expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(0n);
+ expect((await api.rpc.unique.totalPieces(collectionId, tokenId)).value.toBigInt()).to.be.equal(0n);
+ });
+ });
+
+ it('Set allowance for token', async () => {
+ await usingApi(async api => {
+ const collectionId = (await createCollection(api, alice, {mode: {type: 'Fungible', decimalPoints: 0}})).collectionId;
+ const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
+
+ const tokenId = (await createFungibleItemExpectSuccess(alice, collectionId, {Value: 100n}, alice.address));
+ expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(100n);
+
+ expect(await approve(api, collectionId, tokenId, alice, bob, 60n)).to.be.true;
+ expect(await getAllowance(api, collectionId, alice, bob, tokenId)).to.be.equal(60n);
+ expect(await getBalance(api, collectionId, bob, tokenId)).to.be.equal(0n);
+
+ expect(await transferFrom(api, collectionId, tokenId, bob, alice, bob, 20n)).to.be.true;
+ expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(80n);
+ expect(await getBalance(api, collectionId, bob, tokenId)).to.be.equal(20n);
+ expect(await getAllowance(api, collectionId, alice, bob, tokenId)).to.be.equal(40n);
+
+ await burnFromExpectSuccess(bob, alice, collectionId, tokenId, 10n);
+
+ expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(70n);
+ expect(await getAllowance(api, collectionId, alice, bob, tokenId)).to.be.equal(30n);
+ expect(await transferFrom(api, collectionId, tokenId, bob, alice, ethAcc, 10n)).to.be.true;
+ expect(await getBalance(api, collectionId, ethAcc, tokenId)).to.be.equal(10n);
+ });
+ });
+});
tests/src/interfaces/augment-api-consts.tsdiffbeforeafterboth--- a/tests/src/interfaces/augment-api-consts.ts
+++ b/tests/src/interfaces/augment-api-consts.ts
@@ -29,7 +29,13 @@
[key: string]: Codec;
};
common: {
+ /**
+ * Maximum admins per collection.
+ **/
collectionAdminsLimit: u32 & AugmentedConst<ApiType>;
+ /**
+ * Set price to create a collection.
+ **/
collectionCreationPrice: u128 & AugmentedConst<ApiType>;
/**
* Generic const
tests/src/interfaces/augment-api-events.tsdiffbeforeafterboth1// Auto-generated via `yarn polkadot-types-from-chain`, do not edit2/* eslint-disable */34import type { ApiTypes } from '@polkadot/api-base/types';5import type { Bytes, Null, Option, Result, U256, U8aFixed, bool, u128, u32, u64, u8 } from '@polkadot/types-codec';6import type { ITuple } from '@polkadot/types-codec/types';7import type { AccountId32, H160, H256 } from '@polkadot/types/interfaces/runtime';8import type { EthereumLog, EvmCoreErrorExitReason, FrameSupportScheduleLookupError, FrameSupportTokensMiscBalanceStatus, FrameSupportWeightsDispatchInfo, OrmlVestingVestingSchedule, PalletEvmAccountBasicCrossAccountIdRepr, RmrkTraitsNftAccountIdOrCollectionNftTuple, SpRuntimeDispatchError, XcmV1MultiLocation, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation } from '@polkadot/types/lookup';910declare module '@polkadot/api-base/types/events' {11 export interface AugmentedEvents<ApiType extends ApiTypes> {12 balances: {13 /**14 * A balance was set by root.15 **/16 BalanceSet: AugmentedEvent<ApiType, [who: AccountId32, free: u128, reserved: u128], { who: AccountId32, free: u128, reserved: u128 }>;17 /**18 * Some amount was deposited (e.g. for transaction fees).19 **/20 Deposit: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;21 /**22 * An account was removed whose balance was non-zero but below ExistentialDeposit,23 * resulting in an outright loss.24 **/25 DustLost: AugmentedEvent<ApiType, [account: AccountId32, amount: u128], { account: AccountId32, amount: u128 }>;26 /**27 * An account was created with some free balance.28 **/29 Endowed: AugmentedEvent<ApiType, [account: AccountId32, freeBalance: u128], { account: AccountId32, freeBalance: u128 }>;30 /**31 * Some balance was reserved (moved from free to reserved).32 **/33 Reserved: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;34 /**35 * Some balance was moved from the reserve of the first account to the second account.36 * Final argument indicates the destination balance type.37 **/38 ReserveRepatriated: AugmentedEvent<ApiType, [from: AccountId32, to: AccountId32, amount: u128, destinationStatus: FrameSupportTokensMiscBalanceStatus], { from: AccountId32, to: AccountId32, amount: u128, destinationStatus: FrameSupportTokensMiscBalanceStatus }>;39 /**40 * Some amount was removed from the account (e.g. for misbehavior).41 **/42 Slashed: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;43 /**44 * Transfer succeeded.45 **/46 Transfer: AugmentedEvent<ApiType, [from: AccountId32, to: AccountId32, amount: u128], { from: AccountId32, to: AccountId32, amount: u128 }>;47 /**48 * Some balance was unreserved (moved from reserved to free).49 **/50 Unreserved: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;51 /**52 * Some amount was withdrawn from the account (e.g. for transaction fees).53 **/54 Withdraw: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;55 /**56 * Generic event57 **/58 [key: string]: AugmentedEvent<ApiType>;59 };60 common: {61 /**62 * * collection_id63 * 64 * * item_id65 * 66 * * sender67 * 68 * * spender69 * 70 * * amount71 **/72 Approved: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;73 /**74 * New collection was created75 * 76 * # Arguments77 * 78 * * collection_id: Globally unique identifier of newly created collection.79 * 80 * * mode: [CollectionMode] converted into u8.81 * 82 * * account_id: Collection owner.83 **/84 CollectionCreated: AugmentedEvent<ApiType, [u32, u8, AccountId32]>;85 /**86 * New collection was destroyed87 * 88 * # Arguments89 * 90 * * collection_id: Globally unique identifier of collection.91 **/92 CollectionDestroyed: AugmentedEvent<ApiType, [u32]>;93 CollectionPropertyDeleted: AugmentedEvent<ApiType, [u32, Bytes]>;94 CollectionPropertySet: AugmentedEvent<ApiType, [u32, Bytes]>;95 /**96 * New item was created.97 * 98 * # Arguments99 * 100 * * collection_id: Id of the collection where item was created.101 * 102 * * item_id: Id of an item. Unique within the collection.103 * 104 * * recipient: Owner of newly created item105 * 106 * * amount: Always 1 for NFT107 **/108 ItemCreated: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;109 /**110 * Collection item was burned.111 * 112 * # Arguments113 * 114 * * collection_id.115 * 116 * * item_id: Identifier of burned NFT.117 * 118 * * owner: which user has destroyed its tokens119 * 120 * * amount: Always 1 for NFT121 **/122 ItemDestroyed: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;123 PropertyPermissionSet: AugmentedEvent<ApiType, [u32, Bytes]>;124 TokenPropertyDeleted: AugmentedEvent<ApiType, [u32, u32, Bytes]>;125 TokenPropertySet: AugmentedEvent<ApiType, [u32, u32, Bytes]>;126 /**127 * Item was transferred128 * 129 * * collection_id: Id of collection to which item is belong130 * 131 * * item_id: Id of an item132 * 133 * * sender: Original owner of item134 * 135 * * recipient: New owner of item136 * 137 * * amount: Always 1 for NFT138 **/139 Transfer: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;140 /**141 * Generic event142 **/143 [key: string]: AugmentedEvent<ApiType>;144 };145 cumulusXcm: {146 /**147 * Downward message executed with the given outcome.148 * \[ id, outcome \]149 **/150 ExecutedDownward: AugmentedEvent<ApiType, [U8aFixed, XcmV2TraitsOutcome]>;151 /**152 * Downward message is invalid XCM.153 * \[ id \]154 **/155 InvalidFormat: AugmentedEvent<ApiType, [U8aFixed]>;156 /**157 * Downward message is unsupported version of XCM.158 * \[ id \]159 **/160 UnsupportedVersion: AugmentedEvent<ApiType, [U8aFixed]>;161 /**162 * Generic event163 **/164 [key: string]: AugmentedEvent<ApiType>;165 };166 dmpQueue: {167 /**168 * Downward message executed with the given outcome.169 **/170 ExecutedDownward: AugmentedEvent<ApiType, [messageId: U8aFixed, outcome: XcmV2TraitsOutcome], { messageId: U8aFixed, outcome: XcmV2TraitsOutcome }>;171 /**172 * Downward message is invalid XCM.173 **/174 InvalidFormat: AugmentedEvent<ApiType, [messageId: U8aFixed], { messageId: U8aFixed }>;175 /**176 * Downward message is overweight and was placed in the overweight queue.177 **/178 OverweightEnqueued: AugmentedEvent<ApiType, [messageId: U8aFixed, overweightIndex: u64, requiredWeight: u64], { messageId: U8aFixed, overweightIndex: u64, requiredWeight: u64 }>;179 /**180 * Downward message from the overweight queue was executed.181 **/182 OverweightServiced: AugmentedEvent<ApiType, [overweightIndex: u64, weightUsed: u64], { overweightIndex: u64, weightUsed: u64 }>;183 /**184 * Downward message is unsupported version of XCM.185 **/186 UnsupportedVersion: AugmentedEvent<ApiType, [messageId: U8aFixed], { messageId: U8aFixed }>;187 /**188 * The weight limit for handling downward messages was reached.189 **/190 WeightExhausted: AugmentedEvent<ApiType, [messageId: U8aFixed, remainingWeight: u64, requiredWeight: u64], { messageId: U8aFixed, remainingWeight: u64, requiredWeight: u64 }>;191 /**192 * Generic event193 **/194 [key: string]: AugmentedEvent<ApiType>;195 };196 ethereum: {197 /**198 * An ethereum transaction was successfully executed. [from, to/contract_address, transaction_hash, exit_reason]199 **/200 Executed: AugmentedEvent<ApiType, [H160, H160, H256, EvmCoreErrorExitReason]>;201 /**202 * Generic event203 **/204 [key: string]: AugmentedEvent<ApiType>;205 };206 evm: {207 /**208 * A deposit has been made at a given address. \[sender, address, value\]209 **/210 BalanceDeposit: AugmentedEvent<ApiType, [AccountId32, H160, U256]>;211 /**212 * A withdrawal has been made from a given address. \[sender, address, value\]213 **/214 BalanceWithdraw: AugmentedEvent<ApiType, [AccountId32, H160, U256]>;215 /**216 * A contract has been created at given \[address\].217 **/218 Created: AugmentedEvent<ApiType, [H160]>;219 /**220 * A \[contract\] was attempted to be created, but the execution failed.221 **/222 CreatedFailed: AugmentedEvent<ApiType, [H160]>;223 /**224 * A \[contract\] has been executed successfully with states applied.225 **/226 Executed: AugmentedEvent<ApiType, [H160]>;227 /**228 * A \[contract\] has been executed with errors. States are reverted with only gas fees applied.229 **/230 ExecutedFailed: AugmentedEvent<ApiType, [H160]>;231 /**232 * Ethereum events from contracts.233 **/234 Log: AugmentedEvent<ApiType, [EthereumLog]>;235 /**236 * Generic event237 **/238 [key: string]: AugmentedEvent<ApiType>;239 };240 parachainSystem: {241 /**242 * Downward messages were processed using the given weight.243 **/244 DownwardMessagesProcessed: AugmentedEvent<ApiType, [weightUsed: u64, dmqHead: H256], { weightUsed: u64, dmqHead: H256 }>;245 /**246 * Some downward messages have been received and will be processed.247 **/248 DownwardMessagesReceived: AugmentedEvent<ApiType, [count: u32], { count: u32 }>;249 /**250 * An upgrade has been authorized.251 **/252 UpgradeAuthorized: AugmentedEvent<ApiType, [codeHash: H256], { codeHash: H256 }>;253 /**254 * The validation function was applied as of the contained relay chain block number.255 **/256 ValidationFunctionApplied: AugmentedEvent<ApiType, [relayChainBlockNum: u32], { relayChainBlockNum: u32 }>;257 /**258 * The relay-chain aborted the upgrade process.259 **/260 ValidationFunctionDiscarded: AugmentedEvent<ApiType, []>;261 /**262 * The validation function has been scheduled to apply.263 **/264 ValidationFunctionStored: AugmentedEvent<ApiType, []>;265 /**266 * Generic event267 **/268 [key: string]: AugmentedEvent<ApiType>;269 };270 polkadotXcm: {271 /**272 * Some assets have been placed in an asset trap.273 * 274 * \[ hash, origin, assets \]275 **/276 AssetsTrapped: AugmentedEvent<ApiType, [H256, XcmV1MultiLocation, XcmVersionedMultiAssets]>;277 /**278 * Execution of an XCM message was attempted.279 * 280 * \[ outcome \]281 **/282 Attempted: AugmentedEvent<ApiType, [XcmV2TraitsOutcome]>;283 /**284 * Expected query response has been received but the origin location of the response does285 * not match that expected. The query remains registered for a later, valid, response to286 * be received and acted upon.287 * 288 * \[ origin location, id, expected location \]289 **/290 InvalidResponder: AugmentedEvent<ApiType, [XcmV1MultiLocation, u64, Option<XcmV1MultiLocation>]>;291 /**292 * Expected query response has been received but the expected origin location placed in293 * storage by this runtime previously cannot be decoded. The query remains registered.294 * 295 * This is unexpected (since a location placed in storage in a previously executing296 * runtime should be readable prior to query timeout) and dangerous since the possibly297 * valid response will be dropped. Manual governance intervention is probably going to be298 * needed.299 * 300 * \[ origin location, id \]301 **/302 InvalidResponderVersion: AugmentedEvent<ApiType, [XcmV1MultiLocation, u64]>;303 /**304 * Query response has been received and query is removed. The registered notification has305 * been dispatched and executed successfully.306 * 307 * \[ id, pallet index, call index \]308 **/309 Notified: AugmentedEvent<ApiType, [u64, u8, u8]>;310 /**311 * Query response has been received and query is removed. The dispatch was unable to be312 * decoded into a `Call`; this might be due to dispatch function having a signature which313 * is not `(origin, QueryId, Response)`.314 * 315 * \[ id, pallet index, call index \]316 **/317 NotifyDecodeFailed: AugmentedEvent<ApiType, [u64, u8, u8]>;318 /**319 * Query response has been received and query is removed. There was a general error with320 * dispatching the notification call.321 * 322 * \[ id, pallet index, call index \]323 **/324 NotifyDispatchError: AugmentedEvent<ApiType, [u64, u8, u8]>;325 /**326 * Query response has been received and query is removed. The registered notification could327 * not be dispatched because the dispatch weight is greater than the maximum weight328 * originally budgeted by this runtime for the query result.329 * 330 * \[ id, pallet index, call index, actual weight, max budgeted weight \]331 **/332 NotifyOverweight: AugmentedEvent<ApiType, [u64, u8, u8, u64, u64]>;333 /**334 * A given location which had a version change subscription was dropped owing to an error335 * migrating the location to our new XCM format.336 * 337 * \[ location, query ID \]338 **/339 NotifyTargetMigrationFail: AugmentedEvent<ApiType, [XcmVersionedMultiLocation, u64]>;340 /**341 * A given location which had a version change subscription was dropped owing to an error342 * sending the notification to it.343 * 344 * \[ location, query ID, error \]345 **/346 NotifyTargetSendFail: AugmentedEvent<ApiType, [XcmV1MultiLocation, u64, XcmV2TraitsError]>;347 /**348 * Query response has been received and is ready for taking with `take_response`. There is349 * no registered notification call.350 * 351 * \[ id, response \]352 **/353 ResponseReady: AugmentedEvent<ApiType, [u64, XcmV2Response]>;354 /**355 * Received query response has been read and removed.356 * 357 * \[ id \]358 **/359 ResponseTaken: AugmentedEvent<ApiType, [u64]>;360 /**361 * A XCM message was sent.362 * 363 * \[ origin, destination, message \]364 **/365 Sent: AugmentedEvent<ApiType, [XcmV1MultiLocation, XcmV1MultiLocation, XcmV2Xcm]>;366 /**367 * The supported version of a location has been changed. This might be through an368 * automatic notification or a manual intervention.369 * 370 * \[ location, XCM version \]371 **/372 SupportedVersionChanged: AugmentedEvent<ApiType, [XcmV1MultiLocation, u32]>;373 /**374 * Query response received which does not match a registered query. This may be because a375 * matching query was never registered, it may be because it is a duplicate response, or376 * because the query timed out.377 * 378 * \[ origin location, id \]379 **/380 UnexpectedResponse: AugmentedEvent<ApiType, [XcmV1MultiLocation, u64]>;381 /**382 * An XCM version change notification message has been attempted to be sent.383 * 384 * \[ destination, result \]385 **/386 VersionChangeNotified: AugmentedEvent<ApiType, [XcmV1MultiLocation, u32]>;387 /**388 * Generic event389 **/390 [key: string]: AugmentedEvent<ApiType>;391 };392 rmrkCore: {393 CollectionCreated: AugmentedEvent<ApiType, [issuer: AccountId32, collectionId: u32], { issuer: AccountId32, collectionId: u32 }>;394 CollectionDestroyed: AugmentedEvent<ApiType, [issuer: AccountId32, collectionId: u32], { issuer: AccountId32, collectionId: u32 }>;395 CollectionLocked: AugmentedEvent<ApiType, [issuer: AccountId32, collectionId: u32], { issuer: AccountId32, collectionId: u32 }>;396 IssuerChanged: AugmentedEvent<ApiType, [oldIssuer: AccountId32, newIssuer: AccountId32, collectionId: u32], { oldIssuer: AccountId32, newIssuer: AccountId32, collectionId: u32 }>;397 NFTAccepted: AugmentedEvent<ApiType, [sender: AccountId32, recipient: RmrkTraitsNftAccountIdOrCollectionNftTuple, collectionId: u32, nftId: u32], { sender: AccountId32, recipient: RmrkTraitsNftAccountIdOrCollectionNftTuple, collectionId: u32, nftId: u32 }>;398 NFTBurned: AugmentedEvent<ApiType, [owner: AccountId32, nftId: u32], { owner: AccountId32, nftId: u32 }>;399 NftMinted: AugmentedEvent<ApiType, [owner: AccountId32, collectionId: u32, nftId: u32], { owner: AccountId32, collectionId: u32, nftId: u32 }>;400 NFTRejected: AugmentedEvent<ApiType, [sender: AccountId32, collectionId: u32, nftId: u32], { sender: AccountId32, collectionId: u32, nftId: u32 }>;401 NFTSent: AugmentedEvent<ApiType, [sender: AccountId32, recipient: RmrkTraitsNftAccountIdOrCollectionNftTuple, collectionId: u32, nftId: u32, approvalRequired: bool], { sender: AccountId32, recipient: RmrkTraitsNftAccountIdOrCollectionNftTuple, collectionId: u32, nftId: u32, approvalRequired: bool }>;402 PrioritySet: AugmentedEvent<ApiType, [collectionId: u32, nftId: u32], { collectionId: u32, nftId: u32 }>;403 PropertySet: AugmentedEvent<ApiType, [collectionId: u32, maybeNftId: Option<u32>, key: Bytes, value: Bytes], { collectionId: u32, maybeNftId: Option<u32>, key: Bytes, value: Bytes }>;404 ResourceAccepted: AugmentedEvent<ApiType, [nftId: u32, resourceId: u32], { nftId: u32, resourceId: u32 }>;405 ResourceAdded: AugmentedEvent<ApiType, [nftId: u32, resourceId: u32], { nftId: u32, resourceId: u32 }>;406 ResourceRemoval: AugmentedEvent<ApiType, [nftId: u32, resourceId: u32], { nftId: u32, resourceId: u32 }>;407 ResourceRemovalAccepted: AugmentedEvent<ApiType, [nftId: u32, resourceId: u32], { nftId: u32, resourceId: u32 }>;408 /**409 * Generic event410 **/411 [key: string]: AugmentedEvent<ApiType>;412 };413 rmrkEquip: {414 BaseCreated: AugmentedEvent<ApiType, [issuer: AccountId32, baseId: u32], { issuer: AccountId32, baseId: u32 }>;415 EquippablesUpdated: AugmentedEvent<ApiType, [baseId: u32, slotId: u32], { baseId: u32, slotId: u32 }>;416 /**417 * Generic event418 **/419 [key: string]: AugmentedEvent<ApiType>;420 };421 scheduler: {422 /**423 * The call for the provided hash was not found so the task has been aborted.424 **/425 CallLookupFailed: AugmentedEvent<ApiType, [task: ITuple<[u32, u32]>, id: Option<U8aFixed>, error: FrameSupportScheduleLookupError], { task: ITuple<[u32, u32]>, id: Option<U8aFixed>, error: FrameSupportScheduleLookupError }>;426 /**427 * Canceled some task.428 **/429 Canceled: AugmentedEvent<ApiType, [when: u32, index: u32], { when: u32, index: u32 }>;430 /**431 * Dispatched some task.432 **/433 Dispatched: AugmentedEvent<ApiType, [task: ITuple<[u32, u32]>, id: Option<U8aFixed>, result: Result<Null, SpRuntimeDispatchError>], { task: ITuple<[u32, u32]>, id: Option<U8aFixed>, result: Result<Null, SpRuntimeDispatchError> }>;434 /**435 * Scheduled some task.436 **/437 Scheduled: AugmentedEvent<ApiType, [when: u32, index: u32], { when: u32, index: u32 }>;438 /**439 * Generic event440 **/441 [key: string]: AugmentedEvent<ApiType>;442 };443 structure: {444 /**445 * Executed call on behalf of token446 **/447 Executed: AugmentedEvent<ApiType, [Result<Null, SpRuntimeDispatchError>]>;448 /**449 * Generic event450 **/451 [key: string]: AugmentedEvent<ApiType>;452 };453 sudo: {454 /**455 * The \[sudoer\] just switched identity; the old key is supplied if one existed.456 **/457 KeyChanged: AugmentedEvent<ApiType, [oldSudoer: Option<AccountId32>], { oldSudoer: Option<AccountId32> }>;458 /**459 * A sudo just took place. \[result\]460 **/461 Sudid: AugmentedEvent<ApiType, [sudoResult: Result<Null, SpRuntimeDispatchError>], { sudoResult: Result<Null, SpRuntimeDispatchError> }>;462 /**463 * A sudo just took place. \[result\]464 **/465 SudoAsDone: AugmentedEvent<ApiType, [sudoResult: Result<Null, SpRuntimeDispatchError>], { sudoResult: Result<Null, SpRuntimeDispatchError> }>;466 /**467 * Generic event468 **/469 [key: string]: AugmentedEvent<ApiType>;470 };471 system: {472 /**473 * `:code` was updated.474 **/475 CodeUpdated: AugmentedEvent<ApiType, []>;476 /**477 * An extrinsic failed.478 **/479 ExtrinsicFailed: AugmentedEvent<ApiType, [dispatchError: SpRuntimeDispatchError, dispatchInfo: FrameSupportWeightsDispatchInfo], { dispatchError: SpRuntimeDispatchError, dispatchInfo: FrameSupportWeightsDispatchInfo }>;480 /**481 * An extrinsic completed successfully.482 **/483 ExtrinsicSuccess: AugmentedEvent<ApiType, [dispatchInfo: FrameSupportWeightsDispatchInfo], { dispatchInfo: FrameSupportWeightsDispatchInfo }>;484 /**485 * An account was reaped.486 **/487 KilledAccount: AugmentedEvent<ApiType, [account: AccountId32], { account: AccountId32 }>;488 /**489 * A new account was created.490 **/491 NewAccount: AugmentedEvent<ApiType, [account: AccountId32], { account: AccountId32 }>;492 /**493 * On on-chain remark happened.494 **/495 Remarked: AugmentedEvent<ApiType, [sender: AccountId32, hash_: H256], { sender: AccountId32, hash_: H256 }>;496 /**497 * Generic event498 **/499 [key: string]: AugmentedEvent<ApiType>;500 };501 treasury: {502 /**503 * Some funds have been allocated.504 **/505 Awarded: AugmentedEvent<ApiType, [proposalIndex: u32, award: u128, account: AccountId32], { proposalIndex: u32, award: u128, account: AccountId32 }>;506 /**507 * Some of our funds have been burnt.508 **/509 Burnt: AugmentedEvent<ApiType, [burntFunds: u128], { burntFunds: u128 }>;510 /**511 * Some funds have been deposited.512 **/513 Deposit: AugmentedEvent<ApiType, [value: u128], { value: u128 }>;514 /**515 * New proposal.516 **/517 Proposed: AugmentedEvent<ApiType, [proposalIndex: u32], { proposalIndex: u32 }>;518 /**519 * A proposal was rejected; funds were slashed.520 **/521 Rejected: AugmentedEvent<ApiType, [proposalIndex: u32, slashed: u128], { proposalIndex: u32, slashed: u128 }>;522 /**523 * Spending has finished; this is the amount that rolls over until next spend.524 **/525 Rollover: AugmentedEvent<ApiType, [rolloverBalance: u128], { rolloverBalance: u128 }>;526 /**527 * We have ended a spend period and will now allocate funds.528 **/529 Spending: AugmentedEvent<ApiType, [budgetRemaining: u128], { budgetRemaining: u128 }>;530 /**531 * Generic event532 **/533 [key: string]: AugmentedEvent<ApiType>;534 };535 unique: {536 /**537 * Address was add to allow list538 * 539 * # Arguments540 * 541 * * collection_id: Globally unique collection identifier.542 * 543 * * user: Address.544 **/545 AllowListAddressAdded: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;546 /**547 * Address was remove from allow list548 * 549 * # Arguments550 * 551 * * collection_id: Globally unique collection identifier.552 * 553 * * user: Address.554 **/555 AllowListAddressRemoved: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;556 /**557 * Collection admin was added558 * 559 * # Arguments560 * 561 * * collection_id: Globally unique collection identifier.562 * 563 * * admin: Admin address.564 **/565 CollectionAdminAdded: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;566 /**567 * Collection admin was removed568 * 569 * # Arguments570 * 571 * * collection_id: Globally unique collection identifier.572 * 573 * * admin: Admin address.574 **/575 CollectionAdminRemoved: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;576 /**577 * Collection limits was set578 * 579 * # Arguments580 * 581 * * collection_id: Globally unique collection identifier.582 **/583 CollectionLimitSet: AugmentedEvent<ApiType, [u32]>;584 /**585 * Collection owned was change586 * 587 * # Arguments588 * 589 * * collection_id: Globally unique collection identifier.590 * 591 * * owner: New owner address.592 **/593 CollectionOwnedChanged: AugmentedEvent<ApiType, [u32, AccountId32]>;594 CollectionPermissionSet: AugmentedEvent<ApiType, [u32]>;595 /**596 * Collection sponsor was removed597 * 598 * # Arguments599 * 600 * * collection_id: Globally unique collection identifier.601 **/602 CollectionSponsorRemoved: AugmentedEvent<ApiType, [u32]>;603 /**604 * Collection sponsor was set605 * 606 * # Arguments607 * 608 * * collection_id: Globally unique collection identifier.609 * 610 * * owner: New sponsor address.611 **/612 CollectionSponsorSet: AugmentedEvent<ApiType, [u32, AccountId32]>;613 /**614 * New sponsor was confirm615 * 616 * # Arguments617 * 618 * * collection_id: Globally unique collection identifier.619 * 620 * * sponsor: New sponsor address.621 **/622 SponsorshipConfirmed: AugmentedEvent<ApiType, [u32, AccountId32]>;623 /**624 * Generic event625 **/626 [key: string]: AugmentedEvent<ApiType>;627 };628 vesting: {629 /**630 * Claimed vesting.631 **/632 Claimed: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;633 /**634 * Added new vesting schedule.635 **/636 VestingScheduleAdded: AugmentedEvent<ApiType, [from: AccountId32, to: AccountId32, vestingSchedule: OrmlVestingVestingSchedule], { from: AccountId32, to: AccountId32, vestingSchedule: OrmlVestingVestingSchedule }>;637 /**638 * Updated vesting schedules.639 **/640 VestingSchedulesUpdated: AugmentedEvent<ApiType, [who: AccountId32], { who: AccountId32 }>;641 /**642 * Generic event643 **/644 [key: string]: AugmentedEvent<ApiType>;645 };646 xcmpQueue: {647 /**648 * Bad XCM format used.649 **/650 BadFormat: AugmentedEvent<ApiType, [Option<H256>]>;651 /**652 * Bad XCM version used.653 **/654 BadVersion: AugmentedEvent<ApiType, [Option<H256>]>;655 /**656 * Some XCM failed.657 **/658 Fail: AugmentedEvent<ApiType, [Option<H256>, XcmV2TraitsError]>;659 /**660 * An XCM exceeded the individual message weight budget.661 **/662 OverweightEnqueued: AugmentedEvent<ApiType, [u32, u32, u64, u64]>;663 /**664 * An XCM from the overweight queue was executed with the given actual weight used.665 **/666 OverweightServiced: AugmentedEvent<ApiType, [u64, u64]>;667 /**668 * Some XCM was executed ok.669 **/670 Success: AugmentedEvent<ApiType, [Option<H256>]>;671 /**672 * An upward message was sent to the relay chain.673 **/674 UpwardMessageSent: AugmentedEvent<ApiType, [Option<H256>]>;675 /**676 * An HRMP message was sent to a sibling parachain.677 **/678 XcmpMessageSent: AugmentedEvent<ApiType, [Option<H256>]>;679 /**680 * Generic event681 **/682 [key: string]: AugmentedEvent<ApiType>;683 };684 } // AugmentedEvents685} // declare module1// Auto-generated via `yarn polkadot-types-from-chain`, do not edit2/* eslint-disable */34import type { ApiTypes } from '@polkadot/api-base/types';5import type { Bytes, Null, Option, Result, U256, U8aFixed, bool, u128, u32, u64, u8 } from '@polkadot/types-codec';6import type { ITuple } from '@polkadot/types-codec/types';7import type { AccountId32, H160, H256 } from '@polkadot/types/interfaces/runtime';8import type { EthereumLog, EvmCoreErrorExitReason, FrameSupportScheduleLookupError, FrameSupportTokensMiscBalanceStatus, FrameSupportWeightsDispatchInfo, OrmlVestingVestingSchedule, PalletEvmAccountBasicCrossAccountIdRepr, RmrkTraitsNftAccountIdOrCollectionNftTuple, SpRuntimeDispatchError, XcmV1MultiLocation, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation } from '@polkadot/types/lookup';910declare module '@polkadot/api-base/types/events' {11 export interface AugmentedEvents<ApiType extends ApiTypes> {12 balances: {13 /**14 * A balance was set by root.15 **/16 BalanceSet: AugmentedEvent<ApiType, [who: AccountId32, free: u128, reserved: u128], { who: AccountId32, free: u128, reserved: u128 }>;17 /**18 * Some amount was deposited (e.g. for transaction fees).19 **/20 Deposit: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;21 /**22 * An account was removed whose balance was non-zero but below ExistentialDeposit,23 * resulting in an outright loss.24 **/25 DustLost: AugmentedEvent<ApiType, [account: AccountId32, amount: u128], { account: AccountId32, amount: u128 }>;26 /**27 * An account was created with some free balance.28 **/29 Endowed: AugmentedEvent<ApiType, [account: AccountId32, freeBalance: u128], { account: AccountId32, freeBalance: u128 }>;30 /**31 * Some balance was reserved (moved from free to reserved).32 **/33 Reserved: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;34 /**35 * Some balance was moved from the reserve of the first account to the second account.36 * Final argument indicates the destination balance type.37 **/38 ReserveRepatriated: AugmentedEvent<ApiType, [from: AccountId32, to: AccountId32, amount: u128, destinationStatus: FrameSupportTokensMiscBalanceStatus], { from: AccountId32, to: AccountId32, amount: u128, destinationStatus: FrameSupportTokensMiscBalanceStatus }>;39 /**40 * Some amount was removed from the account (e.g. for misbehavior).41 **/42 Slashed: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;43 /**44 * Transfer succeeded.45 **/46 Transfer: AugmentedEvent<ApiType, [from: AccountId32, to: AccountId32, amount: u128], { from: AccountId32, to: AccountId32, amount: u128 }>;47 /**48 * Some balance was unreserved (moved from reserved to free).49 **/50 Unreserved: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;51 /**52 * Some amount was withdrawn from the account (e.g. for transaction fees).53 **/54 Withdraw: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;55 /**56 * Generic event57 **/58 [key: string]: AugmentedEvent<ApiType>;59 };60 common: {61 /**62 * Amount pieces of token owned by `sender` was approved for `spender`.63 **/64 Approved: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;65 /**66 * New collection was created67 **/68 CollectionCreated: AugmentedEvent<ApiType, [u32, u8, AccountId32]>;69 /**70 * New collection was destroyed71 **/72 CollectionDestroyed: AugmentedEvent<ApiType, [u32]>;73 /**74 * The property has been deleted.75 **/76 CollectionPropertyDeleted: AugmentedEvent<ApiType, [u32, Bytes]>;77 /**78 * The colletion property has been set.79 **/80 CollectionPropertySet: AugmentedEvent<ApiType, [u32, Bytes]>;81 /**82 * New item was created.83 **/84 ItemCreated: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;85 /**86 * Collection item was burned.87 **/88 ItemDestroyed: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;89 /**90 * The colletion property permission has been set.91 **/92 PropertyPermissionSet: AugmentedEvent<ApiType, [u32, Bytes]>;93 /**94 * The token property has been deleted.95 **/96 TokenPropertyDeleted: AugmentedEvent<ApiType, [u32, u32, Bytes]>;97 /**98 * The token property has been set.99 **/100 TokenPropertySet: AugmentedEvent<ApiType, [u32, u32, Bytes]>;101 /**102 * Item was transferred103 **/104 Transfer: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;105 /**106 * Generic event107 **/108 [key: string]: AugmentedEvent<ApiType>;109 };110 cumulusXcm: {111 /**112 * Downward message executed with the given outcome.113 * \[ id, outcome \]114 **/115 ExecutedDownward: AugmentedEvent<ApiType, [U8aFixed, XcmV2TraitsOutcome]>;116 /**117 * Downward message is invalid XCM.118 * \[ id \]119 **/120 InvalidFormat: AugmentedEvent<ApiType, [U8aFixed]>;121 /**122 * Downward message is unsupported version of XCM.123 * \[ id \]124 **/125 UnsupportedVersion: AugmentedEvent<ApiType, [U8aFixed]>;126 /**127 * Generic event128 **/129 [key: string]: AugmentedEvent<ApiType>;130 };131 dmpQueue: {132 /**133 * Downward message executed with the given outcome.134 **/135 ExecutedDownward: AugmentedEvent<ApiType, [messageId: U8aFixed, outcome: XcmV2TraitsOutcome], { messageId: U8aFixed, outcome: XcmV2TraitsOutcome }>;136 /**137 * Downward message is invalid XCM.138 **/139 InvalidFormat: AugmentedEvent<ApiType, [messageId: U8aFixed], { messageId: U8aFixed }>;140 /**141 * Downward message is overweight and was placed in the overweight queue.142 **/143 OverweightEnqueued: AugmentedEvent<ApiType, [messageId: U8aFixed, overweightIndex: u64, requiredWeight: u64], { messageId: U8aFixed, overweightIndex: u64, requiredWeight: u64 }>;144 /**145 * Downward message from the overweight queue was executed.146 **/147 OverweightServiced: AugmentedEvent<ApiType, [overweightIndex: u64, weightUsed: u64], { overweightIndex: u64, weightUsed: u64 }>;148 /**149 * Downward message is unsupported version of XCM.150 **/151 UnsupportedVersion: AugmentedEvent<ApiType, [messageId: U8aFixed], { messageId: U8aFixed }>;152 /**153 * The weight limit for handling downward messages was reached.154 **/155 WeightExhausted: AugmentedEvent<ApiType, [messageId: U8aFixed, remainingWeight: u64, requiredWeight: u64], { messageId: U8aFixed, remainingWeight: u64, requiredWeight: u64 }>;156 /**157 * Generic event158 **/159 [key: string]: AugmentedEvent<ApiType>;160 };161 ethereum: {162 /**163 * An ethereum transaction was successfully executed. [from, to/contract_address, transaction_hash, exit_reason]164 **/165 Executed: AugmentedEvent<ApiType, [H160, H160, H256, EvmCoreErrorExitReason]>;166 /**167 * Generic event168 **/169 [key: string]: AugmentedEvent<ApiType>;170 };171 evm: {172 /**173 * A deposit has been made at a given address. \[sender, address, value\]174 **/175 BalanceDeposit: AugmentedEvent<ApiType, [AccountId32, H160, U256]>;176 /**177 * A withdrawal has been made from a given address. \[sender, address, value\]178 **/179 BalanceWithdraw: AugmentedEvent<ApiType, [AccountId32, H160, U256]>;180 /**181 * A contract has been created at given \[address\].182 **/183 Created: AugmentedEvent<ApiType, [H160]>;184 /**185 * A \[contract\] was attempted to be created, but the execution failed.186 **/187 CreatedFailed: AugmentedEvent<ApiType, [H160]>;188 /**189 * A \[contract\] has been executed successfully with states applied.190 **/191 Executed: AugmentedEvent<ApiType, [H160]>;192 /**193 * A \[contract\] has been executed with errors. States are reverted with only gas fees applied.194 **/195 ExecutedFailed: AugmentedEvent<ApiType, [H160]>;196 /**197 * Ethereum events from contracts.198 **/199 Log: AugmentedEvent<ApiType, [EthereumLog]>;200 /**201 * Generic event202 **/203 [key: string]: AugmentedEvent<ApiType>;204 };205 parachainSystem: {206 /**207 * Downward messages were processed using the given weight.208 **/209 DownwardMessagesProcessed: AugmentedEvent<ApiType, [weightUsed: u64, dmqHead: H256], { weightUsed: u64, dmqHead: H256 }>;210 /**211 * Some downward messages have been received and will be processed.212 **/213 DownwardMessagesReceived: AugmentedEvent<ApiType, [count: u32], { count: u32 }>;214 /**215 * An upgrade has been authorized.216 **/217 UpgradeAuthorized: AugmentedEvent<ApiType, [codeHash: H256], { codeHash: H256 }>;218 /**219 * The validation function was applied as of the contained relay chain block number.220 **/221 ValidationFunctionApplied: AugmentedEvent<ApiType, [relayChainBlockNum: u32], { relayChainBlockNum: u32 }>;222 /**223 * The relay-chain aborted the upgrade process.224 **/225 ValidationFunctionDiscarded: AugmentedEvent<ApiType, []>;226 /**227 * The validation function has been scheduled to apply.228 **/229 ValidationFunctionStored: AugmentedEvent<ApiType, []>;230 /**231 * Generic event232 **/233 [key: string]: AugmentedEvent<ApiType>;234 };235 polkadotXcm: {236 /**237 * Some assets have been placed in an asset trap.238 * 239 * \[ hash, origin, assets \]240 **/241 AssetsTrapped: AugmentedEvent<ApiType, [H256, XcmV1MultiLocation, XcmVersionedMultiAssets]>;242 /**243 * Execution of an XCM message was attempted.244 * 245 * \[ outcome \]246 **/247 Attempted: AugmentedEvent<ApiType, [XcmV2TraitsOutcome]>;248 /**249 * Expected query response has been received but the origin location of the response does250 * not match that expected. The query remains registered for a later, valid, response to251 * be received and acted upon.252 * 253 * \[ origin location, id, expected location \]254 **/255 InvalidResponder: AugmentedEvent<ApiType, [XcmV1MultiLocation, u64, Option<XcmV1MultiLocation>]>;256 /**257 * Expected query response has been received but the expected origin location placed in258 * storage by this runtime previously cannot be decoded. The query remains registered.259 * 260 * This is unexpected (since a location placed in storage in a previously executing261 * runtime should be readable prior to query timeout) and dangerous since the possibly262 * valid response will be dropped. Manual governance intervention is probably going to be263 * needed.264 * 265 * \[ origin location, id \]266 **/267 InvalidResponderVersion: AugmentedEvent<ApiType, [XcmV1MultiLocation, u64]>;268 /**269 * Query response has been received and query is removed. The registered notification has270 * been dispatched and executed successfully.271 * 272 * \[ id, pallet index, call index \]273 **/274 Notified: AugmentedEvent<ApiType, [u64, u8, u8]>;275 /**276 * Query response has been received and query is removed. The dispatch was unable to be277 * decoded into a `Call`; this might be due to dispatch function having a signature which278 * is not `(origin, QueryId, Response)`.279 * 280 * \[ id, pallet index, call index \]281 **/282 NotifyDecodeFailed: AugmentedEvent<ApiType, [u64, u8, u8]>;283 /**284 * Query response has been received and query is removed. There was a general error with285 * dispatching the notification call.286 * 287 * \[ id, pallet index, call index \]288 **/289 NotifyDispatchError: AugmentedEvent<ApiType, [u64, u8, u8]>;290 /**291 * Query response has been received and query is removed. The registered notification could292 * not be dispatched because the dispatch weight is greater than the maximum weight293 * originally budgeted by this runtime for the query result.294 * 295 * \[ id, pallet index, call index, actual weight, max budgeted weight \]296 **/297 NotifyOverweight: AugmentedEvent<ApiType, [u64, u8, u8, u64, u64]>;298 /**299 * A given location which had a version change subscription was dropped owing to an error300 * migrating the location to our new XCM format.301 * 302 * \[ location, query ID \]303 **/304 NotifyTargetMigrationFail: AugmentedEvent<ApiType, [XcmVersionedMultiLocation, u64]>;305 /**306 * A given location which had a version change subscription was dropped owing to an error307 * sending the notification to it.308 * 309 * \[ location, query ID, error \]310 **/311 NotifyTargetSendFail: AugmentedEvent<ApiType, [XcmV1MultiLocation, u64, XcmV2TraitsError]>;312 /**313 * Query response has been received and is ready for taking with `take_response`. There is314 * no registered notification call.315 * 316 * \[ id, response \]317 **/318 ResponseReady: AugmentedEvent<ApiType, [u64, XcmV2Response]>;319 /**320 * Received query response has been read and removed.321 * 322 * \[ id \]323 **/324 ResponseTaken: AugmentedEvent<ApiType, [u64]>;325 /**326 * A XCM message was sent.327 * 328 * \[ origin, destination, message \]329 **/330 Sent: AugmentedEvent<ApiType, [XcmV1MultiLocation, XcmV1MultiLocation, XcmV2Xcm]>;331 /**332 * The supported version of a location has been changed. This might be through an333 * automatic notification or a manual intervention.334 * 335 * \[ location, XCM version \]336 **/337 SupportedVersionChanged: AugmentedEvent<ApiType, [XcmV1MultiLocation, u32]>;338 /**339 * Query response received which does not match a registered query. This may be because a340 * matching query was never registered, it may be because it is a duplicate response, or341 * because the query timed out.342 * 343 * \[ origin location, id \]344 **/345 UnexpectedResponse: AugmentedEvent<ApiType, [XcmV1MultiLocation, u64]>;346 /**347 * An XCM version change notification message has been attempted to be sent.348 * 349 * \[ destination, result \]350 **/351 VersionChangeNotified: AugmentedEvent<ApiType, [XcmV1MultiLocation, u32]>;352 /**353 * Generic event354 **/355 [key: string]: AugmentedEvent<ApiType>;356 };357 rmrkCore: {358 CollectionCreated: AugmentedEvent<ApiType, [issuer: AccountId32, collectionId: u32], { issuer: AccountId32, collectionId: u32 }>;359 CollectionDestroyed: AugmentedEvent<ApiType, [issuer: AccountId32, collectionId: u32], { issuer: AccountId32, collectionId: u32 }>;360 CollectionLocked: AugmentedEvent<ApiType, [issuer: AccountId32, collectionId: u32], { issuer: AccountId32, collectionId: u32 }>;361 IssuerChanged: AugmentedEvent<ApiType, [oldIssuer: AccountId32, newIssuer: AccountId32, collectionId: u32], { oldIssuer: AccountId32, newIssuer: AccountId32, collectionId: u32 }>;362 NFTAccepted: AugmentedEvent<ApiType, [sender: AccountId32, recipient: RmrkTraitsNftAccountIdOrCollectionNftTuple, collectionId: u32, nftId: u32], { sender: AccountId32, recipient: RmrkTraitsNftAccountIdOrCollectionNftTuple, collectionId: u32, nftId: u32 }>;363 NFTBurned: AugmentedEvent<ApiType, [owner: AccountId32, nftId: u32], { owner: AccountId32, nftId: u32 }>;364 NftMinted: AugmentedEvent<ApiType, [owner: AccountId32, collectionId: u32, nftId: u32], { owner: AccountId32, collectionId: u32, nftId: u32 }>;365 NFTRejected: AugmentedEvent<ApiType, [sender: AccountId32, collectionId: u32, nftId: u32], { sender: AccountId32, collectionId: u32, nftId: u32 }>;366 NFTSent: AugmentedEvent<ApiType, [sender: AccountId32, recipient: RmrkTraitsNftAccountIdOrCollectionNftTuple, collectionId: u32, nftId: u32, approvalRequired: bool], { sender: AccountId32, recipient: RmrkTraitsNftAccountIdOrCollectionNftTuple, collectionId: u32, nftId: u32, approvalRequired: bool }>;367 PrioritySet: AugmentedEvent<ApiType, [collectionId: u32, nftId: u32], { collectionId: u32, nftId: u32 }>;368 PropertySet: AugmentedEvent<ApiType, [collectionId: u32, maybeNftId: Option<u32>, key: Bytes, value: Bytes], { collectionId: u32, maybeNftId: Option<u32>, key: Bytes, value: Bytes }>;369 ResourceAccepted: AugmentedEvent<ApiType, [nftId: u32, resourceId: u32], { nftId: u32, resourceId: u32 }>;370 ResourceAdded: AugmentedEvent<ApiType, [nftId: u32, resourceId: u32], { nftId: u32, resourceId: u32 }>;371 ResourceRemoval: AugmentedEvent<ApiType, [nftId: u32, resourceId: u32], { nftId: u32, resourceId: u32 }>;372 ResourceRemovalAccepted: AugmentedEvent<ApiType, [nftId: u32, resourceId: u32], { nftId: u32, resourceId: u32 }>;373 /**374 * Generic event375 **/376 [key: string]: AugmentedEvent<ApiType>;377 };378 rmrkEquip: {379 BaseCreated: AugmentedEvent<ApiType, [issuer: AccountId32, baseId: u32], { issuer: AccountId32, baseId: u32 }>;380 EquippablesUpdated: AugmentedEvent<ApiType, [baseId: u32, slotId: u32], { baseId: u32, slotId: u32 }>;381 /**382 * Generic event383 **/384 [key: string]: AugmentedEvent<ApiType>;385 };386 scheduler: {387 /**388 * The call for the provided hash was not found so the task has been aborted.389 **/390 CallLookupFailed: AugmentedEvent<ApiType, [task: ITuple<[u32, u32]>, id: Option<U8aFixed>, error: FrameSupportScheduleLookupError], { task: ITuple<[u32, u32]>, id: Option<U8aFixed>, error: FrameSupportScheduleLookupError }>;391 /**392 * Canceled some task.393 **/394 Canceled: AugmentedEvent<ApiType, [when: u32, index: u32], { when: u32, index: u32 }>;395 /**396 * Dispatched some task.397 **/398 Dispatched: AugmentedEvent<ApiType, [task: ITuple<[u32, u32]>, id: Option<U8aFixed>, result: Result<Null, SpRuntimeDispatchError>], { task: ITuple<[u32, u32]>, id: Option<U8aFixed>, result: Result<Null, SpRuntimeDispatchError> }>;399 /**400 * Scheduled some task.401 **/402 Scheduled: AugmentedEvent<ApiType, [when: u32, index: u32], { when: u32, index: u32 }>;403 /**404 * Generic event405 **/406 [key: string]: AugmentedEvent<ApiType>;407 };408 structure: {409 /**410 * Executed call on behalf of token411 **/412 Executed: AugmentedEvent<ApiType, [Result<Null, SpRuntimeDispatchError>]>;413 /**414 * Generic event415 **/416 [key: string]: AugmentedEvent<ApiType>;417 };418 sudo: {419 /**420 * The \[sudoer\] just switched identity; the old key is supplied if one existed.421 **/422 KeyChanged: AugmentedEvent<ApiType, [oldSudoer: Option<AccountId32>], { oldSudoer: Option<AccountId32> }>;423 /**424 * A sudo just took place. \[result\]425 **/426 Sudid: AugmentedEvent<ApiType, [sudoResult: Result<Null, SpRuntimeDispatchError>], { sudoResult: Result<Null, SpRuntimeDispatchError> }>;427 /**428 * A sudo just took place. \[result\]429 **/430 SudoAsDone: AugmentedEvent<ApiType, [sudoResult: Result<Null, SpRuntimeDispatchError>], { sudoResult: Result<Null, SpRuntimeDispatchError> }>;431 /**432 * Generic event433 **/434 [key: string]: AugmentedEvent<ApiType>;435 };436 system: {437 /**438 * `:code` was updated.439 **/440 CodeUpdated: AugmentedEvent<ApiType, []>;441 /**442 * An extrinsic failed.443 **/444 ExtrinsicFailed: AugmentedEvent<ApiType, [dispatchError: SpRuntimeDispatchError, dispatchInfo: FrameSupportWeightsDispatchInfo], { dispatchError: SpRuntimeDispatchError, dispatchInfo: FrameSupportWeightsDispatchInfo }>;445 /**446 * An extrinsic completed successfully.447 **/448 ExtrinsicSuccess: AugmentedEvent<ApiType, [dispatchInfo: FrameSupportWeightsDispatchInfo], { dispatchInfo: FrameSupportWeightsDispatchInfo }>;449 /**450 * An account was reaped.451 **/452 KilledAccount: AugmentedEvent<ApiType, [account: AccountId32], { account: AccountId32 }>;453 /**454 * A new account was created.455 **/456 NewAccount: AugmentedEvent<ApiType, [account: AccountId32], { account: AccountId32 }>;457 /**458 * On on-chain remark happened.459 **/460 Remarked: AugmentedEvent<ApiType, [sender: AccountId32, hash_: H256], { sender: AccountId32, hash_: H256 }>;461 /**462 * Generic event463 **/464 [key: string]: AugmentedEvent<ApiType>;465 };466 treasury: {467 /**468 * Some funds have been allocated.469 **/470 Awarded: AugmentedEvent<ApiType, [proposalIndex: u32, award: u128, account: AccountId32], { proposalIndex: u32, award: u128, account: AccountId32 }>;471 /**472 * Some of our funds have been burnt.473 **/474 Burnt: AugmentedEvent<ApiType, [burntFunds: u128], { burntFunds: u128 }>;475 /**476 * Some funds have been deposited.477 **/478 Deposit: AugmentedEvent<ApiType, [value: u128], { value: u128 }>;479 /**480 * New proposal.481 **/482 Proposed: AugmentedEvent<ApiType, [proposalIndex: u32], { proposalIndex: u32 }>;483 /**484 * A proposal was rejected; funds were slashed.485 **/486 Rejected: AugmentedEvent<ApiType, [proposalIndex: u32, slashed: u128], { proposalIndex: u32, slashed: u128 }>;487 /**488 * Spending has finished; this is the amount that rolls over until next spend.489 **/490 Rollover: AugmentedEvent<ApiType, [rolloverBalance: u128], { rolloverBalance: u128 }>;491 /**492 * We have ended a spend period and will now allocate funds.493 **/494 Spending: AugmentedEvent<ApiType, [budgetRemaining: u128], { budgetRemaining: u128 }>;495 /**496 * Generic event497 **/498 [key: string]: AugmentedEvent<ApiType>;499 };500 unique: {501 /**502 * Address was add to allow list503 * 504 * # Arguments505 * 506 * * collection_id: Globally unique collection identifier.507 * 508 * * user: Address.509 **/510 AllowListAddressAdded: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;511 /**512 * Address was remove from allow list513 * 514 * # Arguments515 * 516 * * collection_id: Globally unique collection identifier.517 * 518 * * user: Address.519 **/520 AllowListAddressRemoved: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;521 /**522 * Collection admin was added523 * 524 * # Arguments525 * 526 * * collection_id: Globally unique collection identifier.527 * 528 * * admin: Admin address.529 **/530 CollectionAdminAdded: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;531 /**532 * Collection admin was removed533 * 534 * # Arguments535 * 536 * * collection_id: Globally unique collection identifier.537 * 538 * * admin: Admin address.539 **/540 CollectionAdminRemoved: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;541 /**542 * Collection limits was set543 * 544 * # Arguments545 * 546 * * collection_id: Globally unique collection identifier.547 **/548 CollectionLimitSet: AugmentedEvent<ApiType, [u32]>;549 /**550 * Collection owned was change551 * 552 * # Arguments553 * 554 * * collection_id: Globally unique collection identifier.555 * 556 * * owner: New owner address.557 **/558 CollectionOwnedChanged: AugmentedEvent<ApiType, [u32, AccountId32]>;559 CollectionPermissionSet: AugmentedEvent<ApiType, [u32]>;560 /**561 * Collection sponsor was removed562 * 563 * # Arguments564 * 565 * * collection_id: Globally unique collection identifier.566 **/567 CollectionSponsorRemoved: AugmentedEvent<ApiType, [u32]>;568 /**569 * Collection sponsor was set570 * 571 * # Arguments572 * 573 * * collection_id: Globally unique collection identifier.574 * 575 * * owner: New sponsor address.576 **/577 CollectionSponsorSet: AugmentedEvent<ApiType, [u32, AccountId32]>;578 /**579 * New sponsor was confirm580 * 581 * # Arguments582 * 583 * * collection_id: Globally unique collection identifier.584 * 585 * * sponsor: New sponsor address.586 **/587 SponsorshipConfirmed: AugmentedEvent<ApiType, [u32, AccountId32]>;588 /**589 * Generic event590 **/591 [key: string]: AugmentedEvent<ApiType>;592 };593 vesting: {594 /**595 * Claimed vesting.596 **/597 Claimed: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;598 /**599 * Added new vesting schedule.600 **/601 VestingScheduleAdded: AugmentedEvent<ApiType, [from: AccountId32, to: AccountId32, vestingSchedule: OrmlVestingVestingSchedule], { from: AccountId32, to: AccountId32, vestingSchedule: OrmlVestingVestingSchedule }>;602 /**603 * Updated vesting schedules.604 **/605 VestingSchedulesUpdated: AugmentedEvent<ApiType, [who: AccountId32], { who: AccountId32 }>;606 /**607 * Generic event608 **/609 [key: string]: AugmentedEvent<ApiType>;610 };611 xcmpQueue: {612 /**613 * Bad XCM format used.614 **/615 BadFormat: AugmentedEvent<ApiType, [Option<H256>]>;616 /**617 * Bad XCM version used.618 **/619 BadVersion: AugmentedEvent<ApiType, [Option<H256>]>;620 /**621 * Some XCM failed.622 **/623 Fail: AugmentedEvent<ApiType, [Option<H256>, XcmV2TraitsError]>;624 /**625 * An XCM exceeded the individual message weight budget.626 **/627 OverweightEnqueued: AugmentedEvent<ApiType, [u32, u32, u64, u64]>;628 /**629 * An XCM from the overweight queue was executed with the given actual weight used.630 **/631 OverweightServiced: AugmentedEvent<ApiType, [u64, u64]>;632 /**633 * Some XCM was executed ok.634 **/635 Success: AugmentedEvent<ApiType, [Option<H256>]>;636 /**637 * An upward message was sent to the relay chain.638 **/639 UpwardMessageSent: AugmentedEvent<ApiType, [Option<H256>]>;640 /**641 * An HRMP message was sent to a sibling parachain.642 **/643 XcmpMessageSent: AugmentedEvent<ApiType, [Option<H256>]>;644 /**645 * Generic event646 **/647 [key: string]: AugmentedEvent<ApiType>;648 };649 } // AugmentedEvents650} // declare moduletests/src/interfaces/augment-api-query.tsdiffbeforeafterboth--- a/tests/src/interfaces/augment-api-query.ts
+++ b/tests/src/interfaces/augment-api-query.ts
@@ -69,24 +69,36 @@
[key: string]: QueryableStorageEntry<ApiType>;
};
common: {
+ /**
+ * Storage of collection admins count.
+ **/
adminAmount: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
/**
* Allowlisted collection users
**/
allowlist: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
/**
- * Collection info
+ * Storage of collection info.
**/
collectionById: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<UpDataStructsCollection>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
/**
- * Collection properties
+ * Storage of collection properties.
**/
collectionProperties: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<UpDataStructsProperties>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * Storage of collection properties permissions.
+ **/
collectionPropertyPermissions: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<BTreeMap<Bytes, UpDataStructsPropertyPermission>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * Storage of the count of created collections.
+ **/
createdCollectionCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Storage of the count of deleted collections.
+ **/
destroyedCollectionCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
/**
- * Not used by code, exists only to provide some types to metadata
+ * Not used by code, exists only to provide some types to metadata.
**/
dummyStorageValue: AugmentedQuery<ApiType, () => Observable<Option<ITuple<[UpDataStructsCollectionStats, u32, u32, UpDataStructsTokenChild, PhantomTypeUpDataStructs]>>>, []> & QueryableStorageEntry<ApiType, []>;
/**
@@ -231,20 +243,42 @@
[key: string]: QueryableStorageEntry<ApiType>;
};
nonfungible: {
+ /**
+ * Amount of tokens owned by account.
+ **/
accountBalance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u32>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * Allowance set by an owner for a spender for a token.
+ **/
allowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<PalletEvmAccountBasicCrossAccountIdRepr>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
/**
- * Used to enumerate tokens owned by account
+ * Used to enumerate tokens owned by account.
**/
owned: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: u32 | AnyNumber | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]>;
+ /**
+ * Custom data that is serialized to bytes and attached to a token property.
+ * Currently used to store RMRK data.
+ **/
tokenAuxProperties: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: UpDataStructsPropertyScope | 'None' | 'Rmrk' | number | Uint8Array, arg4: Bytes | string | Uint8Array) => Observable<Option<Bytes>>, [u32, u32, UpDataStructsPropertyScope, Bytes]> & QueryableStorageEntry<ApiType, [u32, u32, UpDataStructsPropertyScope, Bytes]>;
/**
- * Used to enumerate token's children
+ * Used to enumerate token's children.
**/
tokenChildren: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: ITuple<[u32, u32]> | [u32 | AnyNumber | Uint8Array, u32 | AnyNumber | Uint8Array]) => Observable<bool>, [u32, u32, ITuple<[u32, u32]>]> & QueryableStorageEntry<ApiType, [u32, u32, ITuple<[u32, u32]>]>;
+ /**
+ * Custom data serialized to bytes for token.
+ **/
tokenData: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<PalletNonfungibleItemData>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
+ /**
+ * Key-Value map stored for token.
+ **/
tokenProperties: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<UpDataStructsProperties>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
+ /**
+ * Amount of burnt tokens for collection.
+ **/
tokensBurnt: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * Amount of tokens minted for collection.
+ **/
tokensMinted: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
/**
* Generic query
@@ -430,6 +464,9 @@
**/
tokenData: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<PalletRefungibleItemData>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
tokenProperties: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<UpDataStructsProperties>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
+ /**
+ * Amount of burnt tokens for collection
+ **/
tokensBurnt: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
/**
* Amount of tokens minted for collection
tests/src/interfaces/augment-api-rpc.tsdiffbeforeafterboth--- a/tests/src/interfaces/augment-api-rpc.ts
+++ b/tests/src/interfaces/augment-api-rpc.ts
@@ -709,6 +709,10 @@
**/
tokenOwner: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<PalletEvmAccountBasicCrossAccountIdRepr>>>;
/**
+ * Returns 10 tokens owners in no particular order
+ **/
+ tokenOwners: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<PalletEvmAccountBasicCrossAccountIdRepr>>>;
+ /**
* Get token properties
**/
tokenProperties: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, propertyKeys?: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsProperty>>>;
tests/src/interfaces/unique/definitions.tsdiffbeforeafterboth--- a/tests/src/interfaces/unique/definitions.ts
+++ b/tests/src/interfaces/unique/definitions.ts
@@ -49,6 +49,7 @@
balance: fun('Get amount of specific account token', [collectionParam, crossAccountParam(), tokenParam], 'u128'),
allowance: fun('Get allowed amount', [collectionParam, crossAccountParam('sender'), crossAccountParam('spender'), tokenParam], 'u128'),
tokenOwner: fun('Get token owner', [collectionParam, tokenParam], `Option<${CROSS_ACCOUNT_ID_TYPE}>`),
+ tokenOwners: fun('Returns 10 tokens owners in no particular order', [collectionParam, tokenParam], `Vec<${CROSS_ACCOUNT_ID_TYPE}>`),
topmostTokenOwner: fun('Get token owner, in case of nested token - find parent recursive', [collectionParam, tokenParam], `Option<${CROSS_ACCOUNT_ID_TYPE}>`),
tokenChildren: fun('Get tokens nested directly into the token', [collectionParam, tokenParam], 'Vec<UpDataStructsTokenChild>'),
constMetadata: fun('Get token constant metadata', [collectionParam, tokenParam], 'Vec<u8>'),
tests/src/refungible.test.tsdiffbeforeafterboth--- a/tests/src/refungible.test.ts
+++ b/tests/src/refungible.test.ts
@@ -32,6 +32,8 @@
repartitionRFT,
createCollectionWithPropsExpectSuccess,
getDetailedCollectionInfo,
+ normalizeAccountId,
+ CrossAccountId,
getCreateItemsResult,
getDestroyItemsResult,
} from './util/helpers';
@@ -55,14 +57,14 @@
it('Create refungible collection and token', async () => {
await usingApi(async api => {
const createCollectionResult = await createCollection(api, alice, {mode: {type: 'ReFungible'}});
- expect(createCollectionResult.success).to.be.true;
+ expect(createCollectionResult.success).to.be.true;
const collectionId = createCollectionResult.collectionId;
-
+
const itemCountBefore = await getLastTokenId(api, collectionId);
const result = await createRefungibleToken(api, alice, collectionId, 100n);
-
+
const itemCountAfter = await getLastTokenId(api, collectionId);
-
+
// What to expect
// tslint:disable-next-line:no-unused-expression
expect(result.success).to.be.true;
@@ -71,7 +73,43 @@
expect(itemCountAfter.toString()).to.be.equal(result.itemId.toString());
});
});
-
+
+ it('RPC method tokenOnewrs for refungible collection and token', async () => {
+ await usingApi(async (api, privateKeyWrapper) => {
+ const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
+ const facelessCrowd = Array.from(Array(7).keys()).map(i => normalizeAccountId(privateKeyWrapper(i.toString())));
+
+ const createCollectionResult = await createCollection(api, alice, {mode: {type: 'ReFungible'}});
+ const collectionId = createCollectionResult.collectionId;
+
+ const result = await createRefungibleToken(api, alice, collectionId, 10_000n);
+ const aliceTokenId = result.itemId;
+
+
+ await transfer(api, collectionId, aliceTokenId, alice, bob, 1000n);
+ await transfer(api, collectionId, aliceTokenId, alice, ethAcc, 900n);
+
+ for (let i = 0; i < 7; i++) {
+ await transfer(api, collectionId, aliceTokenId, alice, facelessCrowd[i], 50*(i+1));
+ }
+
+ const owners = await api.rpc.unique.tokenOwners(collectionId, aliceTokenId);
+ const ids = (owners.toJSON() as CrossAccountId[]).map(s => normalizeAccountId(s));
+
+ const aliceID = normalizeAccountId(alice);
+ const bobId = normalizeAccountId(bob);
+
+ // What to expect
+ // tslint:disable-next-line:no-unused-expression
+ expect(ids).to.deep.include.members([aliceID, ethAcc, bobId, ...facelessCrowd]);
+ expect(owners.length).to.be.equal(10);
+
+ const eleven = privateKeyWrapper('11');
+ expect(await transfer(api, collectionId, aliceTokenId, alice, eleven, 10n)).to.be.true;
+ expect((await api.rpc.unique.tokenOwners(collectionId, aliceTokenId)).length).to.be.equal(10);
+ });
+ });
+
it('Transfer token pieces', async () => {
await usingApi(async api => {
const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
tests/src/rpc.test.tsdiffbeforeafterboth--- a/tests/src/rpc.test.ts
+++ b/tests/src/rpc.test.ts
@@ -1,12 +1,57 @@
+import {IKeyringPair} from '@polkadot/types/types';
import {expect} from 'chai';
import usingApi from './substrate/substrate-api';
-import {createCollectionExpectSuccess, getTokenOwner} from './util/helpers';
+import {createCollection, createCollectionExpectSuccess, createFungibleItemExpectSuccess, CrossAccountId, getTokenOwner, normalizeAccountId, transfer, U128_MAX} from './util/helpers';
+
+let alice: IKeyringPair;
+let bob: IKeyringPair;
-describe('getTokenOwner', () => {
+
+describe('integration test: RPC methods', () => {
+ before(async () => {
+ await usingApi(async (api, privateKeyWrapper) => {
+ alice = privateKeyWrapper('//Alice');
+ bob = privateKeyWrapper('//Bob');
+ });
+ });
+
+
it('returns None for fungible collection', async () => {
await usingApi(async api => {
const collection = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
await expect(getTokenOwner(api, collection, 0)).to.be.rejectedWith(/^owner == null$/);
});
});
+
+ it('RPC method tokenOwners for fungible collection and token', async () => {
+ await usingApi(async (api, privateKeyWrapper) => {
+ const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
+ const facelessCrowd = Array.from(Array(7).keys()).map(i => normalizeAccountId(privateKeyWrapper(i.toString())));
+
+ const createCollectionResult = await createCollection(api, alice, {mode: {type: 'Fungible', decimalPoints: 0}});
+ const collectionId = createCollectionResult.collectionId;
+ const aliceTokenId = await createFungibleItemExpectSuccess(alice, collectionId, {Value: U128_MAX}, alice.address);
+
+ await transfer(api, collectionId, aliceTokenId, alice, bob, 1000n);
+ await transfer(api, collectionId, aliceTokenId, alice, ethAcc, 900n);
+
+ for (let i = 0; i < 7; i++) {
+ await transfer(api, collectionId, aliceTokenId, alice, facelessCrowd[i], 1);
+ }
+
+ const owners = await api.rpc.unique.tokenOwners(collectionId, aliceTokenId);
+ const ids = (owners.toJSON() as CrossAccountId[]).map(s => normalizeAccountId(s));
+ const aliceID = normalizeAccountId(alice);
+ const bobId = normalizeAccountId(bob);
+
+ // What to expect
+ // tslint:disable-next-line:no-unused-expression
+ expect(ids).to.deep.include.members([aliceID, ethAcc, bobId, ...facelessCrowd]);
+ expect(owners.length == 10).to.be.true;
+
+ const eleven = privateKeyWrapper('11');
+ expect(await transfer(api, collectionId, aliceTokenId, alice, eleven, 10n)).to.be.true;
+ expect((await api.rpc.unique.tokenOwners(collectionId, aliceTokenId)).length).to.be.equal(10);
+ });
+ });
});
\ No newline at end of file